xref: /aosp_15_r20/external/freetype/src/sdf/ftsdfcommon.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * ftsdfcommon.c
4  *
5  *   Auxiliary data for Signed Distance Field support (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 "ftsdf.h"
22 #include "ftsdfcommon.h"
23 
24 
25   /**************************************************************************
26    *
27    * common functions
28    *
29    */
30 
31   /*
32    * Original algorithm:
33    *
34    *   https://github.com/chmike/fpsqrt
35    *
36    * Use this to compute the square root of a 16.16 fixed-point number.
37    */
38   FT_LOCAL_DEF( FT_16D16 )
square_root(FT_16D16 val)39   square_root( FT_16D16  val )
40   {
41     FT_ULong  t, q, b, r;
42 
43 
44     r = (FT_ULong)val;
45     b = 0x40000000L;
46     q = 0;
47 
48     while ( b > 0x40L )
49     {
50       t = q + b;
51 
52       if ( r >= t )
53       {
54         r -= t;
55         q  = t + b;
56       }
57 
58       r <<= 1;
59       b >>= 1;
60     }
61 
62     q >>= 8;
63 
64     return (FT_16D16)q;
65   }
66 
67 
68   /**************************************************************************
69    *
70    * format and sign manipulating functions
71    *
72    */
73 
74   /*
75    * Convert 16.16 fixed-point values to the desired output format.
76    * In this case we reduce 16.16 fixed-point values to normalized
77    * 8-bit values.
78    *
79    * The `max_value` in the parameter is the maximum value in the
80    * distance field map and is equal to the spread.  We normalize
81    * the distances using this value instead of computing the maximum
82    * value for the entire bitmap.
83    *
84    * You can use this function to map the 16.16 signed values to any
85    * format required.  Do note that the output buffer is 8-bit, so only
86    * use an 8-bit format for `FT_SDFFormat`, or increase the buffer size in
87    * `ftsdfrend.c`.
88    */
89   FT_LOCAL_DEF( FT_SDFFormat )
map_fixed_to_sdf(FT_16D16 dist,FT_16D16 max_value)90   map_fixed_to_sdf( FT_16D16  dist,
91                     FT_16D16  max_value )
92   {
93     FT_SDFFormat  out;
94     FT_16D16      udist;
95 
96 
97     /* normalize the distance values */
98     dist = FT_DivFix( dist, max_value );
99 
100     udist = dist < 0 ? -dist : dist;
101 
102     /* Reduce the distance values to 8 bits.                   */
103     /*                                                         */
104     /* Since +1/-1 in 16.16 takes the 16th bit, we right-shift */
105     /* the number by 9 to make it fit into the 7-bit range.    */
106     /*                                                         */
107     /* One bit is reserved for the sign.                       */
108     udist >>= 9;
109 
110     /* Since `char` can only store a maximum positive value    */
111     /* of 127 we need to make sure it does not wrap around and */
112     /* give a negative value.                                  */
113     if ( dist > 0 && udist > 127 )
114       udist = 127;
115     if ( dist < 0 && udist > 128 )
116       udist = 128;
117 
118     /* Output the data; negative values are from [0, 127] and positive    */
119     /* from [128, 255].  One important thing is that negative values      */
120     /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */
121     /* More on that in `freetype.h` near the documentation of             */
122     /* `FT_RENDER_MODE_SDF`.                                              */
123     out = dist < 0 ? 128 - (FT_SDFFormat)udist
124                    : (FT_SDFFormat)udist + 128;
125 
126     return out;
127   }
128 
129 
130   /*
131    * Invert the signed distance packed into the corresponding format.
132    * So if the values are negative they will become positive in the
133    * chosen format.
134    *
135    * [Note]: This function should only be used after converting the
136    *         16.16 signed distance values to `FT_SDFFormat`.  If that
137    *         conversion has not been done, then simply invert the sign
138    *         and use the above function to pack the values.
139    */
140   FT_LOCAL_DEF( FT_SDFFormat )
invert_sign(FT_SDFFormat dist)141   invert_sign( FT_SDFFormat  dist )
142   {
143     return 255 - dist;
144   }
145 
146 
147 /* END */
148