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