tor-browser

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

hb-outline.cc (8602B)


      1 /*
      2 * Copyright © 2023  Behdad Esfahbod
      3 * Copyright © 1999  David Turner
      4 * Copyright © 2005  Werner Lemberg
      5 * Copyright © 2013-2015  Alexei Podtelezhnikov
      6 *
      7 *  This is part of HarfBuzz, a text shaping library.
      8 *
      9 * Permission is hereby granted, without written agreement and without
     10 * license or royalty fees, to use, copy, modify, and distribute this
     11 * software and its documentation for any purpose, provided that the
     12 * above copyright notice and the following two paragraphs appear in
     13 * all copies of this software.
     14 *
     15 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     16 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     17 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     18 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     19 * DAMAGE.
     20 *
     21 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     22 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     23 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     24 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     25 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     26 */
     27 
     28 #include "hb.hh"
     29 
     30 #ifndef HB_NO_OUTLINE
     31 
     32 #include "hb-outline.hh"
     33 
     34 #include "hb-machinery.hh"
     35 
     36 
     37 void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
     38 {
     39  hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
     40 
     41  unsigned first = 0;
     42  for (unsigned contour : contours)
     43  {
     44    auto it = points.as_array ().sub_array (first, contour - first);
     45    while (it)
     46    {
     47      hb_outline_point_t p1 = *it++;
     48      switch (p1.type)
     49      {
     50 case hb_outline_point_t::type_t::MOVE_TO:
     51 {
     52   pen->move_to (pen_data, st,
     53 		   p1.x, p1.y);
     54 }
     55 break;
     56 case hb_outline_point_t::type_t::LINE_TO:
     57 {
     58   pen->line_to (pen_data, st,
     59 		   p1.x, p1.y);
     60 }
     61 break;
     62 case hb_outline_point_t::type_t::QUADRATIC_TO:
     63 {
     64   hb_outline_point_t p2 = *it++;
     65   pen->quadratic_to (pen_data, st,
     66 			p1.x, p1.y,
     67 			p2.x, p2.y);
     68 }
     69 break;
     70 case hb_outline_point_t::type_t::CUBIC_TO:
     71 {
     72   hb_outline_point_t p2 = *it++;
     73   hb_outline_point_t p3 = *it++;
     74   pen->cubic_to (pen_data, st,
     75 		    p1.x, p1.y,
     76 		    p2.x, p2.y,
     77 		    p3.x, p3.y);
     78 }
     79 break;
     80      }
     81    }
     82    pen->close_path (pen_data, st);
     83    first = contour;
     84  }
     85 }
     86 
     87 void hb_outline_t::translate (float dx, float dy)
     88 {
     89  for (auto &p : points)
     90  {
     91    p.x += dx;
     92    p.y += dy;
     93  }
     94 }
     95 
     96 void hb_outline_t::slant (float slant_xy)
     97 {
     98  for (auto &p : points)
     99    p.x += slant_xy * p.y;
    100 }
    101 
    102 float hb_outline_t::control_area () const
    103 {
    104  float a = 0;
    105  unsigned first = 0;
    106  for (unsigned contour : contours)
    107  {
    108    for (unsigned i = first; i < contour; i++)
    109    {
    110      unsigned j = i + 1 < contour ? i + 1 : first;
    111 
    112      auto &pi = points[i];
    113      auto &pj = points[j];
    114      a += pi.x * pj.y - pi.y * pj.x;
    115    }
    116 
    117    first = contour;
    118  }
    119  return a * .5f;
    120 }
    121 
    122 void hb_outline_t::embolden (float x_strength, float y_strength,
    123 		     float x_shift, float y_shift)
    124 {
    125  /* This function is a straight port of FreeType's FT_Outline_EmboldenXY.
    126   * Permission has been obtained from the FreeType authors of the code
    127   * to relicense it under the HarfBuzz license. */
    128 
    129  if (!x_strength && !y_strength) return;
    130  if (!points) return;
    131 
    132  x_strength /= 2.f;
    133  y_strength /= 2.f;
    134 
    135  bool orientation_negative = control_area () < 0;
    136 
    137  signed first = 0;
    138  for (unsigned c = 0; c < contours.length; c++)
    139  {
    140    hb_outline_vector_t in, out, anchor, shift;
    141    float l_in, l_out, l_anchor = 0, l, q, d;
    142 
    143    l_in = 0;
    144    signed last = (int) contours[c] - 1;
    145 
    146    /* pacify compiler */
    147    in.x = in.y = anchor.x = anchor.y = 0;
    148 
    149    /* Counter j cycles though the points; counter i advances only  */
    150    /* when points are moved; anchor k marks the first moved point. */
    151    for ( signed i = last, j = first, k = -1;
    152   j != i && i != k;
    153   j = j < last ? j + 1 : first )
    154    {
    155      if ( j != k )
    156      {
    157 out.x = points[j].x - points[i].x;
    158 out.y = points[j].y - points[i].y;
    159 l_out = out.normalize_len ();
    160 
    161 if ( l_out == 0 )
    162   continue;
    163      }
    164      else
    165      {
    166 out   = anchor;
    167 l_out = l_anchor;
    168      }
    169 
    170      if ( l_in != 0 )
    171      {
    172 if ( k < 0 )
    173 {
    174   k        = i;
    175   anchor   = in;
    176   l_anchor = l_in;
    177 }
    178 
    179 d = in.x * out.x + in.y * out.y;
    180 
    181 /* shift only if turn is less than ~160 degrees */
    182 if ( d > -15.f/16.f )
    183 {
    184   d = d + 1.f;
    185 
    186   /* shift components along lateral bisector in proper orientation */
    187   shift.x = in.y + out.y;
    188   shift.y = in.x + out.x;
    189 
    190   if ( orientation_negative )
    191     shift.x = -shift.x;
    192   else
    193     shift.y = -shift.y;
    194 
    195   /* restrict shift magnitude to better handle collapsing segments */
    196   q = out.x * in.y - out.y * in.x;
    197   if ( orientation_negative )
    198     q = -q;
    199 
    200   l = hb_min (l_in, l_out);
    201 
    202   /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
    203   if (x_strength * q <= l * d)
    204     shift.x = shift.x * x_strength / d;
    205   else
    206     shift.x = shift.x * l / q;
    207 
    208 
    209   if (y_strength * q <= l * d)
    210     shift.y = shift.y * y_strength / d;
    211   else
    212     shift.y = shift.y * l / q;
    213 }
    214 else
    215   shift.x = shift.y = 0;
    216 
    217 for ( ;
    218       i != j;
    219       i = i < last ? i + 1 : first )
    220 {
    221   points[i].x += x_shift + shift.x;
    222   points[i].y += y_shift + shift.y;
    223 }
    224      }
    225      else
    226 i = j;
    227 
    228      in   = out;
    229      l_in = l_out;
    230    }
    231 
    232    first = last + 1;
    233  }
    234 }
    235 
    236 static void
    237 hb_outline_recording_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
    238 			  void *data,
    239 			  hb_draw_state_t *st,
    240 			  float to_x, float to_y,
    241 			  void *user_data HB_UNUSED)
    242 {
    243  hb_outline_t *c = (hb_outline_t *) data;
    244 
    245  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::MOVE_TO});
    246 }
    247 
    248 static void
    249 hb_outline_recording_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
    250 			  void *data,
    251 			  hb_draw_state_t *st,
    252 			  float to_x, float to_y,
    253 			  void *user_data HB_UNUSED)
    254 {
    255  hb_outline_t *c = (hb_outline_t *) data;
    256 
    257  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::LINE_TO});
    258 }
    259 
    260 static void
    261 hb_outline_recording_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
    262 			       void *data,
    263 			       hb_draw_state_t *st,
    264 			       float control_x, float control_y,
    265 			       float to_x, float to_y,
    266 			       void *user_data HB_UNUSED)
    267 {
    268  hb_outline_t *c = (hb_outline_t *) data;
    269 
    270  c->points.push (hb_outline_point_t {control_x, control_y, hb_outline_point_t::type_t::QUADRATIC_TO});
    271  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::QUADRATIC_TO});
    272 }
    273 
    274 static void
    275 hb_outline_recording_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
    276 			   void *data,
    277 			   hb_draw_state_t *st,
    278 			   float control1_x, float control1_y,
    279 			   float control2_x, float control2_y,
    280 			   float to_x, float to_y,
    281 			   void *user_data HB_UNUSED)
    282 {
    283  hb_outline_t *c = (hb_outline_t *) data;
    284 
    285  c->points.push (hb_outline_point_t {control1_x, control1_y, hb_outline_point_t::type_t::CUBIC_TO});
    286  c->points.push (hb_outline_point_t {control2_x, control2_y, hb_outline_point_t::type_t::CUBIC_TO});
    287  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::CUBIC_TO});
    288 }
    289 
    290 static void
    291 hb_outline_recording_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
    292 			     void *data,
    293 			     hb_draw_state_t *st,
    294 			     void *user_data HB_UNUSED)
    295 {
    296  hb_outline_t *c = (hb_outline_t *) data;
    297 
    298  c->contours.push (c->points.length);
    299 }
    300 
    301 static inline void free_static_outline_recording_pen_funcs ();
    302 
    303 static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_outline_recording_pen_funcs_lazy_loader_t>
    304 {
    305  static hb_draw_funcs_t *create ()
    306  {
    307    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
    308 
    309    hb_draw_funcs_set_move_to_func (funcs, hb_outline_recording_pen_move_to, nullptr, nullptr);
    310    hb_draw_funcs_set_line_to_func (funcs, hb_outline_recording_pen_line_to, nullptr, nullptr);
    311    hb_draw_funcs_set_quadratic_to_func (funcs, hb_outline_recording_pen_quadratic_to, nullptr, nullptr);
    312    hb_draw_funcs_set_cubic_to_func (funcs, hb_outline_recording_pen_cubic_to, nullptr, nullptr);
    313    hb_draw_funcs_set_close_path_func (funcs, hb_outline_recording_pen_close_path, nullptr, nullptr);
    314 
    315    hb_draw_funcs_make_immutable (funcs);
    316 
    317    hb_atexit (free_static_outline_recording_pen_funcs);
    318 
    319    return funcs;
    320  }
    321 } static_outline_recording_pen_funcs;
    322 
    323 static inline
    324 void free_static_outline_recording_pen_funcs ()
    325 {
    326  static_outline_recording_pen_funcs.free_instance ();
    327 }
    328 
    329 hb_draw_funcs_t *
    330 hb_outline_recording_pen_get_funcs ()
    331 {
    332  return static_outline_recording_pen_funcs.get_unconst ();
    333 }
    334 
    335 
    336 #endif