tor-browser

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

hb-coretext-font.cc (16368B)


      1 /*
      2 * Copyright © 2024  Google, Inc.
      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 * Author(s): Behdad Esfahbod
     25 */
     26 
     27 #include "hb.hh"
     28 
     29 #ifdef HAVE_CORETEXT
     30 
     31 #include "hb-coretext.hh"
     32 #include "hb-aat-layout-trak-table.hh"
     33 
     34 #include "hb-draw.hh"
     35 #include "hb-font.hh"
     36 #include "hb-machinery.hh"
     37 
     38 #if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1080) \
     39    || (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 60000) \
     40    || (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 90000)
     41 #  define kCTFontOrientationDefault kCTFontDefaultOrientation
     42 #  define kCTFontOrientationHorizontal kCTFontHorizontalOrientation
     43 #  define kCTFontOrientationVertical kCTFontVerticalOrientation
     44 #endif
     45 
     46 #define MAX_GLYPHS 256u
     47 
     48 static hb_bool_t
     49 hb_coretext_get_nominal_glyph (hb_font_t *font,
     50 		       void *font_data HB_UNUSED,
     51 		       hb_codepoint_t unicode,
     52 		       hb_codepoint_t *glyph,
     53 		       void *user_data HB_UNUSED)
     54 {
     55  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
     56 
     57  UniChar ch[2];
     58  CGGlyph cg_glyph[2];
     59  unsigned count = 0;
     60 
     61  if (unicode <= 0xFFFF)
     62  {
     63    ch[count++] = unicode;
     64  }
     65  else if (unicode <= 0x10FFFF)
     66  {
     67    ch[count++] = (unicode >> 10) + 0xD7C0;
     68    ch[count++] = (unicode & 0x3FF) + 0xDC00;
     69  }
     70  else
     71    ch[count++] = 0xFFFD;
     72 
     73  if (CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count))
     74  {
     75    *glyph = cg_glyph[0];
     76    return true;
     77  }
     78  return false;
     79 }
     80 
     81 static unsigned int
     82 hb_coretext_get_nominal_glyphs (hb_font_t *font,
     83 			void *font_data,
     84 			unsigned int count,
     85 			const hb_codepoint_t *first_unicode,
     86 			unsigned int unicode_stride,
     87 			hb_codepoint_t *first_glyph,
     88 			unsigned int glyph_stride,
     89 			void *user_data HB_UNUSED)
     90 {
     91  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
     92 
     93  // If any non-BMP codepoint is requested, use the slow path.
     94  bool slow_path = false;
     95  auto *unicode = first_unicode;
     96  for (unsigned i = 0; i < count; i++)
     97  {
     98    if (*unicode > 0xFFFF)
     99    {
    100      slow_path = true;
    101      break;
    102    }
    103    unicode = &StructAtOffset<const hb_codepoint_t> (unicode, unicode_stride);
    104  }
    105 
    106  if (unlikely (slow_path))
    107  {
    108    for (unsigned i = 0; i < count; i++)
    109    {
    110      if (!hb_coretext_get_nominal_glyph (font, font_data, *first_unicode, first_glyph, nullptr))
    111 return i;
    112      first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
    113      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
    114    }
    115    return count;
    116  }
    117 
    118  UniChar ch[MAX_GLYPHS];
    119  CGGlyph cg_glyph[MAX_GLYPHS];
    120  for (unsigned i = 0; i < count; i += MAX_GLYPHS)
    121  {
    122    unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
    123    for (unsigned j = 0; j < c; j++)
    124    {
    125      ch[j] = *first_unicode;
    126      first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
    127    }
    128    if (unlikely (!CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c)))
    129    {
    130      // Use slow path partially and return at first failure.
    131      for (unsigned j = 0; j < c; j++)
    132      {
    133 if (!hb_coretext_get_nominal_glyph (font, font_data, ch[j], first_glyph, nullptr))
    134   return i + j;
    135 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
    136      }
    137    }
    138    for (unsigned j = 0; j < c; j++)
    139    {
    140      *first_glyph = cg_glyph[j];
    141      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
    142    }
    143  }
    144 
    145  return count;
    146 }
    147 
    148 static hb_bool_t
    149 hb_coretext_get_variation_glyph (hb_font_t *font,
    150 			 void *font_data HB_UNUSED,
    151 			 hb_codepoint_t unicode,
    152 			 hb_codepoint_t variation_selector,
    153 			 hb_codepoint_t *glyph,
    154 			 void *user_data HB_UNUSED)
    155 {
    156  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    157 
    158  UniChar ch[4];
    159  CGGlyph cg_glyph[4];
    160  unsigned count = 0;
    161 
    162  // Add Unicode, then variation selector. Ugly, but works.
    163  //
    164  if (unicode <= 0xFFFF)
    165    ch[count++] = unicode;
    166  else if (unicode <= 0x10FFFF)
    167  {
    168    ch[count++] = (unicode >> 10) + 0xD7C0;
    169    ch[count++] = (unicode & 0x3FF) + 0xDC00;
    170  }
    171  else
    172    ch[count++] = 0xFFFD;
    173 
    174  if (variation_selector <= 0xFFFF)
    175    ch[count++] = variation_selector;
    176  else if (variation_selector <= 0x10FFFF)
    177  {
    178    ch[count++] = (variation_selector >> 10) + 0xD7C0;
    179    ch[count++] = (variation_selector & 0x3FF) + 0xDC00;
    180  }
    181  else
    182    ch[count++] = 0xFFFD;
    183 
    184  CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count);
    185 
    186  // All except for first should be zero if we succeeded
    187  for (unsigned i = 1; i < count; i++)
    188    if (cg_glyph[i])
    189      return false;
    190 
    191  // Humm. CoreText falls back to the default glyph if the variation selector
    192  // is not supported.  We cannot truly detect that case. So, in essence,
    193  // we are always returning true here...
    194 
    195  *glyph = cg_glyph[0];
    196  return true;
    197 }
    198 
    199 static void
    200 hb_coretext_get_glyph_h_advances (hb_font_t* font,
    201 			  void* font_data HB_UNUSED,
    202 			  unsigned count,
    203 			  const hb_codepoint_t *first_glyph,
    204 			  unsigned glyph_stride,
    205 			  hb_position_t *first_advance,
    206 			  unsigned advance_stride,
    207 			  void *user_data HB_UNUSED)
    208 {
    209  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    210 
    211  CGFloat ct_font_size = CTFontGetSize (ct_font);
    212  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
    213  hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_LTR, 0.f);
    214 
    215  CGGlyph cg_glyph[MAX_GLYPHS];
    216  CGSize advances[MAX_GLYPHS];
    217  for (unsigned i = 0; i < count; i += MAX_GLYPHS)
    218  {
    219    unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
    220    for (unsigned j = 0; j < c; j++)
    221    {
    222      cg_glyph[j] = *first_glyph;
    223      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
    224    }
    225    CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
    226    for (unsigned j = 0; j < c; j++)
    227    {
    228      *first_advance = round (advances[j].width * x_mult) - tracking;
    229      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
    230    }
    231  }
    232 }
    233 
    234 #ifndef HB_NO_VERTICAL
    235 static void
    236 hb_coretext_get_glyph_v_advances (hb_font_t* font,
    237 			  void* font_data HB_UNUSED,
    238 			  unsigned count,
    239 			  const hb_codepoint_t *first_glyph,
    240 			  unsigned glyph_stride,
    241 			  hb_position_t *first_advance,
    242 			  unsigned advance_stride,
    243 			  void *user_data HB_UNUSED)
    244 {
    245  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    246 
    247  CGFloat ct_font_size = CTFontGetSize (ct_font);
    248  CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
    249  hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_TTB, 0.f);
    250 
    251  CGGlyph cg_glyph[MAX_GLYPHS];
    252  CGSize advances[MAX_GLYPHS];
    253  for (unsigned i = 0; i < count; i += MAX_GLYPHS)
    254  {
    255    unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
    256    for (unsigned j = 0; j < c; j++)
    257    {
    258      cg_glyph[j] = *first_glyph;
    259      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
    260    }
    261    CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
    262    for (unsigned j = 0; j < c; j++)
    263    {
    264      *first_advance = round (advances[j].width * y_mult) - tracking;
    265      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
    266    }
    267  }
    268 }
    269 
    270 static hb_bool_t
    271 hb_coretext_get_glyph_v_origin (hb_font_t *font,
    272 			void *font_data HB_UNUSED,
    273 			hb_codepoint_t glyph,
    274 			hb_position_t *x,
    275 			hb_position_t *y,
    276 			void *user_data HB_UNUSED)
    277 {
    278  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    279 
    280  CGFloat ct_font_size = CTFontGetSize (ct_font);
    281  CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
    282  CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
    283 
    284  const CGGlyph glyphs = glyph;
    285  CGSize origin;
    286  CTFontGetVerticalTranslationsForGlyphs (ct_font, &glyphs, &origin, 1);
    287 
    288  *x = round (x_mult * origin.width);
    289  *y = round (y_mult * origin.height);
    290 
    291  return true;
    292 }
    293 #endif
    294 
    295 static hb_bool_t
    296 hb_coretext_get_glyph_extents (hb_font_t *font,
    297 		       void *font_data HB_UNUSED,
    298 		       hb_codepoint_t glyph,
    299 		       hb_glyph_extents_t *extents,
    300 		       void *user_data HB_UNUSED)
    301 {
    302  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    303 
    304  CGFloat ct_font_size = CTFontGetSize (ct_font);
    305  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
    306  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
    307 
    308  CGGlyph glyphs[1] = { glyph };
    309  CGRect bounds = ::CTFontGetBoundingRectsForGlyphs(ct_font,
    310 					    kCTFontOrientationDefault, glyphs, NULL, 1);
    311 
    312  extents->x_bearing = round (bounds.origin.x * x_mult);
    313  extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult);
    314  extents->width = round (bounds.size.width * x_mult);
    315  extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing;
    316 
    317  return true;
    318 }
    319 
    320 static hb_bool_t
    321 hb_coretext_get_font_h_extents (hb_font_t *font,
    322 			void *font_data HB_UNUSED,
    323 			hb_font_extents_t *metrics,
    324 			void *user_data HB_UNUSED)
    325 {
    326  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    327 
    328  CGFloat ct_font_size = CTFontGetSize (ct_font);
    329  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
    330 
    331  metrics->ascender = round (CTFontGetAscent (ct_font) * y_mult);
    332  metrics->descender = -round (CTFontGetDescent (ct_font) * y_mult);
    333  metrics->line_gap = round (CTFontGetLeading (ct_font) * y_mult);
    334 
    335  return true;
    336 }
    337 
    338 #ifndef HB_NO_DRAW
    339 
    340 static void
    341 ct_apply_func (void *info, const CGPathElement *element)
    342 {
    343  hb_draw_session_t *draws = (hb_draw_session_t *) info;
    344 
    345  switch (element->type)
    346  {
    347  case kCGPathElementMoveToPoint:
    348    draws->move_to (element->points[0].x, element->points[0].y);
    349    break;
    350  case kCGPathElementAddLineToPoint:
    351    draws->line_to (element->points[0].x, element->points[0].y);
    352    break;
    353  case kCGPathElementAddQuadCurveToPoint:
    354    draws->quadratic_to (element->points[0].x, element->points[0].y,
    355 		 element->points[1].x, element->points[1].y);
    356    break;
    357  case kCGPathElementAddCurveToPoint:
    358    draws->cubic_to (element->points[0].x, element->points[0].y,
    359 	     element->points[1].x, element->points[1].y,
    360 	     element->points[2].x, element->points[2].y);
    361    break;
    362  case kCGPathElementCloseSubpath:
    363    draws->close_path ();
    364    break;
    365  }
    366 }
    367 
    368 static hb_bool_t
    369 hb_coretext_draw_glyph_or_fail (hb_font_t *font,
    370 			void *font_data HB_UNUSED,
    371 			hb_codepoint_t glyph,
    372 			hb_draw_funcs_t *draw_funcs, void *draw_data,
    373 			void *user_data)
    374 {
    375  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    376 
    377  CGFloat ct_font_size = CTFontGetSize (ct_font);
    378  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
    379  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
    380 
    381  CGAffineTransform transform = CGAffineTransformIdentity;
    382  transform = CGAffineTransformScale (transform, x_mult, y_mult);
    383 
    384  CGPathRef path = CTFontCreatePathForGlyph (ct_font, glyph, &transform);
    385  if (!path)
    386    return false;
    387 
    388  hb_draw_session_t drawing {draw_funcs, draw_data};
    389 
    390  CGPathApply (path, &drawing, ct_apply_func);
    391 
    392  CFRelease (path);
    393 
    394  return true;
    395 }
    396 #endif
    397 
    398 static hb_bool_t
    399 hb_coretext_get_glyph_name (hb_font_t *font,
    400 		    void *font_data HB_UNUSED,
    401 		    hb_codepoint_t glyph,
    402 		    char *name, unsigned int size,
    403 		    void *user_data HB_UNUSED)
    404 {
    405  CGFontRef cg_font = (CGFontRef) (const void *) font->face->data.coretext;
    406 
    407  CGGlyph cg_glyph = glyph;
    408  CFStringRef cf_name = CGFontCopyGlyphNameForGlyph (cg_font, cg_glyph);
    409  if (!cf_name)
    410    return false;
    411 
    412  CFIndex len = CFStringGetLength (cf_name);
    413  if (len > (CFIndex)size - 1)
    414    len = (CFIndex)size - 1;
    415 
    416  CFStringGetBytes (cf_name, CFRangeMake (0, len),
    417 	    kCFStringEncodingUTF8, 0, false,
    418 	    (UInt8 *) name, size, &len);
    419 
    420  name[len] = '\0';
    421 
    422  CFRelease (cf_name);
    423 
    424  return true;
    425 }
    426 
    427 static hb_bool_t
    428 hb_coretext_get_glyph_from_name (hb_font_t *font,
    429 			 void *font_data HB_UNUSED,
    430 			 const char *name, int len,
    431 			 hb_codepoint_t *glyph,
    432 			 void *user_data HB_UNUSED)
    433 {
    434  CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
    435 
    436  if (len == -1)
    437    len = strlen (name);
    438 
    439  CFStringRef cf_name = CFStringCreateWithBytes (kCFAllocatorDefault,
    440 					 (const UInt8 *) name, len,
    441 					 kCFStringEncodingUTF8, false);
    442  CGGlyph cg_glyph = CTFontGetGlyphWithName (ct_font, cf_name);
    443  *glyph = cg_glyph;
    444 
    445  CFRelease (cf_name);
    446 
    447  // TODO Return true for .notdef; hb-ft does that.
    448 
    449  return cg_glyph != 0;
    450 }
    451 
    452 
    453 static inline void free_static_coretext_funcs ();
    454 
    455 static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_coretext_font_funcs_lazy_loader_t>
    456 {
    457  static hb_font_funcs_t *create ()
    458  {
    459    hb_font_funcs_t *funcs = hb_font_funcs_create ();
    460 
    461    hb_font_funcs_set_nominal_glyph_func (funcs, hb_coretext_get_nominal_glyph, nullptr, nullptr);
    462    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_coretext_get_nominal_glyphs, nullptr, nullptr);
    463    hb_font_funcs_set_variation_glyph_func (funcs, hb_coretext_get_variation_glyph, nullptr, nullptr);
    464 
    465    hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
    466    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
    467 
    468 #ifndef HB_NO_VERTICAL
    469    hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
    470    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
    471 #endif
    472 
    473 #ifndef HB_NO_DRAW
    474    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_coretext_draw_glyph_or_fail, nullptr, nullptr);
    475 #endif
    476 
    477    hb_font_funcs_set_glyph_extents_func (funcs, hb_coretext_get_glyph_extents, nullptr, nullptr);
    478 
    479 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
    480    hb_font_funcs_set_glyph_name_func (funcs, hb_coretext_get_glyph_name, nullptr, nullptr);
    481    hb_font_funcs_set_glyph_from_name_func (funcs, hb_coretext_get_glyph_from_name, nullptr, nullptr);
    482 #endif
    483 
    484    hb_font_funcs_make_immutable (funcs);
    485 
    486    hb_atexit (free_static_coretext_funcs);
    487 
    488    return funcs;
    489  }
    490 } static_coretext_funcs;
    491 
    492 static inline
    493 void free_static_coretext_funcs ()
    494 {
    495  static_coretext_funcs.free_instance ();
    496 }
    497 
    498 static hb_font_funcs_t *
    499 _hb_coretext_get_font_funcs ()
    500 {
    501  return static_coretext_funcs.get_unconst ();
    502 }
    503 
    504 
    505 /**
    506 * hb_coretext_font_set_funcs:
    507 * @font: #hb_font_t to work upon
    508 *
    509 * Configures the font-functions structure of the specified
    510 * #hb_font_t font object to use CoreText font functions.
    511 *
    512 * In particular, you can use this function to configure an
    513 * existing #hb_face_t face object for use with CoreText font
    514 * functions even if that #hb_face_t face object was initially
    515 * created with hb_face_create(), and therefore was not
    516 * initially configured to use CoreText font functions.
    517 *
    518 * <note>Note: Internally, this function creates a CTFont.
    519 * </note>
    520 *
    521 * Since: 10.1.0
    522 **/
    523 void
    524 hb_coretext_font_set_funcs (hb_font_t *font)
    525 {
    526  CTFontRef ct_font = hb_coretext_font_get_ct_font (font);
    527  if (unlikely (!ct_font))
    528  {
    529    hb_font_set_funcs (font,
    530 	       hb_font_funcs_get_empty (),
    531 	       nullptr, nullptr);
    532    return;
    533  }
    534 
    535  hb_font_set_funcs (font,
    536 	     _hb_coretext_get_font_funcs (),
    537 	     nullptr, nullptr);
    538 }
    539 
    540 #undef MAX_GLYPHS
    541 
    542 #endif