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