tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-geometry.hh (9804B)


      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 #include "hb-algs.hh"
     30 
     31 
     32 template <typename Float = float>
     33 struct hb_extents_t
     34 {
     35  hb_extents_t () {}
     36  hb_extents_t (const hb_glyph_extents_t &extents) :
     37 	xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)),
     38 	ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)),
     39 	xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)),
     40 	ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {}
     41  hb_extents_t (Float xmin, Float ymin, Float xmax, Float ymax) :
     42    xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
     43 
     44  bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
     45  bool is_void () const { return xmin > xmax; }
     46 
     47  void union_ (const hb_extents_t &o)
     48  {
     49    if (o.is_empty ()) return;
     50    if (is_empty ())
     51    {
     52      *this = o;
     53      return;
     54    }
     55    xmin = hb_min (xmin, o.xmin);
     56    ymin = hb_min (ymin, o.ymin);
     57    xmax = hb_max (xmax, o.xmax);
     58    ymax = hb_max (ymax, o.ymax);
     59  }
     60 
     61  void intersect (const hb_extents_t &o)
     62  {
     63    if (o.is_empty () || is_empty ())
     64    {
     65      *this = hb_extents_t {};
     66      return;
     67    }
     68    xmin = hb_max (xmin, o.xmin);
     69    ymin = hb_max (ymin, o.ymin);
     70    xmax = hb_min (xmax, o.xmax);
     71    ymax = hb_min (ymax, o.ymax);
     72  }
     73 
     74  void
     75  add_point (Float x, Float y)
     76  {
     77    if (unlikely (is_void ()))
     78    {
     79      xmin = xmax = x;
     80      ymin = ymax = y;
     81    }
     82    else
     83    {
     84      xmin = hb_min (xmin, x);
     85      ymin = hb_min (ymin, y);
     86      xmax = hb_max (xmax, x);
     87      ymax = hb_max (ymax, y);
     88    }
     89  }
     90 
     91  hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const
     92  {
     93    hb_position_t x0 = (hb_position_t) roundf (xmin);
     94    hb_position_t y0 = (hb_position_t) roundf (ymin);
     95    hb_position_t x1 = (hb_position_t) roundf (xmax);
     96    hb_position_t y1 = (hb_position_t) roundf (ymax);
     97    return hb_glyph_extents_t {xneg ? x1 : x0,
     98 		       yneg ? y0 : y1,
     99 		       xneg ? x0 - x1 : x1 - x0,
    100 		       yneg ? y1 - y0 : y0 - y1};
    101  }
    102 
    103  Float xmin = 0;
    104  Float ymin = 0;
    105  Float xmax = -1;
    106  Float ymax = -1;
    107 };
    108 
    109 template <typename Float = float>
    110 struct hb_transform_t
    111 {
    112  hb_transform_t () {}
    113  hb_transform_t (Float xx, Float yx,
    114 	  Float xy, Float yy,
    115 	  Float x0, Float y0) :
    116    xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
    117 
    118  bool is_identity () const
    119  {
    120    return xx == 1 && yx == 0 &&
    121    xy == 0 && yy == 1 &&
    122    x0 == 0 && y0 == 0;
    123  }
    124  bool is_translation () const
    125  {
    126    return xx == 1 && yx == 0 &&
    127    xy == 0 && yy == 1;
    128  }
    129 
    130  void multiply (const hb_transform_t &o, bool before=false)
    131  {
    132    // Copied from cairo-matrix.c
    133    const hb_transform_t &a = before ? o : *this;
    134    const hb_transform_t &b = before ? *this : o;
    135    *this = {
    136      a.xx * b.xx + a.xy * b.yx,
    137      a.yx * b.xx + a.yy * b.yx,
    138      a.xx * b.xy + a.xy * b.yy,
    139      a.yx * b.xy + a.yy * b.yy,
    140      a.xx * b.x0 + a.xy * b.y0 + a.x0,
    141      a.yx * b.x0 + a.yy * b.y0 + a.y0
    142    };
    143  }
    144 
    145  HB_ALWAYS_INLINE
    146  void transform_distance (Float &dx, Float &dy) const
    147  {
    148    Float new_x = xx * dx + xy * dy;
    149    Float new_y = yx * dx + yy * dy;
    150    dx = new_x;
    151    dy = new_y;
    152  }
    153 
    154  HB_ALWAYS_INLINE
    155  void transform_point (Float &x, Float &y) const
    156  {
    157    Float new_x = x0 + xx * x + xy * y;
    158    Float new_y = y0 + yx * x + yy * y;
    159    x = new_x;
    160    y = new_y;
    161  }
    162 
    163  void transform_extents (hb_extents_t<Float> &extents) const
    164  {
    165    Float quad_x[4], quad_y[4];
    166 
    167    quad_x[0] = extents.xmin;
    168    quad_y[0] = extents.ymin;
    169    quad_x[1] = extents.xmin;
    170    quad_y[1] = extents.ymax;
    171    quad_x[2] = extents.xmax;
    172    quad_y[2] = extents.ymin;
    173    quad_x[3] = extents.xmax;
    174    quad_y[3] = extents.ymax;
    175 
    176    extents = hb_extents_t<Float> {};
    177    for (unsigned i = 0; i < 4; i++)
    178    {
    179      transform_point (quad_x[i], quad_y[i]);
    180      extents.add_point (quad_x[i], quad_y[i]);
    181    }
    182  }
    183 
    184  void transform (const hb_transform_t &o, bool before=false) { multiply (o, before); }
    185 
    186  static hb_transform_t translation (Float x, Float y)
    187  {
    188    return {1, 0, 0, 1, x, y};
    189  }
    190  void translate (Float x, Float y, bool before=false)
    191  {
    192    if (before)
    193    {
    194      x0 += x;
    195      y0 += y;
    196    }
    197    else
    198    {
    199      if (x == 0 && y == 0)
    200 return;
    201 
    202      x0 += xx * x + xy * y;
    203      y0 += yx * x + yy * y;
    204    }
    205  }
    206 
    207  static hb_transform_t scaling (Float scaleX, Float scaleY)
    208  {
    209    return {scaleX, 0, 0, scaleY, 0, 0};
    210  }
    211  void scale (Float scaleX, Float scaleY)
    212  {
    213    if (scaleX == 1 && scaleY == 1)
    214      return;
    215 
    216    xx *= scaleX;
    217    yx *= scaleX;
    218    xy *= scaleY;
    219    yy *= scaleY;
    220  }
    221  static hb_transform_t scaling_around_center (Float scaleX, Float scaleY, Float center_x, Float center_y)
    222  {
    223    return {scaleX, 0, 0, scaleY,
    224     center_x ? (1 - scaleX) * center_x : 0,
    225     center_y ? (1 - scaleY) * center_y : 0};
    226  }
    227  void scale_around_center (Float scaleX, Float scaleY, Float center_x, Float center_y)
    228  {
    229    if (scaleX == 1 && scaleY == 1)
    230      return;
    231 
    232    transform (scaling_around_center (scaleX, scaleY, center_x, center_y));
    233  }
    234 
    235  static hb_transform_t rotation (Float radians)
    236  {
    237    // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
    238    Float c;
    239    Float s;
    240    hb_sincos (radians, s, c);
    241    return {c, s, -s, c, 0, 0};
    242  }
    243  void rotate (Float radians, bool before=false)
    244  {
    245    if (radians == 0)
    246      return;
    247 
    248    transform (rotation (radians), before);
    249  }
    250 
    251  static hb_transform_t rotation_around_center (Float radians, Float center_x, Float center_y)
    252  {
    253    Float s, c;
    254    hb_sincos (radians, s, c);
    255    return {
    256      c, s, -s, c,
    257      (1 - c) * center_x + s * center_y,
    258      -s * center_x +  (1 - c) * center_y
    259    };
    260  }
    261  void rotate_around_center (Float radians, Float center_x, Float center_y, bool before=false)
    262  {
    263    if (radians == 0)
    264      return;
    265 
    266    transform (rotation_around_center (radians, center_x, center_y), before);
    267  }
    268 
    269  static hb_transform_t skewing (Float skewX, Float skewY)
    270  {
    271    return {1, skewY ? tanf (skewY) : 0, skewX ? tanf (skewX) : 0, 1, 0, 0};
    272  }
    273  void skew (Float skewX, Float skewY)
    274  {
    275    if (skewX == 0 && skewY == 0)
    276      return;
    277 
    278    transform (skewing (skewX, skewY));
    279  }
    280  static hb_transform_t skewing_around_center (Float skewX, Float skewY, Float center_x, Float center_y)
    281  {
    282    skewX = skewX ? tanf (skewX) : 0;
    283    skewY = skewY ? tanf (skewY) : 0;
    284    return {
    285     1, skewY, skewX, 1,
    286     center_y ? -skewX * center_y : 0,
    287     center_x ? -skewY * center_x : 0
    288    };
    289  }
    290  void skew_around_center (Float skewX, Float skewY, Float center_x, Float center_y)
    291  {
    292    if (skewX == 0 && skewY == 0)
    293     return;
    294 
    295    transform (skewing_around_center (skewX, skewY, center_x, center_y));
    296  }
    297 
    298  Float xx = 1;
    299  Float yx = 0;
    300  Float xy = 0;
    301  Float yy = 1;
    302  Float x0 = 0;
    303  Float y0 = 0;
    304 };
    305 
    306 #define HB_TRANSFORM_IDENTITY {1, 0, 0, 1, 0, 0}
    307 
    308 template <typename Float = float>
    309 struct hb_bounds_t
    310 {
    311  enum status_t {
    312    UNBOUNDED,
    313    BOUNDED,
    314    EMPTY,
    315  };
    316 
    317  hb_bounds_t (status_t status = UNBOUNDED) : status (status) {}
    318  hb_bounds_t (const hb_extents_t<Float> &extents) :
    319    status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
    320 
    321  void union_ (const hb_bounds_t &o)
    322  {
    323    if (o.status == UNBOUNDED)
    324      status = UNBOUNDED;
    325    else if (o.status == BOUNDED)
    326    {
    327      if (status == EMPTY)
    328 *this = o;
    329      else if (status == BOUNDED)
    330        extents.union_ (o.extents);
    331    }
    332  }
    333 
    334  void intersect (const hb_bounds_t &o)
    335  {
    336    if (o.status == EMPTY)
    337      status = EMPTY;
    338    else if (o.status == BOUNDED)
    339    {
    340      if (status == UNBOUNDED)
    341 *this = o;
    342      else if (status == BOUNDED)
    343      {
    344        extents.intersect (o.extents);
    345 if (extents.is_empty ())
    346   status = EMPTY;
    347      }
    348    }
    349  }
    350 
    351  status_t status;
    352  hb_extents_t<Float> extents;
    353 };
    354 
    355 template <typename Float = float>
    356 struct hb_transform_decomposed_t
    357 {
    358  Float translateX = 0;
    359  Float translateY = 0;
    360  Float rotation = 0;  // in radians, counter-clockwise
    361  Float scaleX = 1;
    362  Float scaleY = 1;
    363  Float skewX = 0;  // in radians, counter-clockwise
    364  Float skewY = 0;  // in radians, counter-clockwise
    365  Float tCenterX = 0;
    366  Float tCenterY = 0;
    367 
    368  operator bool () const
    369  {
    370    return translateX || translateY ||
    371    rotation ||
    372    scaleX != 1 || scaleY != 1 ||
    373    skewX || skewY ||
    374    tCenterX || tCenterY;
    375  }
    376 
    377  hb_transform_t<Float> to_transform () const
    378  {
    379    hb_transform_t<Float> t;
    380    t.translate (translateX + tCenterX, translateY + tCenterY);
    381    t.rotate (rotation);
    382    t.scale (scaleX, scaleY);
    383    t.skew (-skewX, skewY);
    384    t.translate (-tCenterX, -tCenterY);
    385    return t;
    386  }
    387 };
    388 
    389 
    390 #endif /* HB_GEOMETRY_HH */