xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-geometry.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 /*
2  * Copyright © 2022 Behdad Esfahbod
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  */
24 #ifndef HB_GEOMETRY_HH
25 #define HB_GEOMETRY_HH
26 
27 #include "hb.hh"
28 
29 
30 struct hb_extents_t
31 {
hb_extents_thb_extents_t32   hb_extents_t () {}
hb_extents_thb_extents_t33   hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
34     xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
35 
is_emptyhb_extents_t36   bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
is_voidhb_extents_t37   bool is_void () const { return xmin > xmax; }
38 
union_hb_extents_t39   void union_ (const hb_extents_t &o)
40   {
41     xmin = hb_min (xmin, o.xmin);
42     ymin = hb_min (ymin, o.ymin);
43     xmax = hb_max (xmax, o.xmax);
44     ymax = hb_max (ymax, o.ymax);
45   }
46 
intersecthb_extents_t47   void intersect (const hb_extents_t &o)
48   {
49     xmin = hb_max (xmin, o.xmin);
50     ymin = hb_max (ymin, o.ymin);
51     xmax = hb_min (xmax, o.xmax);
52     ymax = hb_min (ymax, o.ymax);
53   }
54 
55   void
add_pointhb_extents_t56   add_point (float x, float y)
57   {
58     if (unlikely (is_void ()))
59     {
60       xmin = xmax = x;
61       ymin = ymax = y;
62     }
63     else
64     {
65       xmin = hb_min (xmin, x);
66       ymin = hb_min (ymin, y);
67       xmax = hb_max (xmax, x);
68       ymax = hb_max (ymax, y);
69     }
70   }
71 
72   float xmin = 0.f;
73   float ymin = 0.f;
74   float xmax = -1.f;
75   float ymax = -1.f;
76 };
77 
78 struct hb_transform_t
79 {
hb_transform_thb_transform_t80   hb_transform_t () {}
hb_transform_thb_transform_t81   hb_transform_t (float xx, float yx,
82 		  float xy, float yy,
83 		  float x0, float y0) :
84     xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
85 
multiplyhb_transform_t86   void multiply (const hb_transform_t &o)
87   {
88     /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
89     hb_transform_t r;
90 
91     r.xx = o.xx * xx + o.yx * xy;
92     r.yx = o.xx * yx + o.yx * yy;
93 
94     r.xy = o.xy * xx + o.yy * xy;
95     r.yy = o.xy * yx + o.yy * yy;
96 
97     r.x0 = o.x0 * xx + o.y0 * xy + x0;
98     r.y0 = o.x0 * yx + o.y0 * yy + y0;
99 
100     *this = r;
101   }
102 
transform_distancehb_transform_t103   void transform_distance (float &dx, float &dy) const
104   {
105     float new_x = xx * dx + xy * dy;
106     float new_y = yx * dx + yy * dy;
107     dx = new_x;
108     dy = new_y;
109   }
110 
transform_pointhb_transform_t111   void transform_point (float &x, float &y) const
112   {
113     transform_distance (x, y);
114     x += x0;
115     y += y0;
116   }
117 
transform_extentshb_transform_t118   void transform_extents (hb_extents_t &extents) const
119   {
120     float quad_x[4], quad_y[4];
121 
122     quad_x[0] = extents.xmin;
123     quad_y[0] = extents.ymin;
124     quad_x[1] = extents.xmin;
125     quad_y[1] = extents.ymax;
126     quad_x[2] = extents.xmax;
127     quad_y[2] = extents.ymin;
128     quad_x[3] = extents.xmax;
129     quad_y[3] = extents.ymax;
130 
131     extents = hb_extents_t {};
132     for (unsigned i = 0; i < 4; i++)
133     {
134       transform_point (quad_x[i], quad_y[i]);
135       extents.add_point (quad_x[i], quad_y[i]);
136     }
137   }
138 
transformhb_transform_t139   void transform (const hb_transform_t &o) { multiply (o); }
140 
translatehb_transform_t141   void translate (float x, float y)
142   {
143     if (x == 0.f && y == 0.f)
144       return;
145 
146     x0 += xx * x + xy * y;
147     y0 += yx * x + yy * y;
148   }
149 
scalehb_transform_t150   void scale (float scaleX, float scaleY)
151   {
152     if (scaleX == 1.f && scaleY == 1.f)
153       return;
154 
155     xx *= scaleX;
156     yx *= scaleX;
157     xy *= scaleY;
158     yy *= scaleY;
159   }
160 
rotatehb_transform_t161   void rotate (float rotation)
162   {
163     if (rotation == 0.f)
164       return;
165 
166     // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
167     rotation = rotation * HB_PI;
168     float c;
169     float s;
170 #ifdef HAVE_SINCOSF
171     sincosf (rotation, &s, &c);
172 #else
173     c = cosf (rotation);
174     s = sinf (rotation);
175 #endif
176     auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f};
177     transform (other);
178   }
179 
skewhb_transform_t180   void skew (float skewX, float skewY)
181   {
182     if (skewX == 0.f && skewY == 0.f)
183       return;
184 
185     // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
186     skewX = skewX * HB_PI;
187     skewY = skewY * HB_PI;
188     auto other = hb_transform_t{1.f,
189 				skewY ? tanf (skewY) : 0.f,
190 				skewX ? tanf (skewX) : 0.f,
191 				1.f,
192 				0.f, 0.f};
193     transform (other);
194   }
195 
196   float xx = 1.f;
197   float yx = 0.f;
198   float xy = 0.f;
199   float yy = 1.f;
200   float x0 = 0.f;
201   float y0 = 0.f;
202 };
203 
204 struct hb_bounds_t
205 {
206   enum status_t {
207     UNBOUNDED,
208     BOUNDED,
209     EMPTY,
210   };
211 
hb_bounds_thb_bounds_t212   hb_bounds_t (status_t status) : status (status) {}
hb_bounds_thb_bounds_t213   hb_bounds_t (const hb_extents_t &extents) :
214     status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
215 
union_hb_bounds_t216   void union_ (const hb_bounds_t &o)
217   {
218     if (o.status == UNBOUNDED)
219       status = UNBOUNDED;
220     else if (o.status == BOUNDED)
221     {
222       if (status == EMPTY)
223 	*this = o;
224       else if (status == BOUNDED)
225         extents.union_ (o.extents);
226     }
227   }
228 
intersecthb_bounds_t229   void intersect (const hb_bounds_t &o)
230   {
231     if (o.status == EMPTY)
232       status = EMPTY;
233     else if (o.status == BOUNDED)
234     {
235       if (status == UNBOUNDED)
236 	*this = o;
237       else if (status == BOUNDED)
238       {
239         extents.intersect (o.extents);
240 	if (extents.is_empty ())
241 	  status = EMPTY;
242       }
243     }
244   }
245 
246   status_t status;
247   hb_extents_t extents;
248 };
249 
250 struct hb_transform_decomposed_t
251 {
252   float translateX = 0;
253   float translateY = 0;
254   float rotation = 0;  // in degrees, counter-clockwise
255   float scaleX = 1;
256   float scaleY = 1;
257   float skewX = 0;  // in degrees, counter-clockwise
258   float skewY = 0;  // in degrees, counter-clockwise
259   float tCenterX = 0;
260   float tCenterY = 0;
261 
operator boolhb_transform_decomposed_t262   operator bool () const
263   {
264     return translateX || translateY ||
265 	   rotation ||
266 	   scaleX != 1 || scaleY != 1 ||
267 	   skewX || skewY ||
268 	   tCenterX || tCenterY;
269   }
270 
to_transformhb_transform_decomposed_t271   hb_transform_t to_transform () const
272   {
273     hb_transform_t t;
274     t.translate (translateX + tCenterX, translateY + tCenterY);
275     t.rotate (rotation);
276     t.scale (scaleX, scaleY);
277     t.skew (-skewX, skewY);
278     t.translate (-tCenterX, -tCenterY);
279     return t;
280   }
281 };
282 
283 
284 #endif /* HB_GEOMETRY_HH */
285