tor-browser

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

hb-directwrite.cc (12397B)


      1 /*
      2 * Copyright © 2015-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 #ifdef HAVE_DIRECTWRITE
     28 
     29 #include "hb-directwrite.hh"
     30 
     31 #include "hb-font.hh"
     32 
     33 
     34 /**
     35 * SECTION:hb-directwrite
     36 * @title: hb-directwrite
     37 * @short_description: DirectWrite integration
     38 * @include: hb-directwrite.h
     39 *
     40 * Functions for using HarfBuzz with DirectWrite fonts.
     41 **/
     42 
     43 static inline void free_static_directwrite_global ();
     44 
     45 static struct hb_directwrite_global_lazy_loader_t : hb_lazy_loader_t<hb_directwrite_global_t,
     46 							     hb_directwrite_global_lazy_loader_t>
     47 {
     48  static hb_directwrite_global_t * create ()
     49  {
     50    hb_directwrite_global_t *global = new hb_directwrite_global_t;
     51 
     52    if (unlikely (!global))
     53      return nullptr;
     54    if (unlikely (!global->success))
     55    {
     56      delete global;
     57      return nullptr;
     58    }
     59 
     60    hb_atexit (free_static_directwrite_global);
     61 
     62    return global;
     63  }
     64  static void destroy (hb_directwrite_global_t *l)
     65  {
     66    delete l;
     67  }
     68  static hb_directwrite_global_t * get_null ()
     69  {
     70    return nullptr;
     71  }
     72 } static_directwrite_global;
     73 
     74 
     75 static inline
     76 void free_static_directwrite_global ()
     77 {
     78  static_directwrite_global.free_instance ();
     79 }
     80 
     81 hb_directwrite_global_t *
     82 get_directwrite_global ()
     83 {
     84  return static_directwrite_global.get_unconst ();
     85 }
     86 
     87 DWriteFontFileStream::DWriteFontFileStream (hb_blob_t *blob)
     88 {
     89  auto *global = get_directwrite_global ();
     90  mLoader = global->fontFileLoader;
     91  mRefCount.init ();
     92  mLoader->AddRef ();
     93  hb_blob_make_immutable (blob);
     94  mBlob = hb_blob_reference (blob);
     95  mData = (uint8_t *) hb_blob_get_data (blob, &mSize);
     96  fontFileKey = mLoader->RegisterFontFileStream (this);
     97 }
     98 
     99 DWriteFontFileStream::~DWriteFontFileStream()
    100 {
    101  mLoader->UnregisterFontFileStream (fontFileKey);
    102  mLoader->Release ();
    103  hb_blob_destroy (mBlob);
    104 }
    105 
    106 IDWriteFontFace *
    107 dw_face_create (hb_blob_t *blob, unsigned index)
    108 {
    109 #define FAIL(...) \
    110  HB_STMT_START { \
    111    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
    112    return nullptr; \
    113  } HB_STMT_END
    114 
    115  auto *global = get_directwrite_global ();
    116  if (unlikely (!global))
    117    FAIL ("Couldn't load DirectWrite!");
    118 
    119  DWriteFontFileStream *fontFileStream = new DWriteFontFileStream (blob);
    120 
    121  IDWriteFontFile *fontFile;
    122  auto hr = global->dwriteFactory->CreateCustomFontFileReference (&fontFileStream->fontFileKey, sizeof (fontFileStream->fontFileKey),
    123 							  global->fontFileLoader, &fontFile);
    124 
    125  fontFileStream->Release ();
    126 
    127  if (FAILED (hr))
    128    FAIL ("Failed to load font file from data!");
    129 
    130  BOOL isSupported;
    131  DWRITE_FONT_FILE_TYPE fileType;
    132  DWRITE_FONT_FACE_TYPE faceType;
    133  uint32_t numberOfFaces;
    134  hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
    135  if (FAILED (hr) || !isSupported)
    136  {
    137    fontFile->Release ();
    138    FAIL ("Font file is not supported.");
    139  }
    140 
    141 #undef FAIL
    142 
    143  IDWriteFontFace *fontFace = nullptr;
    144  global->dwriteFactory->CreateFontFace (faceType, 1, &fontFile, index,
    145 				 DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
    146  fontFile->Release ();
    147 
    148  return fontFace;
    149 }
    150 
    151 struct _hb_directwrite_font_table_context {
    152  IDWriteFontFace *face;
    153  void *table_context;
    154 };
    155 
    156 static void
    157 _hb_directwrite_table_data_release (void *data)
    158 {
    159  _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
    160  context->face->ReleaseFontTable (context->table_context);
    161  hb_free (context);
    162 }
    163 
    164 static hb_blob_t *
    165 _hb_directwrite_get_file_blob (IDWriteFontFace *dw_face)
    166 {
    167  UINT32 file_count;
    168  if (FAILED (dw_face->GetFiles(&file_count, NULL)))
    169    return nullptr;
    170 
    171  IDWriteFontFile **files = new IDWriteFontFile*[file_count];
    172  if (FAILED (dw_face->GetFiles(&file_count, files)))
    173  {
    174    delete [] files;
    175    return nullptr;
    176  }
    177 
    178  hb_blob_t *blob = nullptr;
    179  for (UINT32 i = 0; i < file_count; i++)
    180  {
    181    LPCVOID reference_key;
    182    UINT32 reference_key_size;
    183    if (FAILED (files[i]->GetReferenceKey(&reference_key, &reference_key_size)))
    184      continue;
    185 
    186    IDWriteFontFileLoader *loader;
    187    if (FAILED (files[i]->GetLoader(&loader)))
    188      continue;
    189    
    190    IDWriteFontFileStream *stream;
    191    if (FAILED (loader->CreateStreamFromKey (reference_key, reference_key_size, &stream)))
    192    {
    193      loader->Release ();
    194      continue;
    195    }
    196 
    197    UINT64 file_size;
    198    const void *fragment;
    199    void *context;
    200    if (FAILED (stream->GetFileSize(&file_size)) ||
    201        FAILED (stream->ReadFileFragment (&fragment, 0, file_size, &context)))
    202    {
    203      loader->Release ();
    204      continue;
    205    }
    206    blob = hb_blob_create ((const char *) fragment, file_size, HB_MEMORY_MODE_DUPLICATE, NULL, NULL);
    207    stream->ReleaseFileFragment (context);
    208    loader->Release ();
    209    break;
    210  }
    211 
    212  delete [] files;
    213  return blob;
    214 }
    215 
    216 static hb_blob_t *
    217 _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
    218 {
    219  IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
    220  const void *data;
    221  uint32_t length;
    222  void *table_context;
    223  BOOL exists;
    224  if (tag == HB_TAG_NONE)
    225    return _hb_directwrite_get_file_blob (dw_face);
    226 
    227  if (FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
    228 				&length, &table_context, &exists)))
    229    return nullptr;
    230 
    231  if (!data || !exists || !length)
    232  {
    233    dw_face->ReleaseFontTable (table_context);
    234    return nullptr;
    235  }
    236 
    237  _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
    238  if (unlikely (!context))
    239  {
    240    dw_face->ReleaseFontTable (table_context);
    241    return nullptr;
    242  }
    243  context->face = dw_face;
    244  context->table_context = table_context;
    245 
    246  return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
    247 		 context, _hb_directwrite_table_data_release);
    248 }
    249 
    250 static void
    251 _hb_directwrite_face_release (void *data)
    252 {
    253  ((IDWriteFontFace *) data)->Release ();
    254 }
    255 
    256 /**
    257 * hb_directwrite_face_create:
    258 * @dw_face: a DirectWrite IDWriteFontFace object.
    259 *
    260 * Constructs a new face object from the specified DirectWrite IDWriteFontFace.
    261 *
    262 * Return value: #hb_face_t object corresponding to the given input
    263 *
    264 * Since: 2.4.0
    265 **/
    266 hb_face_t *
    267 hb_directwrite_face_create (IDWriteFontFace *dw_face)
    268 {
    269  if (!dw_face)
    270    return hb_face_get_empty ();
    271 
    272  dw_face->AddRef ();
    273  hb_face_t *face = hb_face_create_for_tables (_hb_directwrite_reference_table,
    274 				       dw_face,
    275 				       _hb_directwrite_face_release);
    276 
    277  hb_face_set_index (face, dw_face->GetIndex ());
    278  hb_face_set_glyph_count (face, dw_face->GetGlyphCount ());
    279 
    280  return face;
    281 }
    282 
    283 /**
    284 * hb_directwrite_face_create_from_file_or_fail:
    285 * @file_name: A font filename
    286 * @index: The index of the face within the file
    287 *
    288 * Creates an #hb_face_t face object from the specified
    289 * font file and face index.
    290 *
    291 * This is similar in functionality to hb_face_create_from_file_or_fail(),
    292 * but uses the DirectWrite library for loading the font file.
    293 *
    294 * Return value: (transfer full): The new face object, or `NULL` if
    295 * no face is found at the specified index or the file cannot be read.
    296 *
    297 * Since: 11.0.0
    298 */
    299 hb_face_t *
    300 hb_directwrite_face_create_from_file_or_fail (const char   *file_name,
    301 				      unsigned int  index)
    302 {
    303  auto *blob = hb_blob_create_from_file_or_fail (file_name);
    304  if (unlikely (!blob))
    305    return nullptr;
    306 
    307  return hb_directwrite_face_create_from_blob_or_fail (blob, index);
    308 }
    309 
    310 /**
    311 * hb_directwrite_face_create_from_blob_or_fail:
    312 * @blob: A blob containing the font data
    313 * @index: The index of the face within the blob
    314 *
    315 * Creates an #hb_face_t face object from the specified
    316 * blob and face index.
    317 *
    318 * This is similar in functionality to hb_face_create_from_blob_or_fail(),
    319 * but uses the DirectWrite library for loading the font data.
    320 *
    321 * Return value: (transfer full): The new face object, or `NULL` if
    322 * no face is found at the specified index or the blob cannot be read.
    323 *
    324 * Since: 11.0.0
    325 */
    326 HB_EXTERN hb_face_t *
    327 hb_directwrite_face_create_from_blob_or_fail (hb_blob_t    *blob,
    328 				      unsigned int  index)
    329 {
    330  IDWriteFontFace *dw_face = dw_face_create (blob, index);
    331  if (unlikely (!dw_face))
    332    return nullptr;
    333 
    334  hb_face_t *face = hb_directwrite_face_create (dw_face);
    335  if (unlikely (hb_object_is_immutable (face)))
    336  {
    337    dw_face->Release ();
    338    return face;
    339  }
    340 
    341  /* Let there be dragons here... */
    342  face->data.directwrite.cmpexch (nullptr, (hb_directwrite_face_data_t *) dw_face);
    343 
    344  return face;
    345 }
    346 
    347 /**
    348 * hb_directwrite_face_get_dw_font_face:
    349 * @face: a #hb_face_t object
    350 *
    351 * Gets the DirectWrite IDWriteFontFace associated with @face.
    352 *
    353 * Return value: DirectWrite IDWriteFontFace object corresponding to the given input
    354 *
    355 * Since: 10.4.0
    356 **/
    357 IDWriteFontFace *
    358 hb_directwrite_face_get_dw_font_face (hb_face_t *face)
    359 {
    360  return (IDWriteFontFace *) (const void *) face->data.directwrite;
    361 }
    362 
    363 #ifndef HB_DISABLE_DEPRECATED
    364 
    365 /**
    366 * hb_directwrite_face_get_font_face:
    367 * @face: a #hb_face_t object
    368 *
    369 * Gets the DirectWrite IDWriteFontFace associated with @face.
    370 *
    371 * Return value: DirectWrite IDWriteFontFace object corresponding to the given input
    372 *
    373 * Since: 2.5.0
    374 * Deprecated: 10.4.0: Use hb_directwrite_face_get_dw_font_face() instead
    375 **/
    376 IDWriteFontFace *
    377 hb_directwrite_face_get_font_face (hb_face_t *face)
    378 {
    379  return hb_directwrite_face_get_dw_font_face (face);
    380 }
    381 
    382 #endif
    383 
    384 /**
    385 * hb_directwrite_font_create:
    386 * @dw_face: a DirectWrite IDWriteFontFace object.
    387 *
    388 * Constructs a new font object from the specified DirectWrite IDWriteFontFace.
    389 *
    390 * Return value: #hb_font_t object corresponding to the given input
    391 *
    392 * Since: 11.0.0
    393 **/
    394 hb_font_t *
    395 hb_directwrite_font_create (IDWriteFontFace *dw_face)
    396 {
    397  IDWriteFontFace5 *dw_face5 = nullptr;
    398 
    399  hb_face_t *face = hb_directwrite_face_create (dw_face);
    400  hb_font_t *font = hb_font_create (face);
    401  hb_face_destroy (face);
    402 
    403  if (unlikely (hb_object_is_immutable (font)))
    404    return font;
    405 
    406  /* Copy font variations */
    407  if (SUCCEEDED (dw_face->QueryInterface (__uuidof (IDWriteFontFace5), (void**) &dw_face5)))
    408  {
    409    if (dw_face5->HasVariations ())
    410    {
    411      hb_vector_t<DWRITE_FONT_AXIS_VALUE> values;
    412      uint32_t count = dw_face5->GetFontAxisValueCount ();
    413      if (likely (values.resize_exact (count)) &&
    414   SUCCEEDED (dw_face5->GetFontAxisValues (values.arrayZ, count)))
    415      {
    416 hb_vector_t<hb_variation_t> vars;
    417 if (likely (vars.resize_exact (count)))
    418 {
    419   for (uint32_t i = 0; i < count; ++i)
    420   {
    421     hb_tag_t tag = hb_uint32_swap (values[i].axisTag);
    422     float value = values[i].value;
    423     vars[i] = {tag, value};
    424   }
    425   hb_font_set_variations (font, vars.arrayZ, vars.length);
    426 }
    427      }
    428    }
    429    dw_face5->Release ();
    430  }
    431 
    432  /* Let there be dragons here... */
    433  dw_face->AddRef ();
    434  font->data.directwrite.cmpexch (nullptr, (hb_directwrite_font_data_t *) dw_face);
    435 
    436  return font;
    437 }
    438 
    439 /**
    440 * hb_directwrite_font_get_dw_font_face:
    441 * @font: a #hb_font_t object
    442 *
    443 * Gets the DirectWrite IDWriteFontFace associated with @font.
    444 *
    445 * Return value: DirectWrite IDWriteFontFace object corresponding to the given input
    446 *
    447 * Since: 11.0.0
    448 **/
    449 IDWriteFontFace *
    450 hb_directwrite_font_get_dw_font_face (hb_font_t *font)
    451 {
    452  return (IDWriteFontFace *) (const void *) font->data.directwrite;
    453 }
    454 
    455 
    456 /**
    457 * hb_directwrite_font_get_dw_font:
    458 * @font: a #hb_font_t object
    459 *
    460 * Deprecated.
    461 *
    462 * Return value: Returns `NULL`.
    463 *
    464 * Since: 10.3.0
    465 * Deprecated: 11.0.0:
    466 **/
    467 IDWriteFont *
    468 hb_directwrite_font_get_dw_font (hb_font_t *font)
    469 {
    470  return nullptr;
    471 }
    472 
    473 #endif