tor-browser

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

hb-directwrite-font.cc (11940B)


      1 /*
      2 * Copyright © 2025  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_DIRECTWRITE
     30 
     31 #include "hb-directwrite.h"
     32 
     33 #include <d2d1.h>
     34 
     35 #include "hb-draw.hh"
     36 #include "hb-font.hh"
     37 #include "hb-machinery.hh"
     38 
     39 #define MAX_GLYPHS 256u
     40 
     41 static unsigned int
     42 hb_directwrite_get_nominal_glyphs (hb_font_t *font,
     43 			   void *font_data HB_UNUSED,
     44 			   unsigned int count,
     45 			   const hb_codepoint_t *first_unicode,
     46 			   unsigned int unicode_stride,
     47 			   hb_codepoint_t *first_glyph,
     48 			   unsigned int glyph_stride,
     49 			   void *user_data HB_UNUSED)
     50 {
     51  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
     52 
     53  for (unsigned i = 0; i < count;)
     54  {
     55    UINT32 unicodes[MAX_GLYPHS];
     56    UINT16 gids[MAX_GLYPHS];
     57 
     58    unsigned n = hb_min (MAX_GLYPHS, count - i);
     59 
     60    for (unsigned j = 0; j < n; j++)
     61    {
     62      unicodes[j] = *first_unicode;
     63      first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
     64    }
     65 
     66    if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids)))
     67      return i;
     68 
     69    for (unsigned j = 0; j < n; j++)
     70    {
     71      if (!gids[j])
     72        return i + j;
     73      *first_glyph = gids[j];
     74      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
     75    }
     76 
     77    i += n;
     78  }
     79 
     80  return count;
     81 }
     82 
     83 static hb_bool_t
     84 hb_directwrite_get_font_h_extents (hb_font_t *font,
     85 			   void *font_data HB_UNUSED,
     86 			   hb_font_extents_t *metrics,
     87 			   void *user_data HB_UNUSED)
     88 {
     89  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
     90 
     91  DWRITE_FONT_METRICS dw_metrics;
     92  dw_face->GetMetrics (&dw_metrics);
     93 
     94  metrics->ascender = font->em_scale_y (dw_metrics.ascent);
     95  metrics->descender = -font->em_scale_y (dw_metrics.descent);
     96  metrics->line_gap = font->em_scale_y (dw_metrics.lineGap);
     97 
     98  return true;
     99 }
    100 
    101 static void
    102 hb_directwrite_get_glyph_h_advances (hb_font_t* font,
    103 			     void* font_data HB_UNUSED,
    104 			     unsigned count,
    105 			     const hb_codepoint_t *first_glyph,
    106 			     unsigned glyph_stride,
    107 			     hb_position_t *first_advance,
    108 			     unsigned advance_stride,
    109 			     void *user_data HB_UNUSED)
    110 {
    111  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
    112 
    113  IDWriteFontFace1 *dw_face1 = nullptr;
    114  dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
    115  assert (dw_face1);
    116 
    117  unsigned int num_glyphs = font->face->get_num_glyphs ();
    118 
    119  for (unsigned i = 0; i < count;)
    120  {
    121    UINT16 gids[MAX_GLYPHS];
    122    INT32 advances[MAX_GLYPHS];
    123 
    124    unsigned n = hb_min (MAX_GLYPHS, count - i);
    125 
    126    for (unsigned j = 0; j < n; j++)
    127    {
    128      gids[j] = *first_glyph;
    129      advances[j] = 0;
    130      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
    131    }
    132    dw_face1->GetDesignGlyphAdvances (n, gids, advances, false);
    133    for (unsigned j = 0; j < n; j++)
    134    {
    135      // https://github.com/harfbuzz/harfbuzz/issues/5319
    136      auto advance = gids[j] < num_glyphs ? advances[j] : 0;
    137      *first_advance = font->em_scale_x (advance);
    138      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
    139    }
    140 
    141    i += n;
    142  }
    143 }
    144 
    145 #ifndef HB_NO_VERTICAL
    146 
    147 static void
    148 hb_directwrite_get_glyph_v_advances (hb_font_t* font,
    149 			     void* font_data HB_UNUSED,
    150 			     unsigned count,
    151 			     const hb_codepoint_t *first_glyph,
    152 			     unsigned glyph_stride,
    153 			     hb_position_t *first_advance,
    154 			     unsigned advance_stride,
    155 			     void *user_data HB_UNUSED)
    156 {
    157  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
    158 
    159  IDWriteFontFace1 *dw_face1 = nullptr;
    160  dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
    161  assert (dw_face1);
    162 
    163  for (unsigned i = 0; i < count;)
    164  {
    165    UINT16 gids[MAX_GLYPHS];
    166    INT32 advances[MAX_GLYPHS];
    167 
    168    unsigned n = hb_min (MAX_GLYPHS, count - i);
    169 
    170    for (unsigned j = 0; j < n; j++)
    171    {
    172      gids[j] = *first_glyph;
    173      advances[j] = 0;
    174      first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
    175    }
    176    dw_face1->GetDesignGlyphAdvances (n, gids, advances, true);
    177    for (unsigned j = 0; j < n; j++)
    178    {
    179      *first_advance = -font->em_scale_y (advances[j]);
    180      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
    181    }
    182 
    183    i += n;
    184  }
    185 }
    186 
    187 static hb_bool_t
    188 hb_directwrite_get_glyph_v_origin (hb_font_t *font,
    189 			   void *font_data HB_UNUSED,
    190 			   hb_codepoint_t glyph,
    191 			   hb_position_t *x,
    192 			   hb_position_t *y,
    193 			   void *user_data HB_UNUSED)
    194 {
    195  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
    196 
    197  UINT16 gid = glyph;
    198  DWRITE_GLYPH_METRICS metrics;
    199 
    200  if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
    201    return false;
    202 
    203  *x = font->em_scale_x (metrics.advanceWidth / 2);
    204  *y = font->em_scale_y (metrics.verticalOriginY); // Untested
    205 
    206  return true;
    207 }
    208 #endif
    209 
    210 static hb_bool_t
    211 hb_directwrite_get_glyph_extents (hb_font_t *font,
    212 			  void *font_data HB_UNUSED,
    213 			  hb_codepoint_t glyph,
    214 			  hb_glyph_extents_t *extents,
    215 			  void *user_data HB_UNUSED)
    216 {
    217  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
    218 
    219  UINT16 gid = glyph;
    220  DWRITE_GLYPH_METRICS metrics;
    221 
    222  if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
    223    return false;
    224 
    225  extents->x_bearing = font->em_scale_x (metrics.leftSideBearing);
    226  extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing);
    227  extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing;
    228  extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic
    229 
    230  return true;
    231 }
    232 
    233 
    234 #ifndef HB_NO_DRAW
    235 
    236 class GeometrySink : public IDWriteGeometrySink
    237 {
    238  hb_font_t *font;
    239  hb_draw_session_t drawing;
    240 
    241 public:
    242  GeometrySink(hb_font_t *font,
    243        hb_draw_funcs_t *draw_funcs,
    244        void *draw_data)
    245    : font (font), drawing ({draw_funcs, draw_data}) {}
    246 
    247  virtual ~GeometrySink() {}
    248 
    249  HRESULT STDMETHODCALLTYPE Close() override { return S_OK; }
    250  void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {}
    251  void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {}
    252 
    253  IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; }
    254  IFACEMETHOD_(ULONG, AddRef)() override { return 1; }
    255  IFACEMETHOD_(ULONG, Release)() override { return 1; }
    256 
    257  void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override
    258  {
    259    drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y));
    260  }
    261 
    262  void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override
    263  {
    264    for (unsigned i = 0; i < beziersCount; ++i)
    265      drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y),
    266 		font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y),
    267 		font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y));
    268  }
    269 
    270  void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override
    271  {
    272    for (unsigned i = 0; i < pointsCount; ++i)
    273      drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y));
    274  }
    275 
    276  void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override
    277  {
    278    drawing.close_path ();
    279  }
    280 };
    281 
    282 static hb_bool_t
    283 hb_directwrite_draw_glyph_or_fail (hb_font_t *font,
    284 			   void *font_data HB_UNUSED,
    285 			   hb_codepoint_t glyph,
    286 			   hb_draw_funcs_t *draw_funcs, void *draw_data,
    287 			   void *user_data)
    288 {
    289  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
    290 
    291  GeometrySink sink (font, draw_funcs, draw_data);
    292  UINT16 gid = static_cast<UINT16>(glyph);
    293  unsigned upem = font->face->get_upem();
    294 
    295  return S_OK == dw_face->GetGlyphRunOutline (upem,
    296 				      &gid, nullptr, nullptr,
    297 				      1,
    298 				      false, false,
    299 				      &sink);
    300 }
    301 
    302 #endif
    303 
    304 static inline void free_static_directwrite_funcs ();
    305 
    306 static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t>
    307 {
    308  static hb_font_funcs_t *create ()
    309  {
    310    hb_font_funcs_t *funcs = hb_font_funcs_create ();
    311 
    312    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr);
    313    //hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr);
    314 
    315    hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr);
    316    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr);
    317 
    318 #ifndef HB_NO_VERTICAL
    319    hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr);
    320    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr);
    321 #endif
    322 
    323 #ifndef HB_NO_DRAW
    324    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_directwrite_draw_glyph_or_fail, nullptr, nullptr);
    325 #endif
    326 
    327    hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr);
    328 
    329 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
    330    //hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr);
    331    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr);
    332 #endif
    333 
    334    hb_font_funcs_make_immutable (funcs);
    335 
    336    hb_atexit (free_static_directwrite_funcs);
    337 
    338    return funcs;
    339  }
    340 } static_directwrite_funcs;
    341 
    342 static inline
    343 void free_static_directwrite_funcs ()
    344 {
    345  static_directwrite_funcs.free_instance ();
    346 }
    347 
    348 static hb_font_funcs_t *
    349 _hb_directwrite_get_font_funcs ()
    350 {
    351  return static_directwrite_funcs.get_unconst ();
    352 }
    353 
    354 /**
    355 * hb_directwrite_font_set_funcs:
    356 * @font: #hb_font_t to work upon
    357 *
    358 * Configures the font-functions structure of the specified
    359 * #hb_font_t font object to use DirectWrite font functions.
    360 *
    361 * In particular, you can use this function to configure an
    362 * existing #hb_face_t face object for use with DirectWrite font
    363 * functions even if that #hb_face_t face object was initially
    364 * created with hb_face_create(), and therefore was not
    365 * initially configured to use DirectWrite font functions.
    366 *
    367 * <note>Note: Internally, this function creates a DirectWrite font.
    368 * </note>
    369 *
    370 * Since: 11.0.0
    371 **/
    372 void
    373 hb_directwrite_font_set_funcs (hb_font_t *font)
    374 {
    375  IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
    376  if (unlikely (!dw_face))
    377  {
    378    hb_font_set_funcs (font,
    379 	       hb_font_funcs_get_empty (),
    380 	       nullptr, nullptr);
    381    return;
    382  }
    383 
    384  dw_face->AddRef ();
    385  hb_font_set_funcs (font,
    386 	     _hb_directwrite_get_font_funcs (),
    387 	     nullptr, nullptr);
    388 }
    389 
    390 #undef MAX_GLYPHS
    391 
    392 #endif