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 #define _WIN32_WINNT 0x0600 28 #define WIN32_LEAN_AND_MEAN 29 30 #define HB_SHAPER uniscribe 31 #include "hb-shaper-impl-private.hh" 32 33 #include <windows.h> 34 #include <usp10.h> 35 #include <rpc.h> 36 37 #include "hb-uniscribe.h" 38 39 #include "hb-open-file-private.hh" 40 #include "hb-ot-name-table.hh" 41 #include "hb-ot-tag.h" 42 43 44 #ifndef HB_DEBUG_UNISCRIBE 45 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) 46 #endif 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 = NULL; 203 this->ScriptShapeOpenType = NULL; 204 this->ScriptPlaceOpenType = NULL; 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, NULL, "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 NULL; 243 244 funcs->init (); 245 246 if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) { 247 free (funcs); 248 goto retry; 249 } 250 251 #ifdef HAVE_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 active_feature_t *a, const active_feature_t *b) { 265 return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 : 266 a->order < b->order ? -1 : a->order > b->order ? 1 : 267 a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 : 268 0; 269 } 270 bool operator== (const active_feature_t *f) { 271 return cmp (this, f) == 0; 272 } 273 }; 274 275 struct feature_event_t { 276 unsigned int index; 277 bool start; 278 active_feature_t feature; 279 280 static int cmp (const feature_event_t *a, const feature_event_t *b) { 281 return a->index < b->index ? -1 : a->index > b->index ? 1 : 282 a->start < b->start ? -1 : a->start > b->start ? 1 : 283 active_feature_t::cmp (&a->feature, &b->feature); 284 } 285 }; 286 287 struct range_record_t { 288 TEXTRANGE_PROPERTIES props; 289 unsigned int index_first; /* == start */ 290 unsigned int index_last; /* == end - 1 */ 291 }; 292 293 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face) 294 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font) 295 296 297 /* 298 * shaper face data 299 */ 300 301 struct hb_uniscribe_shaper_face_data_t { 302 HANDLE fh; 303 hb_uniscribe_shaper_funcs_t *funcs; 304 wchar_t face_name[LF_FACESIZE]; 305 }; 306 307 /* face_name should point to a wchar_t[LF_FACESIZE] object. */ 308 static void 309 _hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen) 310 { 311 /* We'll create a private name for the font from a UUID using a simple, 312 * somewhat base64-like encoding scheme */ 313 const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; 314 UUID id; 315 UuidCreate ((UUID*) &id); 316 unsigned int name_str_len = 0; 317 face_name[name_str_len++] = 'F'; 318 face_name[name_str_len++] = '_'; 319 unsigned char *p = (unsigned char *) &id; 320 for (unsigned int i = 0; i < 16; i += 2) 321 { 322 /* Spread the 16 bits from two bytes of the UUID across three chars of face_name, 323 * using the bits in groups of 5,5,6 to select chars from enc. 324 * This will generate 24 characters; with the 'F_' prefix we already provided, 325 * the name will be 26 chars (plus the NUL terminator), so will always fit within 326 * face_name (LF_FACESIZE = 32). */ 327 face_name[name_str_len++] = enc[p[i] >> 3]; 328 face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f]; 329 face_name[name_str_len++] = enc[p[i + 1] & 0x3f]; 330 } 331 face_name[name_str_len] = 0; 332 if (plen) 333 *plen = name_str_len; 334 } 335 336 /* Destroys blob. */ 337 static hb_blob_t * 338 _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) 339 { 340 /* Create a copy of the font data, with the 'name' table replaced by a 341 * table that names the font with our private F_* name created above. 342 * For simplicity, we just append a new 'name' table and update the 343 * sfnt directory; the original table is left in place, but unused. 344 * 345 * The new table will contain just 5 name IDs: family, style, unique, 346 * full, PS. All of them point to the same name data with our unique name. 347 */ 348 349 blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob); 350 351 unsigned int length, new_length, name_str_len; 352 const char *orig_sfnt_data = hb_blob_get_data (blob, &length); 353 354 _hb_generate_unique_face_name (new_name, &name_str_len); 355 356 static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 }; 357 358 unsigned int name_table_length = OT::name::min_size + 359 ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size + 360 name_str_len * 2; /* for name data in UTF16BE form */ 361 unsigned int name_table_offset = (length + 3) & ~3; 362 363 new_length = name_table_offset + ((name_table_length + 3) & ~3); 364 void *new_sfnt_data = calloc (1, new_length); 365 if (!new_sfnt_data) 366 { 367 hb_blob_destroy (blob); 368 return NULL; 369 } 370 371 memcpy(new_sfnt_data, orig_sfnt_data, length); 372 373 OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset); 374 name.format.set (0); 375 name.count.set (ARRAY_LENGTH (name_IDs)); 376 name.stringOffset.set (name.get_size ()); 377 for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++) 378 { 379 OT::NameRecord &record = name.nameRecord[i]; 380 record.platformID.set (3); 381 record.encodingID.set (1); 382 record.languageID.set (0x0409); /* English */ 383 record.nameID.set (name_IDs[i]); 384 record.length.set (name_str_len * 2); 385 record.offset.set (0); 386 } 387 388 /* Copy string data from new_name, converting wchar_t to UTF16BE. */ 389 unsigned char *p = &OT::StructAfter<unsigned char> (name); 390 for (unsigned int i = 0; i < name_str_len; i++) 391 { 392 *p++ = new_name[i] >> 8; 393 *p++ = new_name[i] & 0xff; 394 } 395 396 /* Adjust name table entry to point to new name table */ 397 const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data); 398 unsigned int face_count = file.get_face_count (); 399 for (unsigned int face_index = 0; face_index < face_count; face_index++) 400 { 401 /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be 402 * toe-stepping. But we don't really care. */ 403 const OT::OpenTypeFontFace &face = file.get_face (face_index); 404 unsigned int index; 405 if (face.find_table_index (HB_OT_TAG_name, &index)) 406 { 407 OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index)); 408 record.checkSum.set_for_data (&name, name_table_length); 409 record.offset.set (name_table_offset); 410 record.length.set (name_table_length); 411 } 412 else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */ 413 { 414 free (new_sfnt_data); 415 hb_blob_destroy (blob); 416 return NULL; 417 } 418 } 419 420 /* The checkSumAdjustment field in the 'head' table is now wrong, 421 * but that doesn't actually seem to cause any problems so we don't 422 * bother. */ 423 424 hb_blob_destroy (blob); 425 return hb_blob_create ((const char *) new_sfnt_data, new_length, 426 HB_MEMORY_MODE_WRITABLE, NULL, free); 427 } 428 429 hb_uniscribe_shaper_face_data_t * 430 _hb_uniscribe_shaper_face_data_create (hb_face_t *face) 431 { 432 hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t)); 433 if (unlikely (!data)) 434 return NULL; 435 436 data->funcs = hb_uniscribe_shaper_get_funcs (); 437 if (unlikely (!data->funcs)) 438 { 439 free (data); 440 return NULL; 441 } 442 443 hb_blob_t *blob = hb_face_reference_blob (face); 444 if (unlikely (!hb_blob_get_length (blob))) 445 DEBUG_MSG (UNISCRIBE, face, "Face has empty blob"); 446 447 blob = _hb_rename_font (blob, data->face_name); 448 if (unlikely (!blob)) 449 { 450 free (data); 451 return NULL; 452 } 453 454 DWORD num_fonts_installed; 455 data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL), 456 hb_blob_get_length (blob), 457 0, &num_fonts_installed); 458 if (unlikely (!data->fh)) 459 { 460 DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed"); 461 free (data); 462 return NULL; 463 } 464 465 return data; 466 } 467 468 void 469 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data) 470 { 471 RemoveFontMemResourceEx (data->fh); 472 free (data); 473 } 474 475 476 /* 477 * shaper font data 478 */ 479 480 struct hb_uniscribe_shaper_font_data_t { 481 HDC hdc; 482 LOGFONTW log_font; 483 HFONT hfont; 484 SCRIPT_CACHE script_cache; 485 }; 486 487 static bool 488 populate_log_font (LOGFONTW *lf, 489 hb_font_t *font) 490 { 491 memset (lf, 0, sizeof (*lf)); 492 lf->lfHeight = -font->y_scale; 493 lf->lfCharSet = DEFAULT_CHARSET; 494 495 hb_face_t *face = font->face; 496 hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 497 498 memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName)); 499 500 return true; 501 } 502 503 hb_uniscribe_shaper_font_data_t * 504 _hb_uniscribe_shaper_font_data_create (hb_font_t *font) 505 { 506 if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL; 507 508 hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t)); 509 if (unlikely (!data)) 510 return NULL; 511 512 data->hdc = GetDC (NULL); 513 514 if (unlikely (!populate_log_font (&data->log_font, font))) { 515 DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed"); 516 _hb_uniscribe_shaper_font_data_destroy (data); 517 return NULL; 518 } 519 520 data->hfont = CreateFontIndirectW (&data->log_font); 521 if (unlikely (!data->hfont)) { 522 DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed"); 523 _hb_uniscribe_shaper_font_data_destroy (data); 524 return NULL; 525 } 526 527 if (!SelectObject (data->hdc, data->hfont)) { 528 DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed"); 529 _hb_uniscribe_shaper_font_data_destroy (data); 530 return NULL; 531 } 532 533 return data; 534 } 535 536 void 537 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data) 538 { 539 if (data->hdc) 540 ReleaseDC (NULL, data->hdc); 541 if (data->hfont) 542 DeleteObject (data->hfont); 543 if (data->script_cache) 544 ScriptFreeCache (&data->script_cache); 545 free (data); 546 } 547 548 LOGFONTW * 549 hb_uniscribe_font_get_logfontw (hb_font_t *font) 550 { 551 if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; 552 hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 553 return &font_data->log_font; 554 } 555 556 HFONT 557 hb_uniscribe_font_get_hfont (hb_font_t *font) 558 { 559 if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; 560 hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 561 return font_data->hfont; 562 } 563 564 565 /* 566 * shaper shape_plan data 567 */ 568 569 struct hb_uniscribe_shaper_shape_plan_data_t {}; 570 571 hb_uniscribe_shaper_shape_plan_data_t * 572 _hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 573 const hb_feature_t *user_features HB_UNUSED, 574 unsigned int num_user_features HB_UNUSED) 575 { 576 return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 577 } 578 579 void 580 _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED) 581 { 582 } 583 584 585 /* 586 * shaper 587 */ 588 589 590 hb_bool_t 591 _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, 592 hb_font_t *font, 593 hb_buffer_t *buffer, 594 const hb_feature_t *features, 595 unsigned int num_features) 596 { 597 hb_face_t *face = font->face; 598 hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 599 hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 600 hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs; 601 602 /* 603 * Set up features. 604 */ 605 hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records; 606 hb_auto_array_t<range_record_t> range_records; 607 if (num_features) 608 { 609 /* Sort features by start/end events. */ 610 hb_auto_array_t<feature_event_t> feature_events; 611 for (unsigned int i = 0; i < num_features; i++) 612 { 613 active_feature_t feature; 614 feature.rec.tagFeature = hb_uint32_swap (features[i].tag); 615 feature.rec.lParameter = features[i].value; 616 feature.order = i; 617 618 feature_event_t *event; 619 620 event = feature_events.push (); 621 if (unlikely (!event)) 622 goto fail_features; 623 event->index = features[i].start; 624 event->start = true; 625 event->feature = feature; 626 627 event = feature_events.push (); 628 if (unlikely (!event)) 629 goto fail_features; 630 event->index = features[i].end; 631 event->start = false; 632 event->feature = feature; 633 } 634 feature_events.sort (); 635 /* Add a strategic final event. */ 636 { 637 active_feature_t feature; 638 feature.rec.tagFeature = 0; 639 feature.rec.lParameter = 0; 640 feature.order = num_features + 1; 641 642 feature_event_t *event = feature_events.push (); 643 if (unlikely (!event)) 644 goto fail_features; 645 event->index = 0; /* This value does magic. */ 646 event->start = false; 647 event->feature = feature; 648 } 649 650 /* Scan events and save features for each range. */ 651 hb_auto_array_t<active_feature_t> active_features; 652 unsigned int last_index = 0; 653 for (unsigned int i = 0; i < feature_events.len; i++) 654 { 655 feature_event_t *event = &feature_events[i]; 656 657 if (event->index != last_index) 658 { 659 /* Save a snapshot of active features and the range. */ 660 range_record_t *range = range_records.push (); 661 if (unlikely (!range)) 662 goto fail_features; 663 664 unsigned int offset = feature_records.len; 665 666 active_features.sort (); 667 for (unsigned int j = 0; j < active_features.len; j++) 668 { 669 if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature) 670 { 671 OPENTYPE_FEATURE_RECORD *feature = feature_records.push (); 672 if (unlikely (!feature)) 673 goto fail_features; 674 *feature = active_features[j].rec; 675 } 676 else 677 { 678 /* Overrides value for existing feature. */ 679 feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter; 680 } 681 } 682 683 /* Will convert to pointer after all is ready, since feature_records.array 684 * may move as we grow it. */ 685 range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset); 686 range->props.cotfRecords = feature_records.len - offset; 687 range->index_first = last_index; 688 range->index_last = event->index - 1; 689 690 last_index = event->index; 691 } 692 693 if (event->start) { 694 active_feature_t *feature = active_features.push (); 695 if (unlikely (!feature)) 696 goto fail_features; 697 *feature = event->feature; 698 } else { 699 active_feature_t *feature = active_features.find (&event->feature); 700 if (feature) 701 active_features.remove (feature - active_features.array); 702 } 703 } 704 705 if (!range_records.len) /* No active feature found. */ 706 goto fail_features; 707 708 /* Fixup the pointers. */ 709 for (unsigned int i = 0; i < range_records.len; i++) 710 { 711 range_record_t *range = &range_records[i]; 712 range->props.potfRecords = feature_records.array + reinterpret_cast<unsigned int> (range->props.potfRecords); 713 } 714 } 715 else 716 { 717 fail_features: 718 num_features = 0; 719 } 720 721 #define FAIL(...) \ 722 HB_STMT_START { \ 723 DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \ 724 return false; \ 725 } HB_STMT_END; 726 727 HRESULT hr; 728 729 retry: 730 731 unsigned int scratch_size; 732 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 733 734 #define ALLOCATE_ARRAY(Type, name, len) \ 735 Type *name = (Type *) scratch; \ 736 { \ 737 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 738 assert (_consumed <= scratch_size); \ 739 scratch += _consumed; \ 740 scratch_size -= _consumed; \ 741 } 742 743 #define utf16_index() var1.u32 744 745 ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2); 746 747 unsigned int chars_len = 0; 748 for (unsigned int i = 0; i < buffer->len; i++) 749 { 750 hb_codepoint_t c = buffer->info[i].codepoint; 751 buffer->info[i].utf16_index() = chars_len; 752 if (likely (c < 0x10000)) 753 pchars[chars_len++] = c; 754 else if (unlikely (c >= 0x110000)) 755 pchars[chars_len++] = 0xFFFD; 756 else { 757 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 758 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 759 } 760 } 761 762 ALLOCATE_ARRAY (WORD, log_clusters, chars_len); 763 ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); 764 765 if (num_features) 766 { 767 /* Need log_clusters to assign features. */ 768 chars_len = 0; 769 for (unsigned int i = 0; i < buffer->len; i++) 770 { 771 hb_codepoint_t c = buffer->info[i].codepoint; 772 unsigned int cluster = buffer->info[i].cluster; 773 log_clusters[chars_len++] = cluster; 774 if (c >= 0x10000 && c < 0x110000) 775 log_clusters[chars_len++] = cluster; /* Surrogates. */ 776 } 777 } 778 779 /* All the following types are sized in multiples of sizeof(int). */ 780 unsigned int glyphs_size = scratch_size / ((sizeof (WORD) + 781 sizeof (SCRIPT_GLYPHPROP) + 782 sizeof (int) + 783 sizeof (GOFFSET) + 784 sizeof (uint32_t)) 785 / sizeof (int)); 786 787 ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); 788 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); 789 ALLOCATE_ARRAY (int, advances, glyphs_size); 790 ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); 791 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); 792 793 /* Note: 794 * We can't touch the contents of glyph_props. Our fallback 795 * implementations of Shape and Place functions use that buffer 796 * by casting it to a different type. It works because they 797 * both agree about it, but if we want to access it here we 798 * need address that issue first. 799 */ 800 801 #undef ALLOCATE_ARRAY 802 803 #define MAX_ITEMS 256 804 805 SCRIPT_ITEM items[MAX_ITEMS + 1]; 806 SCRIPT_CONTROL bidi_control = {0}; 807 SCRIPT_STATE bidi_state = {0}; 808 ULONG script_tags[MAX_ITEMS]; 809 int item_count; 810 811 /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ 812 //bidi_control.fMergeNeutralItems = true; 813 *(uint32_t*)&bidi_control |= 1<<24; 814 815 bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 816 bidi_state.fOverrideDirection = 1; 817 818 hr = funcs->ScriptItemizeOpenType (pchars, 819 chars_len, 820 MAX_ITEMS, 821 &bidi_control, 822 &bidi_state, 823 items, 824 script_tags, 825 &item_count); 826 if (unlikely (FAILED (hr))) 827 FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr); 828 829 #undef MAX_ITEMS 830 831 OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language)); 832 hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties; 833 hb_auto_array_t<int> range_char_counts; 834 835 unsigned int glyphs_offset = 0; 836 unsigned int glyphs_len; 837 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 838 for (unsigned int i = 0; i < item_count; i++) 839 { 840 unsigned int chars_offset = items[i].iCharPos; 841 unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; 842 843 if (num_features) 844 { 845 range_properties.shrink (0); 846 range_char_counts.shrink (0); 847 848 range_record_t *last_range = &range_records[0]; 849 850 for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++) 851 { 852 range_record_t *range = last_range; 853 while (log_clusters[k] < range->index_first) 854 range--; 855 while (log_clusters[k] > range->index_last) 856 range++; 857 if (!range_properties.len || 858 &range->props != range_properties[range_properties.len - 1]) 859 { 860 TEXTRANGE_PROPERTIES **props = range_properties.push (); 861 int *c = range_char_counts.push (); 862 if (unlikely (!props || !c)) 863 { 864 range_properties.shrink (0); 865 range_char_counts.shrink (0); 866 break; 867 } 868 *props = &range->props; 869 *c = 1; 870 } 871 else 872 { 873 range_char_counts[range_char_counts.len - 1]++; 874 } 875 876 last_range = range; 877 } 878 } 879 880 /* Asking for glyphs in logical order circumvents at least 881 * one bug in Uniscribe. */ 882 items[i].a.fLogicalOrder = true; 883 884 retry_shape: 885 hr = funcs->ScriptShapeOpenType (font_data->hdc, 886 &font_data->script_cache, 887 &items[i].a, 888 script_tags[i], 889 language_tag, 890 range_char_counts.array, 891 range_properties.array, 892 range_properties.len, 893 pchars + chars_offset, 894 item_chars_len, 895 glyphs_size - glyphs_offset, 896 /* out */ 897 log_clusters + chars_offset, 898 char_props + chars_offset, 899 glyphs + glyphs_offset, 900 glyph_props + glyphs_offset, 901 (int *) &glyphs_len); 902 903 if (unlikely (items[i].a.fNoGlyphIndex)) 904 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); 905 if (unlikely (hr == E_OUTOFMEMORY)) 906 { 907 buffer->ensure (buffer->allocated * 2); 908 if (buffer->in_error) 909 FAIL ("Buffer resize failed"); 910 goto retry; 911 } 912 if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) 913 { 914 if (items[i].a.eScript == SCRIPT_UNDEFINED) 915 FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); 916 items[i].a.eScript = SCRIPT_UNDEFINED; 917 goto retry_shape; 918 } 919 if (unlikely (FAILED (hr))) 920 { 921 FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr); 922 } 923 924 for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) 925 log_clusters[j] += glyphs_offset; 926 927 hr = funcs->ScriptPlaceOpenType (font_data->hdc, 928 &font_data->script_cache, 929 &items[i].a, 930 script_tags[i], 931 language_tag, 932 range_char_counts.array, 933 range_properties.array, 934 range_properties.len, 935 pchars + chars_offset, 936 log_clusters + chars_offset, 937 char_props + chars_offset, 938 item_chars_len, 939 glyphs + glyphs_offset, 940 glyph_props + glyphs_offset, 941 glyphs_len, 942 /* out */ 943 advances + glyphs_offset, 944 offsets + glyphs_offset, 945 NULL); 946 if (unlikely (FAILED (hr))) 947 FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr); 948 949 if (DEBUG_ENABLED (UNISCRIBE)) 950 fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", 951 i, 952 items[i].a.fRTL, 953 items[i].a.fLayoutRTL, 954 items[i].a.fLogicalOrder, 955 HB_UNTAG (hb_uint32_swap (script_tags[i]))); 956 957 glyphs_offset += glyphs_len; 958 } 959 glyphs_len = glyphs_offset; 960 961 /* Ok, we've got everything we need, now compose output buffer, 962 * very, *very*, carefully! */ 963 964 /* Calculate visual-clusters. That's what we ship. */ 965 for (unsigned int i = 0; i < glyphs_len; i++) 966 vis_clusters[i] = -1; 967 for (unsigned int i = 0; i < buffer->len; i++) { 968 uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; 969 *p = MIN (*p, buffer->info[i].cluster); 970 } 971 for (unsigned int i = 1; i < glyphs_len; i++) 972 if (vis_clusters[i] == -1) 973 vis_clusters[i] = vis_clusters[i - 1]; 974 975 #undef utf16_index 976 977 buffer->ensure (glyphs_len); 978 if (buffer->in_error) 979 FAIL ("Buffer in error"); 980 981 #undef FAIL 982 983 /* Set glyph infos */ 984 buffer->len = 0; 985 for (unsigned int i = 0; i < glyphs_len; i++) 986 { 987 hb_glyph_info_t *info = &buffer->info[buffer->len++]; 988 989 info->codepoint = glyphs[i]; 990 info->cluster = vis_clusters[i]; 991 992 /* The rest is crap. Let's store position info there for now. */ 993 info->mask = advances[i]; 994 info->var1.u32 = offsets[i].du; 995 info->var2.u32 = offsets[i].dv; 996 } 997 998 /* Set glyph positions */ 999 buffer->clear_positions (); 1000 for (unsigned int i = 0; i < glyphs_len; i++) 1001 { 1002 hb_glyph_info_t *info = &buffer->info[i]; 1003 hb_glyph_position_t *pos = &buffer->pos[i]; 1004 1005 /* TODO vertical */ 1006 pos->x_advance = info->mask; 1007 pos->x_offset = backward ? -info->var1.u32 : info->var1.u32; 1008 pos->y_offset = info->var2.u32; 1009 } 1010 1011 if (backward) 1012 hb_buffer_reverse (buffer); 1013 1014 /* Wow, done! */ 1015 return true; 1016 } 1017 1018 1019