xref: /aosp_15_r20/external/freetype/src/sdf/ftsdfrend.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * ftsdfrend.c
4  *
5  *   Signed Distance Field renderer interface (body).
6  *
7  * Copyright (C) 2020-2023 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * Written by Anuj Verma.
11  *
12  * This file is part of the FreeType project, and may only be used,
13  * modified, and distributed under the terms of the FreeType project
14  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
15  * this file you indicate that you have read the license and
16  * understand and accept it fully.
17  *
18  */
19 
20 
21 #include <freetype/internal/ftdebug.h>
22 #include <freetype/internal/ftobjs.h>
23 #include <freetype/internal/services/svprop.h>
24 #include <freetype/ftoutln.h>
25 #include <freetype/ftbitmap.h>
26 #include "ftsdfrend.h"
27 #include "ftsdf.h"
28 
29 #include "ftsdferrs.h"
30 
31 
32   /**************************************************************************
33    *
34    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
35    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
36    * messages during execution.
37    */
38 #undef  FT_COMPONENT
39 #define FT_COMPONENT  sdf
40 
41 
42   /**************************************************************************
43    *
44    * macros and default property values
45    *
46    */
47 #define SDF_RENDERER( rend )  ( (SDF_Renderer)rend )
48 
49 
50   /**************************************************************************
51    *
52    * for setting properties
53    *
54    */
55 
56   /* property setter function */
57   static FT_Error
sdf_property_set(FT_Module module,const char * property_name,const void * value,FT_Bool value_is_string)58   sdf_property_set( FT_Module    module,
59                     const char*  property_name,
60                     const void*  value,
61                     FT_Bool      value_is_string )
62   {
63     FT_Error      error  = FT_Err_Ok;
64     SDF_Renderer  render = SDF_RENDERER( FT_RENDERER( module ) );
65 
66     FT_UNUSED( value_is_string );
67 
68 
69     if ( ft_strcmp( property_name, "spread" ) == 0 )
70     {
71       FT_Int  val = *(const FT_Int*)value;
72 
73 
74       if ( val > MAX_SPREAD || val < MIN_SPREAD )
75       {
76         FT_TRACE0(( "[sdf] sdf_property_set:"
77                     " the `spread' property can have a value\n" ));
78         FT_TRACE0(( "                       "
79                     " within range [%d, %d] (value provided: %d)\n",
80                     MIN_SPREAD, MAX_SPREAD, val ));
81 
82         error = FT_THROW( Invalid_Argument );
83         goto Exit;
84       }
85 
86       render->spread = (FT_UInt)val;
87       FT_TRACE7(( "[sdf] sdf_property_set:"
88                   " updated property `spread' to %d\n", val ));
89     }
90 
91     else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
92     {
93       FT_Int  val = *(const FT_Int*)value;
94 
95 
96       render->flip_sign = val ? 1 : 0;
97       FT_TRACE7(( "[sdf] sdf_property_set:"
98                   " updated property `flip_sign' to %d\n", val ));
99     }
100 
101     else if ( ft_strcmp( property_name, "flip_y" ) == 0 )
102     {
103       FT_Int  val = *(const FT_Int*)value;
104 
105 
106       render->flip_y = val ? 1 : 0;
107       FT_TRACE7(( "[sdf] sdf_property_set:"
108                   " updated property `flip_y' to %d\n", val ));
109     }
110 
111     else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
112     {
113       FT_Bool  val = *(const FT_Bool*)value;
114 
115 
116       render->overlaps = val;
117       FT_TRACE7(( "[sdf] sdf_property_set:"
118                   " updated property `overlaps' to %d\n", val ));
119     }
120 
121     else
122     {
123       FT_TRACE0(( "[sdf] sdf_property_set:"
124                   " missing property `%s'\n", property_name ));
125       error = FT_THROW( Missing_Property );
126     }
127 
128   Exit:
129     return error;
130   }
131 
132 
133   /* property getter function */
134   static FT_Error
sdf_property_get(FT_Module module,const char * property_name,void * value)135   sdf_property_get( FT_Module    module,
136                     const char*  property_name,
137                     void*        value )
138   {
139     FT_Error      error  = FT_Err_Ok;
140     SDF_Renderer  render = SDF_RENDERER( FT_RENDERER( module ) );
141 
142 
143     if ( ft_strcmp( property_name, "spread" ) == 0 )
144     {
145       FT_UInt*  val = (FT_UInt*)value;
146 
147 
148       *val = render->spread;
149     }
150 
151     else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
152     {
153       FT_Int*  val = (FT_Int*)value;
154 
155 
156       *val = render->flip_sign;
157     }
158 
159     else if ( ft_strcmp( property_name, "flip_y" ) == 0 )
160     {
161       FT_Int*  val = (FT_Int*)value;
162 
163 
164       *val = render->flip_y;
165     }
166 
167     else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
168     {
169       FT_Int*  val = (FT_Int*)value;
170 
171 
172       *val = render->overlaps;
173     }
174 
175     else
176     {
177       FT_TRACE0(( "[sdf] sdf_property_get:"
178                   " missing property `%s'\n", property_name ));
179       error = FT_THROW( Missing_Property );
180     }
181 
182     return error;
183   }
184 
185 
186   FT_DEFINE_SERVICE_PROPERTIESREC(
187     sdf_service_properties,
188 
189     (FT_Properties_SetFunc)sdf_property_set,        /* set_property */
190     (FT_Properties_GetFunc)sdf_property_get )       /* get_property */
191 
192 
193   FT_DEFINE_SERVICEDESCREC1(
194     sdf_services,
195 
196     FT_SERVICE_ID_PROPERTIES, &sdf_service_properties )
197 
198 
199   static FT_Module_Interface
ft_sdf_requester(FT_Module module,const char * module_interface)200   ft_sdf_requester( FT_Module    module,
201                     const char*  module_interface )
202   {
203     FT_UNUSED( module );
204 
205     return ft_service_list_lookup( sdf_services, module_interface );
206   }
207 
208 
209   /*************************************************************************/
210   /*************************************************************************/
211   /**                                                                     **/
212   /**  OUTLINE TO SDF CONVERTER                                           **/
213   /**                                                                     **/
214   /*************************************************************************/
215   /*************************************************************************/
216 
217   /**************************************************************************
218    *
219    * interface functions
220    *
221    */
222 
223   static FT_Error
ft_sdf_init(FT_Module module)224   ft_sdf_init( FT_Module  module )   /* SDF_Renderer */
225   {
226     SDF_Renderer  sdf_render = SDF_RENDERER( module );
227 
228 
229     sdf_render->spread    = DEFAULT_SPREAD;
230     sdf_render->flip_sign = 0;
231     sdf_render->flip_y    = 0;
232     sdf_render->overlaps  = 0;
233 
234     return FT_Err_Ok;
235   }
236 
237 
238   static void
ft_sdf_done(FT_Module module)239   ft_sdf_done( FT_Module  module )
240   {
241     FT_UNUSED( module );
242   }
243 
244 
245   /* generate signed distance field from a glyph's slot image */
246   static FT_Error
ft_sdf_render(FT_Renderer module,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)247   ft_sdf_render( FT_Renderer       module,
248                  FT_GlyphSlot      slot,
249                  FT_Render_Mode    mode,
250                  const FT_Vector*  origin )
251   {
252     FT_Error     error   = FT_Err_Ok;
253     FT_Outline*  outline = &slot->outline;
254     FT_Bitmap*   bitmap  = &slot->bitmap;
255     FT_Memory    memory  = NULL;
256     FT_Renderer  render  = NULL;
257 
258     FT_Pos  x_shift = 0;
259     FT_Pos  y_shift = 0;
260 
261     FT_Pos  x_pad = 0;
262     FT_Pos  y_pad = 0;
263 
264     SDF_Raster_Params  params;
265     SDF_Renderer       sdf_module = SDF_RENDERER( module );
266 
267 
268     render = &sdf_module->root;
269     memory = render->root.memory;
270 
271     /* check whether slot format is correct before rendering */
272     if ( slot->format != render->glyph_format )
273     {
274       error = FT_THROW( Invalid_Glyph_Format );
275       goto Exit;
276     }
277 
278     /* check whether render mode is correct */
279     if ( mode != FT_RENDER_MODE_SDF )
280     {
281       error = FT_THROW( Cannot_Render_Glyph );
282       goto Exit;
283     }
284 
285     /* deallocate the previously allocated bitmap */
286     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
287     {
288       FT_FREE( bitmap->buffer );
289       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
290     }
291 
292     /* preset the bitmap using the glyph's outline;         */
293     /* the sdf bitmap is similar to an anti-aliased bitmap  */
294     /* with a slightly bigger size and different pixel mode */
295     if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) )
296     {
297       error = FT_THROW( Raster_Overflow );
298       goto Exit;
299     }
300 
301     /* nothing to render */
302     if ( !bitmap->rows || !bitmap->pitch )
303       goto Exit;
304 
305     /* the padding will simply be equal to the `spread' */
306     x_pad = sdf_module->spread;
307     y_pad = sdf_module->spread;
308 
309     /* apply the padding; will be in all the directions */
310     bitmap->rows  += y_pad * 2;
311     bitmap->width += x_pad * 2;
312 
313     /* ignore the pitch, pixel mode and set custom */
314     bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
315     bitmap->pitch      = (int)( bitmap->width );
316     bitmap->num_grays  = 255;
317 
318     /* allocate new buffer */
319     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
320       goto Exit;
321 
322     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
323 
324     slot->bitmap_top  += y_pad;
325     slot->bitmap_left -= x_pad;
326 
327     x_shift  = 64 * -slot->bitmap_left;
328     y_shift  = 64 * -slot->bitmap_top;
329     y_shift += 64 * (FT_Int)bitmap->rows;
330 
331     if ( origin )
332     {
333       x_shift += origin->x;
334       y_shift += origin->y;
335     }
336 
337     /* translate outline to render it into the bitmap */
338     if ( x_shift || y_shift )
339       FT_Outline_Translate( outline, x_shift, y_shift );
340 
341     /* set up parameters */
342     params.root.target = bitmap;
343     params.root.source = outline;
344     params.root.flags  = FT_RASTER_FLAG_SDF;
345     params.spread      = sdf_module->spread;
346     params.flip_sign   = sdf_module->flip_sign;
347     params.flip_y      = sdf_module->flip_y;
348     params.overlaps    = sdf_module->overlaps;
349 
350     /* render the outline */
351     error = render->raster_render( render->raster,
352                                    (const FT_Raster_Params*)&params );
353 
354     /* transform the outline back to the original state */
355     if ( x_shift || y_shift )
356       FT_Outline_Translate( outline, -x_shift, -y_shift );
357 
358   Exit:
359     if ( !error )
360     {
361       /* the glyph is successfully rendered to a bitmap */
362       slot->format = FT_GLYPH_FORMAT_BITMAP;
363     }
364     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
365     {
366       FT_FREE( bitmap->buffer );
367       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
368     }
369 
370     return error;
371   }
372 
373 
374   /* transform the glyph using matrix and/or delta */
375   static FT_Error
ft_sdf_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)376   ft_sdf_transform( FT_Renderer       render,
377                     FT_GlyphSlot      slot,
378                     const FT_Matrix*  matrix,
379                     const FT_Vector*  delta )
380   {
381     FT_Error  error = FT_Err_Ok;
382 
383 
384     if ( slot->format != render->glyph_format )
385     {
386       error = FT_THROW( Invalid_Argument );
387       goto Exit;
388     }
389 
390     if ( matrix )
391       FT_Outline_Transform( &slot->outline, matrix );
392 
393     if ( delta )
394       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
395 
396   Exit:
397     return error;
398   }
399 
400 
401   /* return the control box of a glyph's outline */
402   static void
ft_sdf_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)403   ft_sdf_get_cbox( FT_Renderer   render,
404                    FT_GlyphSlot  slot,
405                    FT_BBox*      cbox )
406   {
407     FT_ZERO( cbox );
408 
409     if ( slot->format == render->glyph_format )
410       FT_Outline_Get_CBox( &slot->outline, cbox );
411   }
412 
413 
414   /* set render specific modes or attributes */
415   static FT_Error
ft_sdf_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)416   ft_sdf_set_mode( FT_Renderer  render,
417                    FT_ULong     mode_tag,
418                    FT_Pointer   data )
419   {
420     /* pass it to the rasterizer */
421     return render->clazz->raster_class->raster_set_mode( render->raster,
422                                                          mode_tag,
423                                                          data );
424   }
425 
426 
427   FT_DEFINE_RENDERER(
428     ft_sdf_renderer_class,
429 
430     FT_MODULE_RENDERER,
431     sizeof ( SDF_Renderer_Module ),
432 
433     "sdf",
434     0x10000L,
435     0x20000L,
436 
437     NULL,
438 
439     (FT_Module_Constructor)ft_sdf_init,
440     (FT_Module_Destructor) ft_sdf_done,
441     (FT_Module_Requester)  ft_sdf_requester,
442 
443     FT_GLYPH_FORMAT_OUTLINE,
444 
445     (FT_Renderer_RenderFunc)   ft_sdf_render,     /* render_glyph    */
446     (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
447     (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
448     (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
449 
450     (FT_Raster_Funcs*)&ft_sdf_raster              /* raster_class    */
451   )
452 
453 
454   /*************************************************************************/
455   /*************************************************************************/
456   /**                                                                     **/
457   /**  BITMAP TO SDF CONVERTER                                            **/
458   /**                                                                     **/
459   /*************************************************************************/
460   /*************************************************************************/
461 
462   /* generate signed distance field from glyph's bitmap */
463   static FT_Error
ft_bsdf_render(FT_Renderer module,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)464   ft_bsdf_render( FT_Renderer       module,
465                   FT_GlyphSlot      slot,
466                   FT_Render_Mode    mode,
467                   const FT_Vector*  origin )
468   {
469     FT_Error   error  = FT_Err_Ok;
470     FT_Memory  memory = NULL;
471 
472     FT_Bitmap*   bitmap  = &slot->bitmap;
473     FT_Renderer  render  = NULL;
474     FT_Bitmap    target;
475 
476     FT_Pos  x_pad = 0;
477     FT_Pos  y_pad = 0;
478 
479     SDF_Raster_Params  params;
480     SDF_Renderer       sdf_module = SDF_RENDERER( module );
481 
482 
483     /* initialize the bitmap in case any error occurs */
484     FT_Bitmap_Init( &target );
485 
486     render = &sdf_module->root;
487     memory = render->root.memory;
488 
489     /* check whether slot format is correct before rendering */
490     if ( slot->format != render->glyph_format )
491     {
492       error = FT_THROW( Invalid_Glyph_Format );
493       goto Exit;
494     }
495 
496     /* check whether render mode is correct */
497     if ( mode != FT_RENDER_MODE_SDF )
498     {
499       error = FT_THROW( Cannot_Render_Glyph );
500       goto Exit;
501     }
502 
503     if ( origin )
504     {
505       FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" ));
506 
507       error = FT_THROW( Unimplemented_Feature );
508       goto Exit;
509     }
510 
511     /* nothing to render */
512     if ( !bitmap->rows || !bitmap->pitch )
513       goto Exit;
514 
515     /* Do not generate SDF if the bitmap is not owned by the       */
516     /* glyph: it might be that the source buffer is already freed. */
517     if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
518     {
519       FT_ERROR(( "ft_bsdf_render: can't generate SDF from"
520                  " unowned source bitmap\n" ));
521 
522       error = FT_THROW( Invalid_Argument );
523       goto Exit;
524     }
525 
526     FT_Bitmap_New( &target );
527 
528     /* padding will simply be equal to `spread` */
529     x_pad = sdf_module->spread;
530     y_pad = sdf_module->spread;
531 
532     /* apply padding, which extends to all directions */
533     target.rows  = bitmap->rows  + y_pad * 2;
534     target.width = bitmap->width + x_pad * 2;
535 
536     /* set up the target bitmap */
537     target.pixel_mode = FT_PIXEL_MODE_GRAY;
538     target.pitch      = (int)( target.width );
539     target.num_grays  = 255;
540 
541     if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) )
542       goto Exit;
543 
544     /* set up parameters */
545     params.root.target = &target;
546     params.root.source = bitmap;
547     params.root.flags  = FT_RASTER_FLAG_SDF;
548     params.spread      = sdf_module->spread;
549     params.flip_sign   = sdf_module->flip_sign;
550     params.flip_y      = sdf_module->flip_y;
551 
552     error = render->raster_render( render->raster,
553                                    (const FT_Raster_Params*)&params );
554 
555   Exit:
556     if ( !error )
557     {
558       /* the glyph is successfully converted to a SDF */
559       if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
560         FT_FREE( bitmap->buffer );
561 
562       slot->bitmap       = target;
563       slot->bitmap_top  += y_pad;
564       slot->bitmap_left -= x_pad;
565 
566       if ( target.buffer )
567         slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
568     }
569     else if ( target.buffer )
570       FT_FREE( target.buffer );
571 
572     return error;
573   }
574 
575 
576   FT_DEFINE_RENDERER(
577     ft_bitmap_sdf_renderer_class,
578 
579     FT_MODULE_RENDERER,
580     sizeof ( SDF_Renderer_Module ),
581 
582     "bsdf",
583     0x10000L,
584     0x20000L,
585 
586     NULL,
587 
588     (FT_Module_Constructor)ft_sdf_init,
589     (FT_Module_Destructor) ft_sdf_done,
590     (FT_Module_Requester)  ft_sdf_requester,
591 
592     FT_GLYPH_FORMAT_BITMAP,
593 
594     (FT_Renderer_RenderFunc)   ft_bsdf_render,    /* render_glyph    */
595     (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
596     (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
597     (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
598 
599     (FT_Raster_Funcs*)&ft_bitmap_sdf_raster       /* raster_class    */
600   )
601 
602 
603 /* END */
604