• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftsdfrend.c
4  *
5  *   Signed Distance Field renderer interface (body).
6  *
7  * Copyright (C) 2020-2021 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_Renderer render,const char * module_interface)200   ft_sdf_requester( FT_Renderer  render,
201                     const char*  module_interface )
202   {
203     FT_UNUSED( render );
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_Renderer render)224   ft_sdf_init( FT_Renderer  render )
225   {
226     SDF_Renderer  sdf_render = SDF_RENDERER( render );
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_Renderer render)239   ft_sdf_done( FT_Renderer  render )
240   {
241     FT_UNUSED( render );
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     /* the rows and pitch must be valid after presetting the */
302     /* bitmap using outline                                  */
303     if ( !bitmap->rows || !bitmap->pitch )
304     {
305       FT_ERROR(( "ft_sdf_render: failed to preset bitmap\n" ));
306 
307       error = FT_THROW( Cannot_Render_Glyph );
308       goto Exit;
309     }
310 
311     /* the padding will simply be equal to the `spread' */
312     x_pad = sdf_module->spread;
313     y_pad = sdf_module->spread;
314 
315     /* apply the padding; will be in all the directions */
316     bitmap->rows  += y_pad * 2;
317     bitmap->width += x_pad * 2;
318 
319     /* ignore the pitch, pixel mode and set custom */
320     bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
321     bitmap->pitch      = (int)( bitmap->width );
322     bitmap->num_grays  = 255;
323 
324     /* allocate new buffer */
325     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
326       goto Exit;
327 
328     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
329 
330     slot->bitmap_top  += y_pad;
331     slot->bitmap_left -= x_pad;
332 
333     x_shift  = 64 * -slot->bitmap_left;
334     y_shift  = 64 * -slot->bitmap_top;
335     y_shift += 64 * (FT_Int)bitmap->rows;
336 
337     if ( origin )
338     {
339       x_shift += origin->x;
340       y_shift += origin->y;
341     }
342 
343     /* translate outline to render it into the bitmap */
344     if ( x_shift || y_shift )
345       FT_Outline_Translate( outline, x_shift, y_shift );
346 
347     /* set up parameters */
348     params.root.target = bitmap;
349     params.root.source = outline;
350     params.root.flags  = FT_RASTER_FLAG_SDF;
351     params.spread      = sdf_module->spread;
352     params.flip_sign   = sdf_module->flip_sign;
353     params.flip_y      = sdf_module->flip_y;
354     params.overlaps    = sdf_module->overlaps;
355 
356     /* render the outline */
357     error = render->raster_render( render->raster,
358                                    (const FT_Raster_Params*)&params );
359 
360     /* transform the outline back to the original state */
361     if ( x_shift || y_shift )
362       FT_Outline_Translate( outline, -x_shift, -y_shift );
363 
364   Exit:
365     if ( !error )
366     {
367       /* the glyph is successfully rendered to a bitmap */
368       slot->format = FT_GLYPH_FORMAT_BITMAP;
369     }
370     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
371     {
372       FT_FREE( bitmap->buffer );
373       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
374     }
375 
376     return error;
377   }
378 
379 
380   /* transform the glyph using matrix and/or delta */
381   static FT_Error
ft_sdf_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)382   ft_sdf_transform( FT_Renderer       render,
383                     FT_GlyphSlot      slot,
384                     const FT_Matrix*  matrix,
385                     const FT_Vector*  delta )
386   {
387     FT_Error  error = FT_Err_Ok;
388 
389 
390     if ( slot->format != render->glyph_format )
391     {
392       error = FT_THROW( Invalid_Argument );
393       goto Exit;
394     }
395 
396     if ( matrix )
397       FT_Outline_Transform( &slot->outline, matrix );
398 
399     if ( delta )
400       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
401 
402   Exit:
403     return error;
404   }
405 
406 
407   /* return the control box of a glyph's outline */
408   static void
ft_sdf_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)409   ft_sdf_get_cbox( FT_Renderer   render,
410                    FT_GlyphSlot  slot,
411                    FT_BBox*      cbox )
412   {
413     FT_ZERO( cbox );
414 
415     if ( slot->format == render->glyph_format )
416       FT_Outline_Get_CBox( &slot->outline, cbox );
417   }
418 
419 
420   /* set render specific modes or attributes */
421   static FT_Error
ft_sdf_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)422   ft_sdf_set_mode( FT_Renderer  render,
423                    FT_ULong     mode_tag,
424                    FT_Pointer   data )
425   {
426     /* pass it to the rasterizer */
427     return render->clazz->raster_class->raster_set_mode( render->raster,
428                                                          mode_tag,
429                                                          data );
430   }
431 
432 
433   FT_DEFINE_RENDERER(
434     ft_sdf_renderer_class,
435 
436     FT_MODULE_RENDERER,
437     sizeof ( SDF_Renderer_Module ),
438 
439     "sdf",
440     0x10000L,
441     0x20000L,
442 
443     NULL,
444 
445     (FT_Module_Constructor)ft_sdf_init,
446     (FT_Module_Destructor) ft_sdf_done,
447     (FT_Module_Requester)  ft_sdf_requester,
448 
449     FT_GLYPH_FORMAT_OUTLINE,
450 
451     (FT_Renderer_RenderFunc)   ft_sdf_render,     /* render_glyph    */
452     (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
453     (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
454     (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
455 
456     (FT_Raster_Funcs*)&ft_sdf_raster              /* raster_class    */
457   )
458 
459 
460   /*************************************************************************/
461   /*************************************************************************/
462   /**                                                                     **/
463   /**  BITMAP TO SDF CONVERTER                                            **/
464   /**                                                                     **/
465   /*************************************************************************/
466   /*************************************************************************/
467 
468   /* generate signed distance field from glyph's bitmap */
469   static FT_Error
ft_bsdf_render(FT_Renderer module,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)470   ft_bsdf_render( FT_Renderer       module,
471                   FT_GlyphSlot      slot,
472                   FT_Render_Mode    mode,
473                   const FT_Vector*  origin )
474   {
475     FT_Error   error  = FT_Err_Ok;
476     FT_Memory  memory = NULL;
477 
478     FT_Bitmap*   bitmap  = &slot->bitmap;
479     FT_Renderer  render  = NULL;
480     FT_Bitmap    target;
481 
482     FT_Pos  x_pad = 0;
483     FT_Pos  y_pad = 0;
484 
485     SDF_Raster_Params  params;
486     SDF_Renderer       sdf_module = SDF_RENDERER( module );
487 
488 
489     /* initialize the bitmap in case any error occurs */
490     FT_Bitmap_Init( &target );
491 
492     render = &sdf_module->root;
493     memory = render->root.memory;
494 
495     /* check whether slot format is correct before rendering */
496     if ( slot->format != render->glyph_format )
497     {
498       error = FT_THROW( Invalid_Glyph_Format );
499       goto Exit;
500     }
501 
502     /* check whether render mode is correct */
503     if ( mode != FT_RENDER_MODE_SDF )
504     {
505       error = FT_THROW( Cannot_Render_Glyph );
506       goto Exit;
507     }
508 
509     if ( origin )
510     {
511       FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" ));
512 
513       error = FT_THROW( Unimplemented_Feature );
514       goto Exit;
515     }
516 
517     /* Do not generate SDF if the bitmap is not owned by the       */
518     /* glyph: it might be that the source buffer is already freed. */
519     if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
520     {
521       FT_ERROR(( "ft_bsdf_render: can't generate SDF from"
522                  " unowned source bitmap\n" ));
523 
524       error = FT_THROW( Invalid_Argument );
525       goto Exit;
526     }
527 
528     if ( !bitmap->rows || !bitmap->pitch )
529     {
530       FT_ERROR(( "ft_bsdf_render: invalid bitmap size\n" ));
531 
532       error = FT_THROW( Invalid_Argument );
533       goto Exit;
534     }
535 
536     FT_Bitmap_New( &target );
537 
538     /* padding will simply be equal to `spread` */
539     x_pad = sdf_module->spread;
540     y_pad = sdf_module->spread;
541 
542     /* apply padding, which extends to all directions */
543     target.rows  = bitmap->rows  + y_pad * 2;
544     target.width = bitmap->width + x_pad * 2;
545 
546     /* set up the target bitmap */
547     target.pixel_mode = FT_PIXEL_MODE_GRAY;
548     target.pitch      = (int)( target.width );
549     target.num_grays  = 255;
550 
551     if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) )
552       goto Exit;
553 
554     /* set up parameters */
555     params.root.target = &target;
556     params.root.source = bitmap;
557     params.root.flags  = FT_RASTER_FLAG_SDF;
558     params.spread      = sdf_module->spread;
559     params.flip_sign   = sdf_module->flip_sign;
560     params.flip_y      = sdf_module->flip_y;
561 
562     error = render->raster_render( render->raster,
563                                    (const FT_Raster_Params*)&params );
564 
565   Exit:
566     if ( !error )
567     {
568       /* the glyph is successfully converted to a SDF */
569       if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
570       {
571         FT_FREE( bitmap->buffer );
572         slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
573       }
574 
575       slot->bitmap           = target;
576       slot->bitmap_top      += y_pad;
577       slot->bitmap_left     -= x_pad;
578       slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
579     }
580     else if ( target.buffer )
581       FT_FREE( target.buffer );
582 
583     return error;
584   }
585 
586 
587   FT_DEFINE_RENDERER(
588     ft_bitmap_sdf_renderer_class,
589 
590     FT_MODULE_RENDERER,
591     sizeof ( SDF_Renderer_Module ),
592 
593     "bsdf",
594     0x10000L,
595     0x20000L,
596 
597     NULL,
598 
599     (FT_Module_Constructor)ft_sdf_init,
600     (FT_Module_Destructor) ft_sdf_done,
601     (FT_Module_Requester)  ft_sdf_requester,
602 
603     FT_GLYPH_FORMAT_BITMAP,
604 
605     (FT_Renderer_RenderFunc)   ft_bsdf_render,    /* render_glyph    */
606     (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
607     (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
608     (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
609 
610     (FT_Raster_Funcs*)&ft_bitmap_sdf_raster       /* raster_class    */
611   )
612 
613 
614 /* END */
615