hb-uniscribe.cc (25090B)
1 /* 2 * Copyright © 2011,2012,2013 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 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #include "hb.hh" 28 29 #ifdef HAVE_UNISCRIBE 30 31 #ifdef HB_NO_OT_TAG 32 #error "Cannot compile 'uniscribe' shaper with HB_NO_OT_TAG." 33 #endif 34 35 #include "hb-shaper-impl.hh" 36 37 #include <windows.h> 38 #include <usp10.h> 39 #include <rpc.h> 40 41 #ifndef E_NOT_SUFFICIENT_BUFFER 42 #define E_NOT_SUFFICIENT_BUFFER HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER) 43 #endif 44 45 #include "hb-uniscribe.h" 46 47 #include "hb-ms-feature-ranges.hh" 48 #include "hb-open-file.hh" 49 #include "hb-ot-name-table.hh" 50 #include "hb-ot-layout.h" 51 52 53 /** 54 * SECTION:hb-uniscribe 55 * @title: hb-uniscribe 56 * @short_description: Windows integration 57 * @include: hb-uniscribe.h 58 * 59 * Functions for using HarfBuzz with Windows fonts. 60 **/ 61 62 typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/( 63 const WCHAR *pwcInChars, 64 int cInChars, 65 int cMaxItems, 66 const SCRIPT_CONTROL *psControl, 67 const SCRIPT_STATE *psState, 68 SCRIPT_ITEM *pItems, 69 OPENTYPE_TAG *pScriptTags, 70 int *pcItems 71 ); 72 73 typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/( 74 HDC hdc, 75 SCRIPT_CACHE *psc, 76 SCRIPT_ANALYSIS *psa, 77 OPENTYPE_TAG tagScript, 78 OPENTYPE_TAG tagLangSys, 79 int *rcRangeChars, 80 TEXTRANGE_PROPERTIES **rpRangeProperties, 81 int cRanges, 82 const WCHAR *pwcChars, 83 int cChars, 84 int cMaxGlyphs, 85 WORD *pwLogClust, 86 SCRIPT_CHARPROP *pCharProps, 87 WORD *pwOutGlyphs, 88 SCRIPT_GLYPHPROP *pOutGlyphProps, 89 int *pcGlyphs 90 ); 91 92 typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/( 93 HDC hdc, 94 SCRIPT_CACHE *psc, 95 SCRIPT_ANALYSIS *psa, 96 OPENTYPE_TAG tagScript, 97 OPENTYPE_TAG tagLangSys, 98 int *rcRangeChars, 99 TEXTRANGE_PROPERTIES **rpRangeProperties, 100 int cRanges, 101 const WCHAR *pwcChars, 102 WORD *pwLogClust, 103 SCRIPT_CHARPROP *pCharProps, 104 int cChars, 105 const WORD *pwGlyphs, 106 const SCRIPT_GLYPHPROP *pGlyphProps, 107 int cGlyphs, 108 int *piAdvance, 109 GOFFSET *pGoffset, 110 ABC *pABC 111 ); 112 113 114 /* Fallback implementations. */ 115 116 static HRESULT WINAPI 117 hb_ScriptItemizeOpenType( 118 const WCHAR *pwcInChars, 119 int cInChars, 120 int cMaxItems, 121 const SCRIPT_CONTROL *psControl, 122 const SCRIPT_STATE *psState, 123 SCRIPT_ITEM *pItems, 124 OPENTYPE_TAG *pScriptTags, 125 int *pcItems 126 ) 127 { 128 { 129 return ScriptItemize (pwcInChars, 130 cInChars, 131 cMaxItems, 132 psControl, 133 psState, 134 pItems, 135 pcItems); 136 } 137 } 138 139 static HRESULT WINAPI 140 hb_ScriptShapeOpenType( 141 HDC hdc, 142 SCRIPT_CACHE *psc, 143 SCRIPT_ANALYSIS *psa, 144 OPENTYPE_TAG tagScript, 145 OPENTYPE_TAG tagLangSys, 146 int *rcRangeChars, 147 TEXTRANGE_PROPERTIES **rpRangeProperties, 148 int cRanges, 149 const WCHAR *pwcChars, 150 int cChars, 151 int cMaxGlyphs, 152 WORD *pwLogClust, 153 SCRIPT_CHARPROP *pCharProps, 154 WORD *pwOutGlyphs, 155 SCRIPT_GLYPHPROP *pOutGlyphProps, 156 int *pcGlyphs 157 ) 158 { 159 SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps; 160 return ScriptShape (hdc, 161 psc, 162 pwcChars, 163 cChars, 164 cMaxGlyphs, 165 psa, 166 pwOutGlyphs, 167 pwLogClust, 168 psva, 169 pcGlyphs); 170 } 171 172 static HRESULT WINAPI 173 hb_ScriptPlaceOpenType( 174 HDC hdc, 175 SCRIPT_CACHE *psc, 176 SCRIPT_ANALYSIS *psa, 177 OPENTYPE_TAG tagScript, 178 OPENTYPE_TAG tagLangSys, 179 int *rcRangeChars, 180 TEXTRANGE_PROPERTIES **rpRangeProperties, 181 int cRanges, 182 const WCHAR *pwcChars, 183 WORD *pwLogClust, 184 SCRIPT_CHARPROP *pCharProps, 185 int cChars, 186 const WORD *pwGlyphs, 187 const SCRIPT_GLYPHPROP *pGlyphProps, 188 int cGlyphs, 189 int *piAdvance, 190 GOFFSET *pGoffset, 191 ABC *pABC 192 ) 193 { 194 SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps; 195 return ScriptPlace (hdc, 196 psc, 197 pwGlyphs, 198 cGlyphs, 199 psva, 200 psa, 201 piAdvance, 202 pGoffset, 203 pABC); 204 } 205 206 207 struct hb_uniscribe_shaper_funcs_t 208 { 209 SIOT ScriptItemizeOpenType; 210 SSOT ScriptShapeOpenType; 211 SPOT ScriptPlaceOpenType; 212 213 void init () 214 { 215 HMODULE hinstLib; 216 this->ScriptItemizeOpenType = nullptr; 217 this->ScriptShapeOpenType = nullptr; 218 this->ScriptPlaceOpenType = nullptr; 219 220 hinstLib = GetModuleHandle (TEXT ("usp10.dll")); 221 if (hinstLib) 222 { 223 #pragma GCC diagnostic push 224 #pragma GCC diagnostic ignored "-Wcast-function-type" 225 this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType"); 226 this->ScriptShapeOpenType = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType"); 227 this->ScriptPlaceOpenType = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType"); 228 #pragma GCC diagnostic pop 229 } 230 if (!this->ScriptItemizeOpenType || 231 !this->ScriptShapeOpenType || 232 !this->ScriptPlaceOpenType) 233 { 234 DEBUG_MSG (UNISCRIBE, nullptr, "OpenType versions of functions not found; falling back."); 235 this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType; 236 this->ScriptShapeOpenType = hb_ScriptShapeOpenType; 237 this->ScriptPlaceOpenType = hb_ScriptPlaceOpenType; 238 } 239 } 240 }; 241 242 static inline void free_static_uniscribe_shaper_funcs (); 243 244 static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t, 245 hb_uniscribe_shaper_funcs_lazy_loader_t> 246 { 247 static hb_uniscribe_shaper_funcs_t *create () 248 { 249 hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_calloc (1, sizeof (hb_uniscribe_shaper_funcs_t)); 250 if (unlikely (!funcs)) 251 return nullptr; 252 253 funcs->init (); 254 255 hb_atexit (free_static_uniscribe_shaper_funcs); 256 257 return funcs; 258 } 259 static void destroy (hb_uniscribe_shaper_funcs_t *p) 260 { 261 hb_free ((void *) p); 262 } 263 static hb_uniscribe_shaper_funcs_t *get_null () 264 { 265 return nullptr; 266 } 267 } static_uniscribe_shaper_funcs; 268 269 static inline 270 void free_static_uniscribe_shaper_funcs () 271 { 272 static_uniscribe_shaper_funcs.free_instance (); 273 } 274 275 static hb_uniscribe_shaper_funcs_t * 276 hb_uniscribe_shaper_get_funcs () 277 { 278 return static_uniscribe_shaper_funcs.get_unconst (); 279 } 280 281 282 /* 283 * shaper face data 284 */ 285 286 struct hb_uniscribe_face_data_t { 287 HANDLE fh; 288 hb_uniscribe_shaper_funcs_t *funcs; 289 wchar_t face_name[LF_FACESIZE]; 290 }; 291 292 /* face_name should point to a wchar_t[LF_FACESIZE] object. */ 293 static void 294 _hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen) 295 { 296 /* We'll create a private name for the font from a UUID using a simple, 297 * somewhat base64-like encoding scheme */ 298 const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; 299 UUID id; 300 UuidCreate ((UUID*) &id); 301 static_assert ((2 + 3 * (16/2) < LF_FACESIZE), ""); 302 unsigned int name_str_len = 0; 303 face_name[name_str_len++] = 'F'; 304 face_name[name_str_len++] = '_'; 305 unsigned char *p = (unsigned char *) &id; 306 for (unsigned int i = 0; i < 16; i += 2) 307 { 308 /* Spread the 16 bits from two bytes of the UUID across three chars of face_name, 309 * using the bits in groups of 5,5,6 to select chars from enc. 310 * This will generate 24 characters; with the 'F_' prefix we already provided, 311 * the name will be 26 chars (plus the NUL terminator), so will always fit within 312 * face_name (LF_FACESIZE = 32). */ 313 face_name[name_str_len++] = enc[p[i] >> 3]; 314 face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f]; 315 face_name[name_str_len++] = enc[p[i + 1] & 0x3f]; 316 } 317 face_name[name_str_len] = 0; 318 if (plen) 319 *plen = name_str_len; 320 } 321 322 /* Destroys blob. */ 323 static hb_blob_t * 324 _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) 325 { 326 /* Create a copy of the font data, with the 'name' table replaced by a 327 * table that names the font with our private F_* name created above. 328 * For simplicity, we just append a new 'name' table and update the 329 * sfnt directory; the original table is left in place, but unused. 330 * 331 * The new table will contain just 5 name IDs: family, style, unique, 332 * full, PS. All of them point to the same name data with our unique name. 333 */ 334 335 blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (blob); 336 337 unsigned int length, new_length, name_str_len; 338 const char *orig_sfnt_data = hb_blob_get_data (blob, &length); 339 340 _hb_generate_unique_face_name (new_name, &name_str_len); 341 342 static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 }; 343 344 unsigned int name_table_length = OT::name::min_size + 345 ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size + 346 name_str_len * 2; /* for name data in UTF16BE form */ 347 unsigned int padded_name_table_length = ((name_table_length + 3) & ~3); 348 unsigned int name_table_offset = (length + 3) & ~3; 349 350 new_length = name_table_offset + padded_name_table_length; 351 void *new_sfnt_data = hb_calloc (1, new_length); 352 if (!new_sfnt_data) 353 { 354 hb_blob_destroy (blob); 355 return nullptr; 356 } 357 358 hb_memcpy(new_sfnt_data, orig_sfnt_data, length); 359 360 OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset); 361 name.format = 0; 362 name.count = ARRAY_LENGTH (name_IDs); 363 name.stringOffset = name.get_size (); 364 for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++) 365 { 366 OT::NameRecord &record = name.nameRecordZ[i]; 367 record.platformID = 3; 368 record.encodingID = 1; 369 record.languageID = 0x0409u; /* English */ 370 record.nameID = name_IDs[i]; 371 record.length = name_str_len * 2; 372 record.offset = 0; 373 } 374 375 /* Copy string data from new_name, converting wchar_t to UTF16BE. */ 376 unsigned char *p = &StructAfter<unsigned char> (name); 377 for (unsigned int i = 0; i < name_str_len; i++) 378 { 379 *p++ = new_name[i] >> 8; 380 *p++ = new_name[i] & 0xff; 381 } 382 383 /* Adjust name table entry to point to new name table */ 384 const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data); 385 unsigned int face_count = file.get_face_count (); 386 for (unsigned int face_index = 0; face_index < face_count; face_index++) 387 { 388 /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be 389 * toe-stepping. But we don't really care. */ 390 const OT::OpenTypeFontFace &face = file.get_face (face_index); 391 unsigned int index; 392 if (face.find_table_index (HB_OT_TAG_name, &index)) 393 { 394 OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index)); 395 record.checkSum.set_for_data (&name, padded_name_table_length); 396 record.offset = name_table_offset; 397 record.length = name_table_length; 398 } 399 else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */ 400 { 401 hb_free (new_sfnt_data); 402 hb_blob_destroy (blob); 403 return nullptr; 404 } 405 } 406 407 /* The checkSumAdjustment field in the 'head' table is now wrong, 408 * but that doesn't actually seem to cause any problems so we don't 409 * bother. */ 410 411 hb_blob_destroy (blob); 412 return hb_blob_create ((const char *) new_sfnt_data, new_length, 413 HB_MEMORY_MODE_WRITABLE, new_sfnt_data, hb_free); 414 } 415 416 hb_uniscribe_face_data_t * 417 _hb_uniscribe_shaper_face_data_create (hb_face_t *face) 418 { 419 hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_calloc (1, sizeof (hb_uniscribe_face_data_t)); 420 if (unlikely (!data)) 421 return nullptr; 422 423 data->funcs = hb_uniscribe_shaper_get_funcs (); 424 if (unlikely (!data->funcs)) 425 { 426 hb_free (data); 427 return nullptr; 428 } 429 430 hb_blob_t *blob = hb_face_reference_blob (face); 431 if (unlikely (!hb_blob_get_length (blob))) 432 DEBUG_MSG (UNISCRIBE, face, "Face has empty blob"); 433 434 blob = _hb_rename_font (blob, data->face_name); 435 if (unlikely (!blob)) 436 { 437 hb_free (data); 438 return nullptr; 439 } 440 441 DWORD num_fonts_installed; 442 data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, nullptr), 443 hb_blob_get_length (blob), 444 0, &num_fonts_installed); 445 if (unlikely (!data->fh)) 446 { 447 DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed"); 448 hb_free (data); 449 return nullptr; 450 } 451 452 return data; 453 } 454 455 void 456 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t *data) 457 { 458 RemoveFontMemResourceEx (data->fh); 459 hb_free (data); 460 } 461 462 463 /* 464 * shaper font data 465 */ 466 467 struct hb_uniscribe_font_data_t 468 { 469 HDC hdc; 470 mutable LOGFONTW log_font; 471 HFONT hfont; 472 mutable SCRIPT_CACHE script_cache; 473 double x_mult, y_mult; /* From LOGFONT space to HB space. */ 474 }; 475 476 static bool 477 populate_log_font (LOGFONTW *lf, 478 hb_font_t *font, 479 unsigned int font_size) 480 { 481 hb_memset (lf, 0, sizeof (*lf)); 482 lf->lfHeight = - (int) font_size; 483 lf->lfCharSet = DEFAULT_CHARSET; 484 485 hb_memcpy (lf->lfFaceName, font->face->data.uniscribe->face_name, sizeof (lf->lfFaceName)); 486 487 return true; 488 } 489 490 hb_uniscribe_font_data_t * 491 _hb_uniscribe_shaper_font_data_create (hb_font_t *font) 492 { 493 hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_calloc (1, sizeof (hb_uniscribe_font_data_t)); 494 if (unlikely (!data)) 495 return nullptr; 496 497 int font_size = font->face->get_upem (); /* Default... */ 498 /* No idea if the following is even a good idea. */ 499 if (font->y_ppem) 500 font_size = font->y_ppem; 501 502 if (font_size < 0) 503 font_size = -font_size; 504 data->x_mult = (double) font->x_scale / font_size; 505 data->y_mult = (double) font->y_scale / font_size; 506 507 data->hdc = GetDC (nullptr); 508 509 if (unlikely (!populate_log_font (&data->log_font, font, font_size))) { 510 DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed"); 511 _hb_uniscribe_shaper_font_data_destroy (data); 512 return nullptr; 513 } 514 515 data->hfont = CreateFontIndirectW (&data->log_font); 516 if (unlikely (!data->hfont)) { 517 DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed"); 518 _hb_uniscribe_shaper_font_data_destroy (data); 519 return nullptr; 520 } 521 522 if (!SelectObject (data->hdc, data->hfont)) { 523 DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed"); 524 _hb_uniscribe_shaper_font_data_destroy (data); 525 return nullptr; 526 } 527 528 return data; 529 } 530 531 void 532 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t *data) 533 { 534 if (data->hdc) 535 ReleaseDC (nullptr, data->hdc); 536 if (data->hfont) 537 DeleteObject (data->hfont); 538 if (data->script_cache) 539 ScriptFreeCache (&data->script_cache); 540 hb_free (data); 541 } 542 543 /** 544 * hb_uniscribe_font_get_logfontw: 545 * @font: The #hb_font_t to work upon 546 * 547 * Fetches the LOGFONTW structure that corresponds to the 548 * specified #hb_font_t font. 549 * 550 * Return value: a pointer to the LOGFONTW retrieved 551 * 552 **/ 553 LOGFONTW * 554 hb_uniscribe_font_get_logfontw (hb_font_t *font) 555 { 556 const hb_uniscribe_font_data_t *data = font->data.uniscribe; 557 return data ? &data->log_font : nullptr; 558 } 559 560 /** 561 * hb_uniscribe_font_get_hfont: 562 * @font: The #hb_font_t to work upon 563 * 564 * Fetches the HFONT handle that corresponds to the 565 * specified #hb_font_t font. 566 * 567 * Return value: the HFONT retreieved 568 * 569 **/ 570 HFONT 571 hb_uniscribe_font_get_hfont (hb_font_t *font) 572 { 573 const hb_uniscribe_font_data_t *data = font->data.uniscribe; 574 return data ? data->hfont : nullptr; 575 } 576 577 578 /* 579 * shaper 580 */ 581 582 583 hb_bool_t 584 _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, 585 hb_font_t *font, 586 hb_buffer_t *buffer, 587 const hb_feature_t *features, 588 unsigned int num_features) 589 { 590 hb_face_t *face = font->face; 591 const hb_uniscribe_face_data_t *face_data = face->data.uniscribe; 592 const hb_uniscribe_font_data_t *font_data = font->data.uniscribe; 593 hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs; 594 595 #define FAIL(...) \ 596 HB_STMT_START { \ 597 DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \ 598 return false; \ 599 } HB_STMT_END 600 601 HRESULT hr; 602 603 retry: 604 605 unsigned int scratch_size; 606 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 607 608 #define ALLOCATE_ARRAY(Type, name, len) \ 609 Type *name = (Type *) scratch; \ 610 do { \ 611 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 612 assert (_consumed <= scratch_size); \ 613 scratch += _consumed; \ 614 scratch_size -= _consumed; \ 615 } while (0) 616 617 #define utf16_index() var1.u32 618 619 ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2); 620 621 unsigned int chars_len = 0; 622 for (unsigned int i = 0; i < buffer->len; i++) 623 { 624 hb_codepoint_t c = buffer->info[i].codepoint; 625 buffer->info[i].utf16_index() = chars_len; 626 if (likely (c <= 0xFFFFu)) 627 pchars[chars_len++] = c; 628 else if (unlikely (c > 0x10FFFFu)) 629 pchars[chars_len++] = 0xFFFDu; 630 else { 631 pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); 632 pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1)); 633 } 634 } 635 636 ALLOCATE_ARRAY (WORD, log_clusters, chars_len); 637 ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); 638 639 if (num_features) 640 { 641 /* Need log_clusters to assign features. */ 642 chars_len = 0; 643 for (unsigned int i = 0; i < buffer->len; i++) 644 { 645 hb_codepoint_t c = buffer->info[i].codepoint; 646 unsigned int cluster = buffer->info[i].cluster; 647 log_clusters[chars_len++] = cluster; 648 if (hb_in_range (c, 0x10000u, 0x10FFFFu)) 649 log_clusters[chars_len++] = cluster; /* Surrogates. */ 650 } 651 } 652 653 /* The -2 in the following is to compensate for possible 654 * alignment needed after the WORD array. sizeof(WORD) == 2. */ 655 unsigned int glyphs_size = (scratch_size * sizeof (int) - 2) 656 / (sizeof (WORD) + 657 sizeof (SCRIPT_GLYPHPROP) + 658 sizeof (int) + 659 sizeof (GOFFSET) + 660 sizeof (uint32_t)); 661 662 ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); 663 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); 664 ALLOCATE_ARRAY (int, advances, glyphs_size); 665 ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); 666 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); 667 668 /* Note: 669 * We can't touch the contents of glyph_props. Our fallback 670 * implementations of Shape and Place functions use that buffer 671 * by casting it to a different type. It works because they 672 * both agree about it, but if we want to access it here we 673 * need address that issue first. 674 */ 675 676 #undef ALLOCATE_ARRAY 677 678 #define MAX_ITEMS 256 679 680 SCRIPT_ITEM items[MAX_ITEMS + 1]; 681 SCRIPT_CONTROL bidi_control = {0}; 682 SCRIPT_STATE bidi_state = {0}; 683 ULONG script_tags[MAX_ITEMS]; 684 int item_count; 685 686 /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ 687 //bidi_control.fMergeNeutralItems = true; 688 *(uint32_t*)&bidi_control |= 1u<<24; 689 690 bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 691 bidi_state.fOverrideDirection = 1; 692 693 hr = funcs->ScriptItemizeOpenType (pchars, 694 chars_len, 695 MAX_ITEMS, 696 &bidi_control, 697 &bidi_state, 698 items, 699 script_tags, 700 &item_count); 701 if (unlikely (FAILED (hr))) 702 FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", (unsigned long) hr); 703 704 #undef MAX_ITEMS 705 706 hb_tag_t lang_tag; 707 unsigned int lang_count = 1; 708 hb_ot_tags_from_script_and_language (buffer->props.script, 709 buffer->props.language, 710 nullptr, nullptr, 711 &lang_count, &lang_tag); 712 OPENTYPE_TAG language_tag = hb_uint32_swap (lang_count ? lang_tag : HB_TAG_NONE); 713 714 /* 715 * Set up features. 716 */ 717 static_assert ((sizeof (TEXTRANGE_PROPERTIES) == sizeof (hb_ms_features_t)), ""); 718 static_assert ((sizeof (OPENTYPE_FEATURE_RECORD) == sizeof (hb_ms_feature_t)), ""); 719 hb_vector_t<hb_ms_feature_t> feature_records; 720 hb_vector_t<hb_ms_range_record_t> range_records; 721 bool has_features = false; 722 if (num_features) 723 has_features = hb_ms_setup_features (features, 724 num_features, 725 feature_records, 726 range_records); 727 728 hb_vector_t<hb_ms_features_t*> range_properties; 729 hb_vector_t<uint32_t> range_char_counts; 730 731 unsigned int glyphs_offset = 0; 732 unsigned int glyphs_len; 733 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 734 for (int i = 0; i < item_count; i++) 735 { 736 unsigned int chars_offset = items[i].iCharPos; 737 unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; 738 739 if (has_features) 740 hb_ms_make_feature_ranges (feature_records, 741 range_records, 742 item_chars_len, 743 chars_offset, 744 log_clusters, 745 range_properties, 746 range_char_counts); 747 748 /* Asking for glyphs in logical order circumvents at least 749 * one bug in Uniscribe. */ 750 items[i].a.fLogicalOrder = true; 751 752 retry_shape: 753 hr = funcs->ScriptShapeOpenType (font_data->hdc, 754 &font_data->script_cache, 755 &items[i].a, 756 script_tags[i], 757 language_tag, 758 (int *) range_char_counts.arrayZ, 759 (TEXTRANGE_PROPERTIES**) range_properties.arrayZ, 760 range_properties.length, 761 pchars + chars_offset, 762 item_chars_len, 763 glyphs_size - glyphs_offset, 764 /* out */ 765 log_clusters + chars_offset, 766 char_props + chars_offset, 767 glyphs + glyphs_offset, 768 glyph_props + glyphs_offset, 769 (int *) &glyphs_len); 770 771 if (unlikely (items[i].a.fNoGlyphIndex)) 772 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); 773 if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER)) 774 { 775 if (unlikely (!buffer->ensure (buffer->allocated * 2))) 776 FAIL ("Buffer resize failed"); 777 goto retry; 778 } 779 if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) 780 { 781 if (items[i].a.eScript == SCRIPT_UNDEFINED) 782 FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); 783 items[i].a.eScript = SCRIPT_UNDEFINED; 784 goto retry_shape; 785 } 786 if (unlikely (FAILED (hr))) 787 { 788 FAIL ("ScriptShapeOpenType() failed: 0x%08lx", (unsigned long) hr); 789 } 790 791 for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) 792 log_clusters[j] += glyphs_offset; 793 794 hr = funcs->ScriptPlaceOpenType (font_data->hdc, 795 &font_data->script_cache, 796 &items[i].a, 797 script_tags[i], 798 language_tag, 799 (int *) range_char_counts.arrayZ, 800 (TEXTRANGE_PROPERTIES**) range_properties.arrayZ, 801 range_properties.length, 802 pchars + chars_offset, 803 log_clusters + chars_offset, 804 char_props + chars_offset, 805 item_chars_len, 806 glyphs + glyphs_offset, 807 glyph_props + glyphs_offset, 808 glyphs_len, 809 /* out */ 810 advances + glyphs_offset, 811 offsets + glyphs_offset, 812 nullptr); 813 if (unlikely (FAILED (hr))) 814 FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", (unsigned long) hr); 815 816 if (DEBUG_ENABLED (UNISCRIBE)) 817 fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", 818 i, 819 items[i].a.fRTL, 820 items[i].a.fLayoutRTL, 821 items[i].a.fLogicalOrder, 822 HB_UNTAG (hb_uint32_swap (script_tags[i]))); 823 824 glyphs_offset += glyphs_len; 825 } 826 glyphs_len = glyphs_offset; 827 828 /* Ok, we've got everything we need, now compose output buffer, 829 * very, *very*, carefully! */ 830 831 /* Calculate visual-clusters. That's what we ship. */ 832 for (unsigned int i = 0; i < glyphs_len; i++) 833 vis_clusters[i] = (uint32_t) -1; 834 for (unsigned int i = 0; i < buffer->len; i++) { 835 uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; 836 *p = hb_min (*p, buffer->info[i].cluster); 837 } 838 for (unsigned int i = 1; i < glyphs_len; i++) 839 if (vis_clusters[i] == (uint32_t) -1) 840 vis_clusters[i] = vis_clusters[i - 1]; 841 842 #undef utf16_index 843 844 if (unlikely (!buffer->ensure (glyphs_len))) 845 FAIL ("Buffer in error"); 846 847 #undef FAIL 848 849 /* Set glyph infos */ 850 buffer->len = 0; 851 for (unsigned int i = 0; i < glyphs_len; i++) 852 { 853 hb_glyph_info_t *info = &buffer->info[buffer->len++]; 854 855 info->codepoint = glyphs[i]; 856 info->cluster = vis_clusters[i]; 857 858 /* The rest is crap. Let's store position info there for now. */ 859 info->mask = advances[i]; 860 info->var1.i32 = offsets[i].du; 861 info->var2.i32 = offsets[i].dv; 862 } 863 864 /* Set glyph positions */ 865 buffer->clear_positions (); 866 double x_mult = font_data->x_mult, y_mult = font_data->y_mult; 867 for (unsigned int i = 0; i < glyphs_len; i++) 868 { 869 hb_glyph_info_t *info = &buffer->info[i]; 870 hb_glyph_position_t *pos = &buffer->pos[i]; 871 872 /* TODO vertical */ 873 pos->x_advance = x_mult * (int32_t) info->mask; 874 pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32); 875 pos->y_offset = y_mult * info->var2.i32; 876 } 877 878 if (backward) 879 hb_buffer_reverse (buffer); 880 881 buffer->clear_glyph_flags (); 882 buffer->unsafe_to_break (); 883 884 /* Wow, done! */ 885 return true; 886 } 887 888 889 #endif