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