tor-browser

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

hb-ot-metrics.cc (15524B)


      1 /*
      2 * Copyright © 2018-2019  Ebrahim Byagowi
      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 
     25 #include "hb.hh"
     26 
     27 #include "hb-ot-var-mvar-table.hh"
     28 #include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
     29 #include "hb-ot-os2-table.hh"
     30 #include "hb-ot-post-table.hh"
     31 #include "hb-ot-hhea-table.hh"
     32 #include "hb-ot-metrics.hh"
     33 #include "hb-ot-face.hh"
     34 
     35 
     36 /**
     37 * SECTION:hb-ot-metrics
     38 * @title: hb-ot-metrics
     39 * @short_description: OpenType Metrics
     40 * @include: hb-ot.h
     41 *
     42 * Functions for fetching metrics from fonts.
     43 **/
     44 
     45 static float
     46 _fix_ascender_descender (float value, hb_ot_metrics_tag_t metrics_tag)
     47 {
     48  if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER ||
     49      metrics_tag == HB_OT_METRICS_TAG_VERTICAL_ASCENDER)
     50    return fabs ((double) value);
     51  if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER ||
     52      metrics_tag == HB_OT_METRICS_TAG_VERTICAL_DESCENDER)
     53    return -fabs ((double) value);
     54  return value;
     55 }
     56 
     57 /* The common part of _get_position logic needed on hb-ot-font and here
     58   to be able to have slim builds without the not always needed parts */
     59 bool
     60 _hb_ot_metrics_get_position_common (hb_font_t           *font,
     61 			    hb_ot_metrics_tag_t  metrics_tag,
     62 			    hb_position_t       *position     /* OUT.  May be NULL. */)
     63 {
     64  hb_face_t *face = font->face;
     65  switch ((unsigned) metrics_tag)
     66  {
     67 #ifndef HB_NO_VAR
     68 #define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords)
     69 #else
     70 #define GET_VAR .0f
     71 #endif
     72 #define GET_METRIC_X(TABLE, ATTR) \
     73  (face->table.TABLE->has_data () && \
     74    ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
     75      face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
     76 #define GET_METRIC_Y(TABLE, ATTR) \
     77  (face->table.TABLE->has_data () && \
     78    ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
     79      face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
     80 
     81  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
     82    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
     83    GET_METRIC_Y (hhea, ascender);
     84  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
     85    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoDescender)) ||
     86    GET_METRIC_Y (hhea, descender);
     87  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
     88    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) ||
     89    GET_METRIC_Y (hhea, lineGap);
     90 
     91 #ifndef HB_NO_VERTICAL
     92  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:  return GET_METRIC_X (vhea, ascender);
     93  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender);
     94  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:  return GET_METRIC_X (vhea, lineGap);
     95 #endif
     96 
     97 #undef GET_METRIC_Y
     98 #undef GET_METRIC_X
     99 #undef GET_VAR
    100  default:                               assert (0); return false;
    101  }
    102 }
    103 
    104 #ifndef HB_NO_METRICS
    105 
    106 #if 0
    107 static bool
    108 _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag)
    109 {
    110  const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0'));
    111  if (&range == &Null (OT::GaspRange)) return false;
    112  if (result) *result = range.rangeMaxPPEM + font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords);
    113  return true;
    114 }
    115 #endif
    116 
    117 /* Private tags for https://github.com/harfbuzz/harfbuzz/issues/1866 */
    118 #define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2   HB_TAG ('O','a','s','c')
    119 #define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA  HB_TAG ('H','a','s','c')
    120 #define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2  HB_TAG ('O','d','s','c')
    121 #define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA HB_TAG ('H','d','s','c')
    122 #define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2   HB_TAG ('O','l','g','p')
    123 #define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA  HB_TAG ('H','l','g','p')
    124 
    125 /**
    126 * hb_ot_metrics_get_position:
    127 * @font: an #hb_font_t object.
    128 * @metrics_tag: tag of metrics value you like to fetch.
    129 * @position: (out) (optional): result of metrics value from the font.
    130 *
    131 * Fetches metrics value corresponding to @metrics_tag from @font.
    132 *
    133 * Returns: Whether found the requested metrics in the font.
    134 * Since: 2.6.0
    135 **/
    136 hb_bool_t
    137 hb_ot_metrics_get_position (hb_font_t           *font,
    138 		    hb_ot_metrics_tag_t  metrics_tag,
    139 		    hb_position_t       *position     /* OUT.  May be NULL. */)
    140 {
    141  hb_face_t *face = font->face;
    142  switch ((unsigned) metrics_tag)
    143  {
    144  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
    145  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
    146  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
    147  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
    148  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
    149  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:           return _hb_ot_metrics_get_position_common (font, metrics_tag, position);
    150 #ifndef HB_NO_VAR
    151 #define GET_VAR hb_ot_metrics_get_variation (font, metrics_tag)
    152 #else
    153 #define GET_VAR 0
    154 #endif
    155 #define GET_METRIC_X(TABLE, ATTR) \
    156  (face->table.TABLE->has_data () && \
    157    ((void) (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR))), true))
    158 #define GET_METRIC_Y(TABLE, ATTR) \
    159  (face->table.TABLE->has_data () && \
    160    ((void) (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR))), true))
    161  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:  return GET_METRIC_Y (OS2, usWinAscent);
    162  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent);
    163 
    164  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
    165  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
    166  {
    167    unsigned mult = 1u;
    168 
    169    if (font->slant)
    170    {
    171      unsigned rise = face->table.hhea->caretSlopeRise;
    172      unsigned upem = face->get_upem ();
    173      mult = (rise && rise < upem) ? hb_min (upem / rise, 256u) : 1u;
    174    }
    175 
    176    if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE)
    177    {
    178      bool ret = GET_METRIC_Y (hhea, caretSlopeRise);
    179 
    180      if (position)
    181 *position *= mult;
    182 
    183      return ret;
    184    }
    185    else
    186    {
    187      hb_position_t rise = 0;
    188 
    189      if (font->slant && position && GET_METRIC_Y (hhea, caretSlopeRise))
    190 rise = *position;
    191 
    192      bool ret = GET_METRIC_X (hhea, caretSlopeRun);
    193 
    194      if (position)
    195      {
    196 *position *= mult;
    197 
    198 if (font->slant)
    199   *position += roundf (mult * font->slant_xy * rise);
    200      }
    201 
    202      return ret;
    203    }
    204  }
    205  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:     return GET_METRIC_X (hhea, caretOffset);
    206 
    207 #ifndef HB_NO_VERTICAL
    208  case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:         return GET_METRIC_X (vhea, caretSlopeRise);
    209  case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:          return GET_METRIC_Y (vhea, caretSlopeRun);
    210  case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:       return GET_METRIC_Y (vhea, caretOffset);
    211 #endif
    212  case HB_OT_METRICS_TAG_X_HEIGHT:                    return GET_METRIC_Y (OS2->v2 (), sxHeight);
    213  case HB_OT_METRICS_TAG_CAP_HEIGHT:                  return GET_METRIC_Y (OS2->v2 (), sCapHeight);
    214  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:         return GET_METRIC_X (OS2, ySubscriptXSize);
    215  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:         return GET_METRIC_Y (OS2, ySubscriptYSize);
    216  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:       return GET_METRIC_X (OS2, ySubscriptXOffset);
    217  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:       return GET_METRIC_Y (OS2, ySubscriptYOffset);
    218  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:       return GET_METRIC_X (OS2, ySuperscriptXSize);
    219  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:       return GET_METRIC_Y (OS2, ySuperscriptYSize);
    220  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:     return GET_METRIC_X (OS2, ySuperscriptXOffset);
    221  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:     return GET_METRIC_Y (OS2, ySuperscriptYOffset);
    222  case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:              return GET_METRIC_Y (OS2, yStrikeoutSize);
    223  case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:            return GET_METRIC_Y (OS2, yStrikeoutPosition);
    224  case HB_OT_METRICS_TAG_UNDERLINE_SIZE:              return GET_METRIC_Y (post->table, underlineThickness);
    225  case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:            return GET_METRIC_Y (post->table, underlinePosition);
    226 
    227  /* Private tags */
    228  case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2:    return GET_METRIC_Y (OS2, sTypoAscender);
    229  case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA:   return GET_METRIC_Y (hhea, ascender);
    230  case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2:   return GET_METRIC_Y (OS2, sTypoDescender);
    231  case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA:  return GET_METRIC_Y (hhea, descender);
    232  case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2:    return GET_METRIC_Y (OS2, sTypoLineGap);
    233  case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA:   return GET_METRIC_Y (hhea, lineGap);
    234 #undef GET_METRIC_Y
    235 #undef GET_METRIC_X
    236 #undef GET_VAR
    237  default:                                        return false;
    238  }
    239 }
    240 
    241 /**
    242 * hb_ot_metrics_get_position_with_fallback:
    243 * @font: an #hb_font_t object.
    244 * @metrics_tag: tag of metrics value you like to fetch.
    245 * @position: (out) (optional): result of metrics value from the font.
    246 *
    247 * Fetches metrics value corresponding to @metrics_tag from @font,
    248 * and synthesizes a value if it the value is missing in the font.
    249 *
    250 * Since: 4.0.0
    251 **/
    252 void
    253 hb_ot_metrics_get_position_with_fallback (hb_font_t           *font,
    254 				  hb_ot_metrics_tag_t  metrics_tag,
    255 				  hb_position_t       *position     /* OUT */)
    256 {
    257  hb_font_extents_t font_extents;
    258  hb_codepoint_t glyph;
    259  hb_glyph_extents_t extents;
    260 
    261  if (hb_ot_metrics_get_position (font, metrics_tag, position))
    262    {
    263      if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE &&
    264           metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) ||
    265          *position != 0)
    266        return;
    267    }
    268 
    269  switch (metrics_tag)
    270  {
    271  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
    272  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:
    273    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
    274    *position = font_extents.ascender;
    275    break;
    276 
    277  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
    278    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
    279    *position = font_extents.ascender;
    280    break;
    281 
    282  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
    283  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT:
    284    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
    285    *position = font_extents.descender;
    286    break;
    287 
    288  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
    289    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
    290    *position = font_extents.ascender;
    291    break;
    292 
    293  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
    294    hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
    295    *position = font_extents.line_gap;
    296    break;
    297 
    298  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:
    299    hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents);
    300    *position = font_extents.line_gap;
    301    break;
    302 
    303  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:
    304  case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:
    305    *position = 1;
    306    break;
    307 
    308  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:
    309  case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:
    310    *position = 0;
    311    break;
    312 
    313  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:
    314  case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:
    315    *position = 0;
    316    break;
    317 
    318  case HB_OT_METRICS_TAG_X_HEIGHT:
    319    if (hb_font_get_nominal_glyph (font, 'x', &glyph) &&
    320        hb_font_get_glyph_extents (font, glyph, &extents))
    321      *position = extents.y_bearing;
    322    else
    323      *position = font->y_scale / 2;
    324    break;
    325 
    326  case HB_OT_METRICS_TAG_CAP_HEIGHT:
    327    if (hb_font_get_nominal_glyph (font, 'O', &glyph) &&
    328        hb_font_get_glyph_extents (font, glyph, &extents))
    329      *position = extents.height + 2 * extents.y_bearing;
    330    else
    331      *position = font->y_scale * 2 / 3;
    332    break;
    333 
    334  case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:
    335  case HB_OT_METRICS_TAG_UNDERLINE_SIZE:
    336    *position = font->y_scale / 18;
    337    break;
    338 
    339  case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:
    340    {
    341      hb_position_t ascender;
    342      hb_ot_metrics_get_position_with_fallback (font,
    343                                                HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
    344                                                &ascender);
    345      *position = ascender / 2;
    346    }
    347    break;
    348 
    349  case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:
    350    *position = - font->y_scale / 18;
    351    break;
    352 
    353  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:
    354  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:
    355    *position = font->x_scale * 10 / 12;
    356    break;
    357 
    358  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:
    359  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:
    360    *position = font->y_scale * 10 / 12;
    361    break;
    362 
    363  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:
    364  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:
    365    *position = 0;
    366    break;
    367 
    368  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:
    369  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:
    370    *position = font->y_scale / 5;
    371    break;
    372 
    373  case _HB_OT_METRICS_TAG_MAX_VALUE:
    374  default:
    375    *position = 0;
    376    break;
    377  }
    378 }
    379 
    380 #ifndef HB_NO_VAR
    381 /**
    382 * hb_ot_metrics_get_variation:
    383 * @font: an #hb_font_t object.
    384 * @metrics_tag: tag of metrics value you like to fetch.
    385 *
    386 * Fetches metrics value corresponding to @metrics_tag from @font with the
    387 * current font variation settings applied.
    388 *
    389 * Returns: The requested metric value.
    390 *
    391 * Since: 2.6.0
    392 **/
    393 float
    394 hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
    395 {
    396  return font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords);
    397 }
    398 
    399 /**
    400 * hb_ot_metrics_get_x_variation:
    401 * @font: an #hb_font_t object.
    402 * @metrics_tag: tag of metrics value you like to fetch.
    403 *
    404 * Fetches horizontal metrics value corresponding to @metrics_tag from @font
    405 * with the current font variation settings applied.
    406 *
    407 * Returns: The requested metric value.
    408 *
    409 * Since: 2.6.0
    410 **/
    411 hb_position_t
    412 hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
    413 {
    414  return font->em_scalef_x (hb_ot_metrics_get_variation (font, metrics_tag));
    415 }
    416 
    417 /**
    418 * hb_ot_metrics_get_y_variation:
    419 * @font: an #hb_font_t object.
    420 * @metrics_tag: tag of metrics value you like to fetch.
    421 *
    422 * Fetches vertical metrics value corresponding to @metrics_tag from @font with
    423 * the current font variation settings applied.
    424 *
    425 * Returns: The requested metric value.
    426 *
    427 * Since: 2.6.0
    428 **/
    429 hb_position_t
    430 hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
    431 {
    432  return font->em_scalef_y (hb_ot_metrics_get_variation (font, metrics_tag));
    433 }
    434 #endif
    435 
    436 #endif