Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / sdf / ftbsdf.c
1 /****************************************************************************
2  *
3  * ftbsdf.c
4  *
5  *   Signed Distance Field support for bitmap fonts (body only).
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/ftobjs.h>
22 #include <freetype/internal/ftdebug.h>
23 #include <freetype/internal/ftmemory.h>
24 #include <freetype/fttrigon.h>
25
26 #include "ftsdf.h"
27 #include "ftsdferrs.h"
28 #include "ftsdfcommon.h"
29
30
31   /**************************************************************************
32    *
33    * A brief technical overview of how the BSDF rasterizer works
34    * -----------------------------------------------------------
35    *
36    * [Notes]:
37    *   * SDF stands for Signed Distance Field everywhere.
38    *
39    *   * BSDF stands for Bitmap to Signed Distance Field rasterizer.
40    *
41    *   * This renderer converts rasterized bitmaps to SDF.  There is another
42    *     renderer called 'sdf', which generates SDF directly from outlines;
43    *     see file `ftsdf.c` for more.
44    *
45    *   * The idea of generating SDF from bitmaps is taken from two research
46    *     papers, where one is dependent on the other:
47    *
48    *     - Per-Erik Danielsson: Euclidean Distance Mapping
49    *       http://webstaff.itn.liu.se/~stegu/JFA/Danielsson.pdf
50    *
51    *       From this paper we use the eight-point sequential Euclidean
52    *       distance mapping (8SED).  This is the heart of the process used
53    *       in this rasterizer.
54    *
55    *     - Stefan Gustavson, Robin Strand: Anti-aliased Euclidean distance transform.
56    *       http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf
57    *
58    *       The original 8SED algorithm discards the pixels' alpha values,
59    *       which can contain information about the actual outline of the
60    *       glyph.  This paper takes advantage of those alpha values and
61    *       approximates outline pretty accurately.
62    *
63    *   * This rasterizer also works for monochrome bitmaps.  However, the
64    *     result is not as accurate since we don't have any way to
65    *     approximate outlines from binary bitmaps.
66    *
67    * ========================================================================
68    *
69    * Generating SDF from bitmap is done in several steps.
70    *
71    * (1) The only information we have is the bitmap itself.  It can
72    *     be monochrome or anti-aliased.  If it is anti-aliased, pixel values
73    *     are nothing but coverage values.  These coverage values can be used
74    *     to extract information about the outline of the image.  For
75    *     example, if the pixel's alpha value is 0.5, then we can safely
76    *     assume that the outline passes through the center of the pixel.
77    *
78    * (2) Find edge pixels in the bitmap (see `bsdf_is_edge` for more).  For
79    *     all edge pixels we use the Anti-aliased Euclidean distance
80    *     transform algorithm and compute approximate edge distances (see
81    *     `compute_edge_distance` and/or the second paper for more).
82    *
83    * (3) Now that we have computed approximate distances for edge pixels we
84    *     use the 8SED algorithm to basically sweep the entire bitmap and
85    *     compute distances for the rest of the pixels.  (Since the algorithm
86    *     is pretty convoluted it is only explained briefly in a comment to
87    *     function `edt8`.  To see the actual algorithm refer to the first
88    *     paper.)
89    *
90    * (4) Finally, compute the sign for each pixel.  This is done in function
91    *     `finalize_sdf`.  The basic idea is that if a pixel's original
92    *     alpha/coverage value is greater than 0.5 then it is 'inside' (and
93    *     'outside' otherwise).
94    *
95    * Pseudo Code:
96    *
97    * ```
98    * b  = source bitmap;
99    * t  = target bitmap;
100    * dm = list of distances; // dimension equal to b
101    *
102    * foreach grid_point (x, y) in b:
103    * {
104    *   if (is_edge(x, y)):
105    *     dm = approximate_edge_distance(b, x, y);
106    *
107    *   // do the 8SED on the distances
108    *   edt8(dm);
109    *
110    *   // determine the signs
111    *   determine_signs(dm):
112    *
113    *   // copy SDF data to the target bitmap
114    *   copy(dm to t);
115    * }
116    *
117    */
118
119
120   /**************************************************************************
121    *
122    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
123    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
124    * messages during execution.
125    */
126 #undef  FT_COMPONENT
127 #define FT_COMPONENT  bsdf
128
129
130   /**************************************************************************
131    *
132    * useful macros
133    *
134    */
135
136 #define ONE  65536 /* 1 in 16.16 */
137
138
139   /**************************************************************************
140    *
141    * structs
142    *
143    */
144
145
146   /**************************************************************************
147    *
148    * @Struct:
149    *   BSDF_TRaster
150    *
151    * @Description:
152    *   This struct is used in place of @FT_Raster and is stored within the
153    *   internal FreeType renderer struct.  While rasterizing this is passed
154    *   to the @FT_Raster_RenderFunc function, which then can be used however
155    *   we want.
156    *
157    * @Fields:
158    *   memory ::
159    *     Used internally to allocate intermediate memory while raterizing.
160    *
161    */
162   typedef struct  BSDF_TRaster_
163   {
164     FT_Memory  memory;
165
166   } BSDF_TRaster, *BSDF_PRaster;
167
168
169   /**************************************************************************
170    *
171    * @Struct:
172    *   ED
173    *
174    * @Description:
175    *   Euclidean distance.  It gets used for Euclidean distance transforms;
176    *   it can also be interpreted as an edge distance.
177    *
178    * @Fields:
179    *   dist ::
180    *     Vector length of the `prox` parameter.  Can be squared or absolute
181    *     depending on the `USE_SQUARED_DISTANCES` macro defined in file
182    *     `ftsdfcommon.h`.
183    *
184    *   prox ::
185    *     Vector to the nearest edge.  Can also be interpreted as shortest
186    *     distance of a point.
187    *
188    *   alpha ::
189    *     Alpha value of the original bitmap from which we generate SDF.
190    *     Needed for computing the gradient and determining the proper sign
191    *     of a pixel.
192    *
193    */
194   typedef struct  ED_
195   {
196     FT_16D16      dist;
197     FT_16D16_Vec  prox;
198     FT_Byte       alpha;
199
200   } ED;
201
202
203   /**************************************************************************
204    *
205    * @Struct:
206    *   BSDF_Worker
207    *
208    * @Description:
209    *   A convenience struct that is passed to functions while generating
210    *   SDF; most of those functions require the same parameters.
211    *
212    * @Fields:
213    *   distance_map ::
214    *     A one-dimensional array that gets interpreted as two-dimensional
215    *     one.  It contains the Euclidean distances of all points of the
216    *     bitmap.
217    *
218    *   width ::
219    *     Width of the above `distance_map`.
220    *
221    *   rows ::
222    *     Number of rows in the above `distance_map`.
223    *
224    *   params ::
225    *     Internal parameters and properties required by the rasterizer.  See
226    *     file `ftsdf.h` for more.
227    *
228    */
229   typedef struct  BSDF_Worker_
230   {
231     ED*  distance_map;
232
233     FT_Int  width;
234     FT_Int  rows;
235
236     SDF_Raster_Params  params;
237
238   } BSDF_Worker;
239
240
241   /**************************************************************************
242    *
243    * initializer
244    *
245    */
246
247   static const ED  zero_ed = { 0, { 0, 0 }, 0 };
248
249
250   /**************************************************************************
251    *
252    * rasterizer functions
253    *
254    */
255
256   /**************************************************************************
257    *
258    * @Function:
259    *   bsdf_is_edge
260    *
261    * @Description:
262    *   Check whether a pixel is an edge pixel, i.e., whether it is
263    *   surrounded by a completely black pixel (zero alpha), and the current
264    *   pixel is not a completely black pixel.
265    *
266    * @Input:
267    *   dm ::
268    *     Array of distances.  The parameter must point to the current
269    *     pixel, i.e., the pixel that is to be checked for being an edge.
270    *
271    *   x ::
272    *     The x position of the current pixel.
273    *
274    *   y ::
275    *     The y position of the current pixel.
276    *
277    *   w ::
278    *     Width of the bitmap.
279    *
280    *   r ::
281    *     Number of rows in the bitmap.
282    *
283    * @Return:
284    *   1~if the current pixel is an edge pixel, 0~otherwise.
285    *
286    */
287
288 #ifdef CHECK_NEIGHBOR
289 #undef CHECK_NEIGHBOR
290 #endif
291
292 #define CHECK_NEIGHBOR( x_offset, y_offset )              \
293           do                                              \
294           {                                               \
295             if ( x + x_offset >= 0 && x + x_offset < w && \
296                  y + y_offset >= 0 && y + y_offset < r )  \
297             {                                             \
298               num_neighbors++;                            \
299                                                           \
300               to_check = dm + y_offset * w + x_offset;    \
301               if ( to_check->alpha == 0 )                 \
302               {                                           \
303                 is_edge = 1;                              \
304                 goto Done;                                \
305               }                                           \
306             }                                             \
307           } while ( 0 )
308
309   static FT_Bool
310   bsdf_is_edge( ED*     dm,   /* distance map              */
311                 FT_Int  x,    /* x index of point to check */
312                 FT_Int  y,    /* y index of point to check */
313                 FT_Int  w,    /* width                     */
314                 FT_Int  r )   /* rows                      */
315   {
316     FT_Bool  is_edge       = 0;
317     ED*      to_check      = NULL;
318     FT_Int   num_neighbors = 0;
319
320
321     if ( dm->alpha == 0 )
322       goto Done;
323
324     if ( dm->alpha > 0 && dm->alpha < 255 )
325     {
326       is_edge = 1;
327       goto Done;
328     }
329
330     /* up */
331     CHECK_NEIGHBOR(  0, -1 );
332
333     /* down */
334     CHECK_NEIGHBOR(  0,  1 );
335
336     /* left */
337     CHECK_NEIGHBOR( -1,  0 );
338
339     /* right */
340     CHECK_NEIGHBOR(  1,  0 );
341
342     /* up left */
343     CHECK_NEIGHBOR( -1, -1 );
344
345     /* up right */
346     CHECK_NEIGHBOR(  1, -1 );
347
348     /* down left */
349     CHECK_NEIGHBOR( -1,  1 );
350
351     /* down right */
352     CHECK_NEIGHBOR(  1,  1 );
353
354     if ( num_neighbors != 8 )
355       is_edge = 1;
356
357   Done:
358     return is_edge;
359   }
360
361 #undef CHECK_NEIGHBOR
362
363
364   /**************************************************************************
365    *
366    * @Function:
367    *   compute_edge_distance
368    *
369    * @Description:
370    *   Approximate the outline and compute the distance from `current`
371    *   to the approximated outline.
372    *
373    * @Input:
374    *   current ::
375    *     Array of Euclidean distances.  `current` must point to the position
376    *     for which the distance is to be caculated.  We treat this array as
377    *     a two-dimensional array mapped to a one-dimensional array.
378    *
379    *   x ::
380    *     The x coordinate of the `current` parameter in the array.
381    *
382    *   y ::
383    *     The y coordinate of the `current` parameter in the array.
384    *
385    *   w ::
386    *     The width of the distances array.
387    *
388    *   r ::
389    *     Number of rows in the distances array.
390    *
391    * @Return:
392    *   A vector pointing to the approximate edge distance.
393    *
394    * @Note:
395    *   This is a computationally expensive function.  Try to reduce the
396    *   number of calls to this function.  Moreover, this must only be used
397    *   for edge pixel positions.
398    *
399    */
400   static FT_16D16_Vec
401   compute_edge_distance( ED*     current,
402                          FT_Int  x,
403                          FT_Int  y,
404                          FT_Int  w,
405                          FT_Int  r )
406   {
407     /*
408      * This function, based on the paper presented by Stefan Gustavson and
409      * Robin Strand, gets used to approximate edge distances from
410      * anti-aliased bitmaps.
411      *
412      * The algorithm is as follows.
413      *
414      * (1) In anti-aliased images, the pixel's alpha value is the coverage
415      *     of the pixel by the outline.  For example, if the alpha value is
416      *     0.5f we can assume that the outline passes through the center of
417      *     the pixel.
418      *
419      * (2) For this reason we can use that alpha value to approximate the real
420      *     distance of the pixel to edge pretty accurately.  A simple
421      *     approximation is `(0.5f - alpha)`, assuming that the outline is
422      *     parallel to the x or y~axis.  However, in this algorithm we use a
423      *     different approximation which is quite accurate even for
424      *     non-axis-aligned edges.
425      *
426      * (3) The only remaining piece of information that we cannot
427      *     approximate directly from the alpha is the direction of the edge.
428      *     This is where we use Sobel's operator to compute the gradient of
429      *     the pixel.  The gradient give us a pretty good approximation of
430      *     the edge direction.  We use a 3x3 kernel filter to compute the
431      *     gradient.
432      *
433      * (4) After the above two steps we have both the direction and the
434      *     distance to the edge which is used to generate the Signed
435      *     Distance Field.
436      *
437      * References:
438      *
439      * - Anti-Aliased Euclidean Distance Transform:
440      *     http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf
441      * - Sobel Operator:
442      *     https://en.wikipedia.org/wiki/Sobel_operator
443      */
444
445     FT_16D16_Vec  g = { 0, 0 };
446     FT_16D16      dist, current_alpha;
447     FT_16D16      a1, temp;
448     FT_16D16      gx, gy;
449     FT_16D16      alphas[9];
450
451
452     /* Since our spread cannot be 0, this condition */
453     /* can never be true.                           */
454     if ( x <= 0 || x >= w - 1 ||
455          y <= 0 || y >= r - 1 )
456       return g;
457
458     /* initialize the alphas */
459     alphas[0] = 256 * (FT_16D16)current[-w - 1].alpha;
460     alphas[1] = 256 * (FT_16D16)current[-w    ].alpha;
461     alphas[2] = 256 * (FT_16D16)current[-w + 1].alpha;
462     alphas[3] = 256 * (FT_16D16)current[    -1].alpha;
463     alphas[4] = 256 * (FT_16D16)current[     0].alpha;
464     alphas[5] = 256 * (FT_16D16)current[     1].alpha;
465     alphas[6] = 256 * (FT_16D16)current[ w - 1].alpha;
466     alphas[7] = 256 * (FT_16D16)current[ w    ].alpha;
467     alphas[8] = 256 * (FT_16D16)current[ w + 1].alpha;
468
469     current_alpha = alphas[4];
470
471     /* Compute the gradient using the Sobel operator. */
472     /* In this case we use the following 3x3 filters: */
473     /*                                                */
474     /* For x: |   -1     0   -1    |                  */
475     /*        | -root(2) 0 root(2) |                  */
476     /*        |    -1    0    1    |                  */
477     /*                                                */
478     /* For y: |   -1 -root(2) -1   |                  */
479     /*        |    0    0      0   |                  */
480     /*        |    1  root(2)  1   |                  */
481     /*                                                */
482     /* [Note]: 92681 is root(2) in 16.16 format.      */
483     g.x = -alphas[0] -
484            FT_MulFix( alphas[3], 92681 ) -
485            alphas[6] +
486            alphas[2] +
487            FT_MulFix( alphas[5], 92681 ) +
488            alphas[8];
489
490     g.y = -alphas[0] -
491            FT_MulFix( alphas[1], 92681 ) -
492            alphas[2] +
493            alphas[6] +
494            FT_MulFix( alphas[7], 92681 ) +
495            alphas[8];
496
497     FT_Vector_NormLen( &g );
498
499     /* The gradient gives us the direction of the    */
500     /* edge for the current pixel.  Once we have the */
501     /* approximate direction of the edge, we can     */
502     /* approximate the edge distance much better.    */
503
504     if ( g.x == 0 || g.y == 0 )
505       dist = ONE / 2 - alphas[4];
506     else
507     {
508       gx = g.x;
509       gy = g.y;
510
511       gx = FT_ABS( gx );
512       gy = FT_ABS( gy );
513
514       if ( gx < gy )
515       {
516         temp = gx;
517         gx   = gy;
518         gy   = temp;
519       }
520
521       a1 = FT_DivFix( gy, gx ) / 2;
522
523       if ( current_alpha < a1 )
524         dist = ( gx + gy ) / 2 -
525                square_root( 2 * FT_MulFix( gx,
526                                            FT_MulFix( gy,
527                                                       current_alpha ) ) );
528
529       else if ( current_alpha < ( ONE - a1 ) )
530         dist = FT_MulFix( ONE / 2 - current_alpha, gx );
531
532       else
533         dist = -( gx + gy ) / 2 +
534                square_root( 2 * FT_MulFix( gx,
535                                            FT_MulFix( gy,
536                                                       ONE - current_alpha ) ) );
537     }
538
539     g.x = FT_MulFix( g.x, dist );
540     g.y = FT_MulFix( g.y, dist );
541
542     return g;
543   }
544
545
546   /**************************************************************************
547    *
548    * @Function:
549    *   bsdf_approximate_edge
550    *
551    * @Description:
552    *   Loops over all the pixels and call `compute_edge_distance` only for
553    *   edge pixels.  This maked the process a lot faster since
554    *   `compute_edge_distance` uses functions such as `FT_Vector_NormLen',
555    *   which are quite slow.
556    *
557    * @InOut:
558    *   worker ::
559    *     Contains the distance map as well as all the relevant parameters
560    *     required by the function.
561    *
562    * @Return:
563    *   FreeType error, 0 means success.
564    *
565    * @Note:
566    *   The function directly manipulates `worker->distance_map`.
567    *
568    */
569   static FT_Error
570   bsdf_approximate_edge( BSDF_Worker*  worker )
571   {
572     FT_Error  error = FT_Err_Ok;
573     FT_Int    i, j;
574     FT_Int    index;
575     ED*       ed;
576
577
578     if ( !worker || !worker->distance_map )
579     {
580       error = FT_THROW( Invalid_Argument );
581       goto Exit;
582     }
583
584     ed = worker->distance_map;
585
586     for ( j = 0; j < worker->rows; j++ )
587     {
588       for ( i = 0; i < worker->width; i++ )
589       {
590         index = j * worker->width + i;
591
592         if ( bsdf_is_edge( worker->distance_map + index,
593                            i, j,
594                            worker->width,
595                            worker->rows ) )
596         {
597           /* approximate the edge distance for edge pixels */
598           ed[index].prox = compute_edge_distance( ed + index,
599                                                   i, j,
600                                                   worker->width,
601                                                   worker->rows );
602           ed[index].dist = VECTOR_LENGTH_16D16( ed[index].prox );
603         }
604         else
605         {
606           /* for non-edge pixels assign far away distances */
607           ed[index].dist   = 400 * ONE;
608           ed[index].prox.x = 200 * ONE;
609           ed[index].prox.y = 200 * ONE;
610         }
611       }
612     }
613
614   Exit:
615     return error;
616   }
617
618
619   /**************************************************************************
620    *
621    * @Function:
622    *   bsdf_init_distance_map
623    *
624    * @Description:
625    *   Initialize the distance map according to the '8-point sequential
626    *   Euclidean distance mapping' (8SED) algorithm.  Basically it copies
627    *   the `source` bitmap alpha values to the `distance_map->alpha`
628    *   parameter of `worker`.
629    *
630    * @Input:
631    *   source ::
632    *     Source bitmap to copy the data from.
633    *
634    * @Output:
635    *   worker ::
636    *     Target distance map to copy the data to.
637    *
638    * @Return:
639    *   FreeType error, 0 means success.
640    *
641    */
642   static FT_Error
643   bsdf_init_distance_map( const FT_Bitmap*  source,
644                           BSDF_Worker*      worker )
645   {
646     FT_Error  error = FT_Err_Ok;
647
648     FT_Int    x_diff, y_diff;
649     FT_Int    t_i, t_j, s_i, s_j;
650     FT_Byte*  s;
651     ED*       t;
652
653
654     /* again check the parameters (probably unnecessary) */
655     if ( !source || !worker )
656     {
657       error = FT_THROW( Invalid_Argument );
658       goto Exit;
659     }
660
661     /* Because of the way we convert a bitmap to SDF, */
662     /* i.e., aligning the source to the center of the */
663     /* target, the target's width and rows must be    */
664     /* checked before copying.                        */
665     if ( worker->width < (FT_Int)source->width ||
666          worker->rows  < (FT_Int)source->rows  )
667     {
668       error = FT_THROW( Invalid_Argument );
669       goto Exit;
670     }
671
672     /* check pixel mode */
673     if ( source->pixel_mode == FT_PIXEL_MODE_NONE )
674     {
675       FT_ERROR(( "bsdf_copy_source_to_target:"
676                  " Invalid pixel mode of source bitmap" ));
677       error = FT_THROW( Invalid_Argument );
678       goto Exit;
679     }
680
681 #ifdef FT_DEBUG_LEVEL_TRACE
682     if ( source->pixel_mode == FT_PIXEL_MODE_MONO )
683     {
684       FT_TRACE0(( "bsdf_copy_source_to_target:"
685                   " The `bsdf' renderer can convert monochrome\n" ));
686       FT_TRACE0(( "                           "
687                   " bitmaps to SDF but the results are not perfect\n" ));
688       FT_TRACE0(( "                           "
689                   " because there is no way to approximate actual\n" ));
690       FT_TRACE0(( "                           "
691                   " outlines from monochrome bitmaps.  Consider\n" ));
692       FT_TRACE0(( "                           "
693                   " using an anti-aliased bitmap instead.\n" ));
694     }
695 #endif
696
697     /* Calculate the width and row differences */
698     /* between target and source.              */
699     x_diff = worker->width - (int)source->width;
700     y_diff = worker->rows - (int)source->rows;
701
702     x_diff /= 2;
703     y_diff /= 2;
704
705     t = (ED*)worker->distance_map;
706     s = source->buffer;
707
708     /* For now we only support pixel mode `FT_PIXEL_MODE_MONO`  */
709     /* and `FT_PIXEL_MODE_GRAY`.  More will be added later.     */
710     /*                                                          */
711     /* [NOTE]: We can also use @FT_Bitmap_Convert to convert    */
712     /*         bitmap to 8bpp.  To avoid extra allocation and   */
713     /*         since the target bitmap can be 16bpp we manually */
714     /*         convert the source bitmap to the desired bpp.    */
715
716     switch ( source->pixel_mode )
717     {
718     case FT_PIXEL_MODE_MONO:
719       {
720         FT_Int  t_width = worker->width;
721         FT_Int  t_rows  = worker->rows;
722         FT_Int  s_width = (int)source->width;
723         FT_Int  s_rows  = (int)source->rows;
724
725
726         for ( t_j = 0; t_j < t_rows; t_j++ )
727         {
728           for ( t_i = 0; t_i < t_width; t_i++ )
729           {
730             FT_Int   t_index = t_j * t_width + t_i;
731             FT_Int   s_index;
732             FT_Int   div, mod;
733             FT_Byte  pixel, byte;
734
735
736             t[t_index] = zero_ed;
737
738             s_i = t_i - x_diff;
739             s_j = t_j - y_diff;
740
741             /* Assign 0 to padding similar to */
742             /* the source bitmap.             */
743             if ( s_i < 0 || s_i >= s_width ||
744                  s_j < 0 || s_j >= s_rows  )
745               continue;
746
747             if ( worker->params.flip_y )
748               s_index = ( s_rows - s_j - 1 ) * source->pitch;
749             else
750               s_index = s_j * source->pitch;
751
752             div = s_index + s_i / 8;
753             mod = 7 - s_i % 8;
754
755             pixel = s[div];
756             byte  = (FT_Byte)( 1 << mod );
757
758             t[t_index].alpha = pixel & byte ? 255 : 0;
759           }
760         }
761       }
762       break;
763
764     case FT_PIXEL_MODE_GRAY:
765       {
766         FT_Int  t_width = worker->width;
767         FT_Int  t_rows  = worker->rows;
768         FT_Int  s_width = (int)source->width;
769         FT_Int  s_rows  = (int)source->rows;
770
771
772         /* loop over all pixels and assign pixel values from source */
773         for ( t_j = 0; t_j < t_rows; t_j++ )
774         {
775           for ( t_i = 0; t_i < t_width; t_i++ )
776           {
777             FT_Int  t_index = t_j * t_width + t_i;
778             FT_Int  s_index;
779
780
781             t[t_index] = zero_ed;
782
783             s_i = t_i - x_diff;
784             s_j = t_j - y_diff;
785
786             /* Assign 0 to padding similar to */
787             /* the source bitmap.             */
788             if ( s_i < 0 || s_i >= s_width ||
789                  s_j < 0 || s_j >= s_rows  )
790               continue;
791
792             if ( worker->params.flip_y )
793               s_index = ( s_rows - s_j - 1 ) * s_width + s_i;
794             else
795               s_index = s_j * s_width + s_i;
796
797             /* simply copy the alpha values */
798             t[t_index].alpha = s[s_index];
799           }
800         }
801       }
802       break;
803
804     default:
805       FT_ERROR(( "bsdf_copy_source_to_target:"
806                  " unsopported pixel mode of source bitmap\n" ));
807
808       error = FT_THROW( Unimplemented_Feature );
809       break;
810     }
811
812   Exit:
813     return error;
814   }
815
816
817   /**************************************************************************
818    *
819    * @Function:
820    *   compare_neighbor
821    *
822    * @Description:
823    *   Compare neighbor pixel (which is defined by the offset) and update
824    *   `current` distance if the new distance is shorter than the original.
825    *
826    * @Input:
827    *   x_offset ::
828    *     X offset of the neighbor to be checked.  The offset is relative to
829    *     the `current`.
830    *
831    *   y_offset ::
832    *     Y offset of the neighbor to be checked.  The offset is relative to
833    *     the `current`.
834    *
835    *   width ::
836    *     Width of the `current` array.
837    *
838    * @InOut:
839    *   current ::
840    *     Pointer into array of distances.  This parameter must point to the
841    *     position whose neighbor is to be checked.  The array is treated as
842    *     a two-dimensional array.
843    *
844    */
845   static void
846   compare_neighbor( ED*     current,
847                     FT_Int  x_offset,
848                     FT_Int  y_offset,
849                     FT_Int  width )
850   {
851     ED*           to_check;
852     FT_16D16      dist;
853     FT_16D16_Vec  dist_vec;
854
855
856     to_check = current + ( y_offset * width ) + x_offset;
857
858     /*
859      * While checking for the nearest point we first approximate the
860      * distance of `current` by adding the deviation (which is sqrt(2) at
861      * most).  Only if the new value is less than the current value we
862      * calculate the actual distances using `FT_Vector_Length`.  This last
863      * step can be omitted by using squared distances.
864      */
865
866     /*
867      * Approximate the distance.  We subtract 1 to avoid precision errors,
868      * which could happen because the two directions can be opposite.
869      */
870     dist = to_check->dist - ONE;
871
872     if ( dist < current->dist )
873     {
874       dist_vec = to_check->prox;
875
876       dist_vec.x += x_offset * ONE;
877       dist_vec.y += y_offset * ONE;
878       dist = VECTOR_LENGTH_16D16( dist_vec );
879
880       if ( dist < current->dist )
881       {
882         current->dist = dist;
883         current->prox = dist_vec;
884       }
885     }
886   }
887
888
889   /**************************************************************************
890    *
891    * @Function:
892    *   first_pass
893    *
894    * @Description:
895    *   First pass of the 8SED algorithm.  Loop over the bitmap from top to
896    *   bottom and scan each row left to right, updating the distances in
897    *   `worker->distance_map`.
898    *
899    * @InOut:
900    *   worker::
901    *     Contains all the relevant parameters.
902    *
903    */
904   static void
905   first_pass( BSDF_Worker*  worker )
906   {
907     FT_Int  i, j; /* iterators    */
908     FT_Int  w, r; /* width, rows  */
909     ED*     dm;   /* distance map */
910
911
912     dm = worker->distance_map;
913     w  = worker->width;
914     r  = worker->rows;
915
916     /* Start scanning from top to bottom and sweep each    */
917     /* row back and forth comparing the distances of the   */
918     /* neighborhood.  Leave the first row as it has no top */
919     /* neighbor; it will be covered in the second scan of  */
920     /* the image (from bottom to top).                     */
921     for ( j = 1; j < r; j++ )
922     {
923       FT_Int  index;
924       ED*     current;
925
926
927       /* Forward pass of rows (left -> right).  Leave the first  */
928       /* column, which gets covered in the backward pass.        */
929       for ( i = 1; i < w - 1; i++ )
930       {
931         index   = j * w + i;
932         current = dm + index;
933
934         /* left-up */
935         compare_neighbor( current, -1, -1, w );
936         /* up */
937         compare_neighbor( current,  0, -1, w );
938         /* up-right */
939         compare_neighbor( current,  1, -1, w );
940         /* left */
941         compare_neighbor( current, -1,  0, w );
942       }
943
944       /* Backward pass of rows (right -> left).  Leave the last */
945       /* column, which was already covered in the forward pass. */
946       for ( i = w - 2; i >= 0; i-- )
947       {
948         index   = j * w + i;
949         current = dm + index;
950
951         /* right */
952         compare_neighbor( current, 1, 0, w );
953       }
954     }
955   }
956
957
958   /**************************************************************************
959    *
960    * @Function:
961    *   second_pass
962    *
963    * @Description:
964    *   Second pass of the 8SED algorithm.  Loop over the bitmap from bottom
965    *   to top and scan each row left to right, updating the distances in
966    *   `worker->distance_map`.
967    *
968    * @InOut:
969    *   worker::
970    *     Contains all the relevant parameters.
971    *
972    */
973   static void
974   second_pass( BSDF_Worker*  worker )
975   {
976     FT_Int  i, j; /* iterators    */
977     FT_Int  w, r; /* width, rows  */
978     ED*     dm;   /* distance map */
979
980
981     dm = worker->distance_map;
982     w  = worker->width;
983     r  = worker->rows;
984
985     /* Start scanning from bottom to top and sweep each    */
986     /* row back and forth comparing the distances of the   */
987     /* neighborhood.  Leave the last row as it has no down */
988     /* neighbor; it is already covered in the first scan   */
989     /* of the image (from top to bottom).                  */
990     for ( j = r - 2; j >= 0; j-- )
991     {
992       FT_Int  index;
993       ED*     current;
994
995
996       /* Forward pass of rows (left -> right).  Leave the first */
997       /* column, which gets covered in the backward pass.       */
998       for ( i = 1; i < w - 1; i++ )
999       {
1000         index   = j * w + i;
1001         current = dm + index;
1002
1003         /* left-up */
1004         compare_neighbor( current, -1, 1, w );
1005         /* up */
1006         compare_neighbor( current,  0, 1, w );
1007         /* up-right */
1008         compare_neighbor( current,  1, 1, w );
1009         /* left */
1010         compare_neighbor( current, -1, 0, w );
1011       }
1012
1013       /* Backward pass of rows (right -> left).  Leave the last */
1014       /* column, which was already covered in the forward pass. */
1015       for ( i = w - 2; i >= 0; i-- )
1016       {
1017         index   = j * w + i;
1018         current = dm + index;
1019
1020         /* right */
1021         compare_neighbor( current, 1, 0, w );
1022       }
1023     }
1024   }
1025
1026
1027   /**************************************************************************
1028    *
1029    * @Function:
1030    *   edt8
1031    *
1032    * @Description:
1033    *   Compute the distance map of the a bitmap.  Execute both first and
1034    *   second pass of the 8SED algorithm.
1035    *
1036    * @InOut:
1037    *   worker::
1038    *     Contains all the relevant parameters.
1039    *
1040    * @Return:
1041    *   FreeType error, 0 means success.
1042    *
1043    */
1044   static FT_Error
1045   edt8( BSDF_Worker*  worker )
1046   {
1047     FT_Error  error = FT_Err_Ok;
1048
1049
1050     if ( !worker || !worker->distance_map )
1051     {
1052       error = FT_THROW( Invalid_Argument );
1053       goto Exit;
1054     }
1055
1056     /* first scan of the image */
1057     first_pass( worker );
1058
1059     /* second scan of the image */
1060     second_pass( worker );
1061
1062   Exit:
1063     return error;
1064   }
1065
1066
1067   /**************************************************************************
1068    *
1069    * @Function:
1070    *   finalize_sdf
1071    *
1072    * @Description:
1073    *   Copy the SDF data from `worker->distance_map` to the `target` bitmap.
1074    *   Also transform the data to output format, (which is 6.10 fixed-point
1075    *   format at the moment).
1076    *
1077    * @Input:
1078    *   worker ::
1079    *     Contains source distance map and other SDF data.
1080    *
1081    * @Output:
1082    *   target ::
1083    *     Target bitmap to which the SDF data is copied to.
1084    *
1085    * @Return:
1086    *   FreeType error, 0 means success.
1087    *
1088    */
1089   static FT_Error
1090   finalize_sdf( BSDF_Worker*      worker,
1091                 const FT_Bitmap*  target )
1092   {
1093     FT_Error  error = FT_Err_Ok;
1094
1095     FT_Int  w, r;
1096     FT_Int  i, j;
1097
1098     FT_SDFFormat*  t_buffer;
1099     FT_16D16       sp_sq, spread;
1100
1101
1102     if ( !worker || !target )
1103     {
1104       error = FT_THROW( Invalid_Argument );
1105       goto Exit;
1106     }
1107
1108     w        = (int)target->width;
1109     r        = (int)target->rows;
1110     t_buffer = (FT_SDFFormat*)target->buffer;
1111
1112     if ( w != worker->width ||
1113          r != worker->rows  )
1114     {
1115       error = FT_THROW( Invalid_Argument );
1116       goto Exit;
1117     }
1118
1119     spread = (FT_16D16)FT_INT_16D16( worker->params.spread );
1120
1121 #if USE_SQUARED_DISTANCES
1122     sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread *
1123                                     worker->params.spread );
1124 #else
1125     sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread );
1126 #endif
1127
1128     for ( j = 0; j < r; j++ )
1129     {
1130       for ( i = 0; i < w; i++ )
1131       {
1132         FT_Int        index;
1133         FT_16D16      dist;
1134         FT_SDFFormat  final_dist;
1135         FT_Char       sign;
1136
1137
1138         index = j * w + i;
1139         dist  = worker->distance_map[index].dist;
1140
1141         if ( dist < 0 || dist > sp_sq )
1142           dist = sp_sq;
1143
1144 #if USE_SQUARED_DISTANCES
1145         dist = square_root( dist );
1146 #endif
1147
1148         /* We assume that if the pixel is inside a contour */
1149         /* its coverage value must be > 127.               */
1150         sign = worker->distance_map[index].alpha < 127 ? -1 : 1;
1151
1152         /* flip the sign according to the property */
1153         if ( worker->params.flip_sign )
1154           sign = -sign;
1155
1156         /* concatenate from 16.16 to appropriate format */
1157         final_dist = map_fixed_to_sdf( dist * sign, spread );
1158
1159         t_buffer[index] = final_dist;
1160       }
1161     }
1162
1163   Exit:
1164     return error;
1165   }
1166
1167
1168   /**************************************************************************
1169    *
1170    * interface functions
1171    *
1172    */
1173
1174   /* called when adding a new module through @FT_Add_Module */
1175   static FT_Error
1176   bsdf_raster_new( void*       memory_,    /* FT_Memory     */
1177                    FT_Raster*  araster_ )  /* BSDF_PRaster* */
1178   {
1179     FT_Memory      memory  = (FT_Memory)memory_;
1180     BSDF_PRaster*  araster = (BSDF_PRaster*)araster_;
1181
1182     FT_Error      error;
1183     BSDF_PRaster  raster = NULL;
1184
1185
1186     if ( !FT_NEW( raster ) )
1187       raster->memory = memory;
1188
1189     *araster = raster;
1190
1191     return error;
1192   }
1193
1194
1195   /* unused */
1196   static void
1197   bsdf_raster_reset( FT_Raster       raster,
1198                      unsigned char*  pool_base,
1199                      unsigned long   pool_size )
1200   {
1201     FT_UNUSED( raster );
1202     FT_UNUSED( pool_base );
1203     FT_UNUSED( pool_size );
1204   }
1205
1206
1207   /* unused */
1208   static FT_Error
1209   bsdf_raster_set_mode( FT_Raster      raster,
1210                         unsigned long  mode,
1211                         void*          args )
1212   {
1213     FT_UNUSED( raster );
1214     FT_UNUSED( mode );
1215     FT_UNUSED( args );
1216
1217     return FT_Err_Ok;
1218   }
1219
1220
1221   /* called while rendering through @FT_Render_Glyph */
1222   static FT_Error
1223   bsdf_raster_render( FT_Raster                raster,
1224                       const FT_Raster_Params*  params )
1225   {
1226     FT_Error   error  = FT_Err_Ok;
1227     FT_Memory  memory = NULL;
1228
1229     const FT_Bitmap*  source = NULL;
1230     const FT_Bitmap*  target = NULL;
1231
1232     BSDF_TRaster*  bsdf_raster = (BSDF_TRaster*)raster;
1233     BSDF_Worker    worker;
1234
1235     const SDF_Raster_Params*  sdf_params = (const SDF_Raster_Params*)params;
1236
1237
1238     worker.distance_map = NULL;
1239
1240     /* check for valid parameters */
1241     if ( !raster || !params )
1242     {
1243       error = FT_THROW( Invalid_Argument );
1244       goto Exit;
1245     }
1246
1247     /* check whether the flag is set */
1248     if ( sdf_params->root.flags != FT_RASTER_FLAG_SDF )
1249     {
1250       error = FT_THROW( Raster_Corrupted );
1251       goto Exit;
1252     }
1253
1254     source = (const FT_Bitmap*)sdf_params->root.source;
1255     target = (const FT_Bitmap*)sdf_params->root.target;
1256
1257     /* check source and target bitmap */
1258     if ( !source || !target )
1259     {
1260       error = FT_THROW( Invalid_Argument );
1261       goto Exit;
1262     }
1263
1264     memory = bsdf_raster->memory;
1265     if ( !memory )
1266     {
1267       FT_TRACE0(( "bsdf_raster_render: Raster not set up properly,\n" ));
1268       FT_TRACE0(( "                    unable to find memory handle.\n" ));
1269
1270       error = FT_THROW( Invalid_Handle );
1271       goto Exit;
1272     }
1273
1274     /* check whether spread is set properly */
1275     if ( sdf_params->spread > MAX_SPREAD ||
1276          sdf_params->spread < MIN_SPREAD )
1277     {
1278       FT_TRACE0(( "bsdf_raster_render:"
1279                   " The `spread' field of `SDF_Raster_Params'\n" ));
1280       FT_TRACE0(( "                   "
1281                   " is invalid; the value of this field must be\n" ));
1282       FT_TRACE0(( "                   "
1283                   " within [%d, %d].\n",
1284                   MIN_SPREAD, MAX_SPREAD ));
1285       FT_TRACE0(( "                   "
1286                   " Also, you must pass `SDF_Raster_Params'\n" ));
1287       FT_TRACE0(( "                   "
1288                   " instead of the default `FT_Raster_Params'\n" ));
1289       FT_TRACE0(( "                   "
1290                   " while calling this function and set the fields\n" ));
1291       FT_TRACE0(( "                   "
1292                   " accordingly.\n" ));
1293
1294       error = FT_THROW( Invalid_Argument );
1295       goto Exit;
1296     }
1297
1298     /* set up the worker */
1299
1300     /* allocate the distance map */
1301     if ( FT_QALLOC_MULT( worker.distance_map, target->rows,
1302                          target->width * sizeof ( *worker.distance_map ) ) )
1303       goto Exit;
1304
1305     worker.width  = (int)target->width;
1306     worker.rows   = (int)target->rows;
1307     worker.params = *sdf_params;
1308
1309     FT_CALL( bsdf_init_distance_map( source, &worker ) );
1310     FT_CALL( bsdf_approximate_edge( &worker ) );
1311     FT_CALL( edt8( &worker ) );
1312     FT_CALL( finalize_sdf( &worker, target ) );
1313
1314     FT_TRACE0(( "bsdf_raster_render: Total memory used = %ld\n",
1315                 worker.width * worker.rows *
1316                   (long)sizeof ( *worker.distance_map ) ));
1317
1318   Exit:
1319     if ( worker.distance_map )
1320       FT_FREE( worker.distance_map );
1321
1322     return error;
1323   }
1324
1325
1326   /* called while deleting `FT_Library` only if the module is added */
1327   static void
1328   bsdf_raster_done( FT_Raster  raster )
1329   {
1330     FT_Memory  memory = (FT_Memory)((BSDF_TRaster*)raster)->memory;
1331
1332
1333     FT_FREE( raster );
1334   }
1335
1336
1337   FT_DEFINE_RASTER_FUNCS(
1338     ft_bitmap_sdf_raster,
1339
1340     FT_GLYPH_FORMAT_BITMAP,
1341
1342     (FT_Raster_New_Func)     bsdf_raster_new,       /* raster_new      */
1343     (FT_Raster_Reset_Func)   bsdf_raster_reset,     /* raster_reset    */
1344     (FT_Raster_Set_Mode_Func)bsdf_raster_set_mode,  /* raster_set_mode */
1345     (FT_Raster_Render_Func)  bsdf_raster_render,    /* raster_render   */
1346     (FT_Raster_Done_Func)    bsdf_raster_done       /* raster_done     */
1347   )
1348
1349
1350 /* END */