/work/workdir/UnpackedTarball/harfbuzz/src/hb-geometry.hh
Line | Count | Source (jump to first uncovered line) |
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 | | { |
32 | 0 | hb_extents_t () {} |
33 | | hb_extents_t (const hb_glyph_extents_t &extents) : |
34 | | xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)), |
35 | | ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)), |
36 | | xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)), |
37 | 0 | ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {} |
38 | | hb_extents_t (float xmin, float ymin, float xmax, float ymax) : |
39 | 0 | xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {} |
40 | | |
41 | 0 | bool is_empty () const { return xmin >= xmax || ymin >= ymax; } |
42 | 0 | bool is_void () const { return xmin > xmax; } |
43 | | |
44 | | void union_ (const hb_extents_t &o) |
45 | 0 | { |
46 | 0 | if (o.is_empty ()) return; |
47 | 0 | if (is_empty ()) |
48 | 0 | { |
49 | 0 | *this = o; |
50 | 0 | return; |
51 | 0 | } |
52 | 0 | xmin = hb_min (xmin, o.xmin); |
53 | 0 | ymin = hb_min (ymin, o.ymin); |
54 | 0 | xmax = hb_max (xmax, o.xmax); |
55 | 0 | ymax = hb_max (ymax, o.ymax); |
56 | 0 | } |
57 | | |
58 | | void intersect (const hb_extents_t &o) |
59 | 0 | { |
60 | 0 | if (o.is_empty () || is_empty ()) |
61 | 0 | { |
62 | 0 | *this = hb_extents_t {}; |
63 | 0 | return; |
64 | 0 | } |
65 | 0 | xmin = hb_max (xmin, o.xmin); |
66 | 0 | ymin = hb_max (ymin, o.ymin); |
67 | 0 | xmax = hb_min (xmax, o.xmax); |
68 | 0 | ymax = hb_min (ymax, o.ymax); |
69 | 0 | } |
70 | | |
71 | | void |
72 | | add_point (float x, float y) |
73 | 0 | { |
74 | 0 | if (unlikely (is_void ())) |
75 | 0 | { |
76 | 0 | xmin = xmax = x; |
77 | 0 | ymin = ymax = y; |
78 | 0 | } |
79 | 0 | else |
80 | 0 | { |
81 | 0 | xmin = hb_min (xmin, x); |
82 | 0 | ymin = hb_min (ymin, y); |
83 | 0 | xmax = hb_max (xmax, x); |
84 | 0 | ymax = hb_max (ymax, y); |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const |
89 | 0 | { |
90 | 0 | hb_position_t x0 = (hb_position_t) roundf (xmin); |
91 | 0 | hb_position_t y0 = (hb_position_t) roundf (ymin); |
92 | 0 | hb_position_t x1 = (hb_position_t) roundf (xmax); |
93 | 0 | hb_position_t y1 = (hb_position_t) roundf (ymax); |
94 | 0 | return hb_glyph_extents_t {xneg ? x1 : x0, |
95 | 0 | yneg ? y0 : y1, |
96 | 0 | xneg ? x0 - x1 : x1 - x0, |
97 | 0 | yneg ? y1 - y0 : y0 - y1}; |
98 | 0 | } |
99 | | |
100 | | float xmin = 0.f; |
101 | | float ymin = 0.f; |
102 | | float xmax = -1.f; |
103 | | float ymax = -1.f; |
104 | | }; |
105 | | |
106 | | struct hb_transform_t |
107 | | { |
108 | 0 | hb_transform_t () {} |
109 | | hb_transform_t (float xx, float yx, |
110 | | float xy, float yy, |
111 | | float x0, float y0) : |
112 | 0 | xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {} |
113 | | |
114 | | bool is_identity () const |
115 | 0 | { |
116 | 0 | return xx == 1.f && yx == 0.f && |
117 | 0 | xy == 0.f && yy == 1.f && |
118 | 0 | x0 == 0.f && y0 == 0.f; |
119 | 0 | } |
120 | | |
121 | | void multiply (const hb_transform_t &o) |
122 | 0 | { |
123 | | /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */ |
124 | 0 | hb_transform_t r; |
125 | |
|
126 | 0 | r.xx = o.xx * xx + o.yx * xy; |
127 | 0 | r.yx = o.xx * yx + o.yx * yy; |
128 | |
|
129 | 0 | r.xy = o.xy * xx + o.yy * xy; |
130 | 0 | r.yy = o.xy * yx + o.yy * yy; |
131 | |
|
132 | 0 | r.x0 = o.x0 * xx + o.y0 * xy + x0; |
133 | 0 | r.y0 = o.x0 * yx + o.y0 * yy + y0; |
134 | |
|
135 | 0 | *this = r; |
136 | 0 | } |
137 | | |
138 | | void transform_distance (float &dx, float &dy) const |
139 | 0 | { |
140 | 0 | float new_x = xx * dx + xy * dy; |
141 | 0 | float new_y = yx * dx + yy * dy; |
142 | 0 | dx = new_x; |
143 | 0 | dy = new_y; |
144 | 0 | } |
145 | | |
146 | | void transform_point (float &x, float &y) const |
147 | 0 | { |
148 | 0 | transform_distance (x, y); |
149 | 0 | x += x0; |
150 | 0 | y += y0; |
151 | 0 | } |
152 | | |
153 | | void transform_extents (hb_extents_t &extents) const |
154 | 0 | { |
155 | 0 | float quad_x[4], quad_y[4]; |
156 | |
|
157 | 0 | quad_x[0] = extents.xmin; |
158 | 0 | quad_y[0] = extents.ymin; |
159 | 0 | quad_x[1] = extents.xmin; |
160 | 0 | quad_y[1] = extents.ymax; |
161 | 0 | quad_x[2] = extents.xmax; |
162 | 0 | quad_y[2] = extents.ymin; |
163 | 0 | quad_x[3] = extents.xmax; |
164 | 0 | quad_y[3] = extents.ymax; |
165 | |
|
166 | 0 | extents = hb_extents_t {}; |
167 | 0 | for (unsigned i = 0; i < 4; i++) |
168 | 0 | { |
169 | 0 | transform_point (quad_x[i], quad_y[i]); |
170 | 0 | extents.add_point (quad_x[i], quad_y[i]); |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | 0 | void transform (const hb_transform_t &o) { multiply (o); } |
175 | | |
176 | | void translate (float x, float y) |
177 | 0 | { |
178 | 0 | if (x == 0.f && y == 0.f) |
179 | 0 | return; |
180 | 0 |
|
181 | 0 | x0 += xx * x + xy * y; |
182 | 0 | y0 += yx * x + yy * y; |
183 | 0 | } |
184 | | |
185 | | void scale (float scaleX, float scaleY) |
186 | 0 | { |
187 | 0 | if (scaleX == 1.f && scaleY == 1.f) |
188 | 0 | return; |
189 | 0 |
|
190 | 0 | xx *= scaleX; |
191 | 0 | yx *= scaleX; |
192 | 0 | xy *= scaleY; |
193 | 0 | yy *= scaleY; |
194 | 0 | } |
195 | | |
196 | | void rotate (float rotation) |
197 | 0 | { |
198 | 0 | if (rotation == 0.f) |
199 | 0 | return; |
200 | 0 |
|
201 | 0 | // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 |
202 | 0 | rotation = rotation * HB_PI; |
203 | 0 | float c; |
204 | 0 | float s; |
205 | 0 | #ifdef HAVE_SINCOSF |
206 | 0 | sincosf (rotation, &s, &c); |
207 | 0 | #else |
208 | 0 | c = cosf (rotation); |
209 | 0 | s = sinf (rotation); |
210 | 0 | #endif |
211 | 0 | auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f}; |
212 | 0 | transform (other); |
213 | 0 | } |
214 | | |
215 | | void skew (float skewX, float skewY) |
216 | 0 | { |
217 | 0 | if (skewX == 0.f && skewY == 0.f) |
218 | 0 | return; |
219 | 0 |
|
220 | 0 | // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 |
221 | 0 | skewX = skewX * HB_PI; |
222 | 0 | skewY = skewY * HB_PI; |
223 | 0 | auto other = hb_transform_t{1.f, |
224 | 0 | skewY ? tanf (skewY) : 0.f, |
225 | 0 | skewX ? tanf (skewX) : 0.f, |
226 | 0 | 1.f, |
227 | 0 | 0.f, 0.f}; |
228 | 0 | transform (other); |
229 | 0 | } |
230 | | |
231 | | float xx = 1.f; |
232 | | float yx = 0.f; |
233 | | float xy = 0.f; |
234 | | float yy = 1.f; |
235 | | float x0 = 0.f; |
236 | | float y0 = 0.f; |
237 | | }; |
238 | | |
239 | | #define HB_TRANSFORM_IDENTITY hb_transform_t{1.f, 0.f, 0.f, 1.f, 0.f, 0.f} |
240 | | |
241 | | struct hb_bounds_t |
242 | | { |
243 | | enum status_t { |
244 | | UNBOUNDED, |
245 | | BOUNDED, |
246 | | EMPTY, |
247 | | }; |
248 | | |
249 | 0 | hb_bounds_t (status_t status = UNBOUNDED) : status (status) {} |
250 | | hb_bounds_t (const hb_extents_t &extents) : |
251 | 0 | status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {} |
252 | | |
253 | | void union_ (const hb_bounds_t &o) |
254 | 0 | { |
255 | 0 | if (o.status == UNBOUNDED) |
256 | 0 | status = UNBOUNDED; |
257 | 0 | else if (o.status == BOUNDED) |
258 | 0 | { |
259 | 0 | if (status == EMPTY) |
260 | 0 | *this = o; |
261 | 0 | else if (status == BOUNDED) |
262 | 0 | extents.union_ (o.extents); |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | void intersect (const hb_bounds_t &o) |
267 | 0 | { |
268 | 0 | if (o.status == EMPTY) |
269 | 0 | status = EMPTY; |
270 | 0 | else if (o.status == BOUNDED) |
271 | 0 | { |
272 | 0 | if (status == UNBOUNDED) |
273 | 0 | *this = o; |
274 | 0 | else if (status == BOUNDED) |
275 | 0 | { |
276 | 0 | extents.intersect (o.extents); |
277 | 0 | if (extents.is_empty ()) |
278 | 0 | status = EMPTY; |
279 | 0 | } |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | | status_t status; |
284 | | hb_extents_t extents; |
285 | | }; |
286 | | |
287 | | struct hb_transform_decomposed_t |
288 | | { |
289 | | float translateX = 0; |
290 | | float translateY = 0; |
291 | | float rotation = 0; // in degrees, counter-clockwise |
292 | | float scaleX = 1; |
293 | | float scaleY = 1; |
294 | | float skewX = 0; // in degrees, counter-clockwise |
295 | | float skewY = 0; // in degrees, counter-clockwise |
296 | | float tCenterX = 0; |
297 | | float tCenterY = 0; |
298 | | |
299 | | operator bool () const |
300 | 0 | { |
301 | 0 | return translateX || translateY || |
302 | 0 | rotation || |
303 | 0 | scaleX != 1 || scaleY != 1 || |
304 | 0 | skewX || skewY || |
305 | 0 | tCenterX || tCenterY; |
306 | 0 | } |
307 | | |
308 | | hb_transform_t to_transform () const |
309 | 0 | { |
310 | 0 | hb_transform_t t; |
311 | 0 | t.translate (translateX + tCenterX, translateY + tCenterY); |
312 | 0 | t.rotate (rotation); |
313 | 0 | t.scale (scaleX, scaleY); |
314 | 0 | t.skew (-skewX, skewY); |
315 | 0 | t.translate (-tCenterX, -tCenterY); |
316 | 0 | return t; |
317 | 0 | } |
318 | | }; |
319 | | |
320 | | |
321 | | #endif /* HB_GEOMETRY_HH */ |