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