hb-uniscribe.cc revision 9a175914d72187d0c3f50ddad50c9569649c3072
1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/* 2baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * Copyright © 2011,2012 Google, Inc. 3cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * 4cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * This is part of HarfBuzz, a text shaping library. 5baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * 6baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * Permission is hereby granted, without written agreement and without 7cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * license or royalty fees, to use, copy, modify, and distribute this 8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * software and its documentation for any purpose, provided that the 9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * above copyright notice and the following two paragraphs appear in 10baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * all copies of this software. 11baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * 12baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * DAMAGE. 17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * 18cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky * 24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * Google Author(s): Behdad Esfahbod 25cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky */ 26cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define _WIN32_WINNT 0x0600 28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#define WIN32_LEAN_AND_MEAN 29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync 30cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#define HB_SHAPER uniscribe 31cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "hb-shaper-impl-private.hh" 32baa3858d3f5d128a5c8466b700098109edcad5f2repo sync 33baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include <windows.h> 34baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include <usp10.h> 35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#include <rpc.h> 36baa3858d3f5d128a5c8466b700098109edcad5f2repo sync 37cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "hb-uniscribe.h" 38baa3858d3f5d128a5c8466b700098109edcad5f2repo sync 39cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "hb-open-file-private.hh" 40cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "hb-ot-name-table.hh" 41cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#include "hb-ot-tag.h" 42cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 43cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 44baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#ifndef HB_DEBUG_UNISCRIBE 45cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) 46baa3858d3f5d128a5c8466b700098109edcad5f2repo sync#endif 47cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 48cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 49cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckytypedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/( 50cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const WCHAR *pwcInChars, 51cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int cInChars, 52cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int cMaxItems, 53cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const SCRIPT_CONTROL *psControl, 54cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky const SCRIPT_STATE *psState, 55cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky SCRIPT_ITEM *pItems, 56cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky OPENTYPE_TAG *pScriptTags, 57cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int *pcItems 58cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky); 59cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 60cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckytypedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/( 61cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky HDC hdc, 62baa3858d3f5d128a5c8466b700098109edcad5f2repo sync SCRIPT_CACHE *psc, 63baa3858d3f5d128a5c8466b700098109edcad5f2repo sync SCRIPT_ANALYSIS *psa, 64baa3858d3f5d128a5c8466b700098109edcad5f2repo sync OPENTYPE_TAG tagScript, 65cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky OPENTYPE_TAG tagLangSys, 66cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int *rcRangeChars, 67cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky TEXTRANGE_PROPERTIES **rpRangeProperties, 68baa3858d3f5d128a5c8466b700098109edcad5f2repo sync int cRanges, 69baa3858d3f5d128a5c8466b700098109edcad5f2repo sync const WCHAR *pwcChars, 70cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int cChars, 71baa3858d3f5d128a5c8466b700098109edcad5f2repo sync int cMaxGlyphs, 72baa3858d3f5d128a5c8466b700098109edcad5f2repo sync WORD *pwLogClust, 73cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky SCRIPT_CHARPROP *pCharProps, 74cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky WORD *pwOutGlyphs, 75cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky SCRIPT_GLYPHPROP *pOutGlyphProps, 76baa3858d3f5d128a5c8466b700098109edcad5f2repo sync int *pcGlyphs 77cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky); 78cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky 79cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbeckytypedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/( 80cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky HDC hdc, 81cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky SCRIPT_CACHE *psc, 82cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky SCRIPT_ANALYSIS *psa, 83cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky OPENTYPE_TAG tagScript, 84cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky OPENTYPE_TAG tagLangSys, 85cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int *rcRangeChars, 86cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky TEXTRANGE_PROPERTIES **rpRangeProperties, 87cd66d540cead3f8200b0c73bad9c276d67896c3dDavid Srbecky int cRanges, 88baa3858d3f5d128a5c8466b700098109edcad5f2repo sync const WCHAR *pwcChars, 89baa3858d3f5d128a5c8466b700098109edcad5f2repo sync WORD *pwLogClust, 90baa3858d3f5d128a5c8466b700098109edcad5f2repo sync 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 103static HRESULT WINAPI 104hb_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 126static HRESULT WINAPI 127hb_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 159static HRESULT WINAPI 160hb_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 194struct 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("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}; 224static hb_uniscribe_shaper_funcs_t *uniscribe_funcs; 225 226static inline void 227free_uniscribe_funcs (void) 228{ 229 free (uniscribe_funcs); 230} 231 232static hb_uniscribe_shaper_funcs_t * 233hb_uniscribe_shaper_get_funcs (void) 234{ 235retry: 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 260struct 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 275struct 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 287struct range_record_t { 288 TEXTRANGE_PROPERTIES props; 289 unsigned int index_first; /* == start */ 290 unsigned int index_last; /* == end - 1 */ 291}; 292 293HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face) 294HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font) 295 296 297/* 298 * shaper face data 299 */ 300 301struct 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. */ 308static 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. */ 337static 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 429hb_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 468void 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 480struct hb_uniscribe_shaper_font_data_t { 481 HDC hdc; 482 LOGFONTW log_font; 483 HFONT hfont; 484 SCRIPT_CACHE script_cache; 485}; 486 487static bool 488populate_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 503hb_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 536void 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 548LOGFONTW * 549hb_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 556HFONT 557hb_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 569struct hb_uniscribe_shaper_shape_plan_data_t {}; 570 571hb_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 579void 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 590hb_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 729retry: 730 731 unsigned int scratch_size; 732 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); 733 734 /* Allocate char buffers; they all fit */ 735 736#define ALLOCATE_ARRAY(Type, name, len) \ 737 Type *name = (Type *) scratch; \ 738 scratch += (len) * sizeof ((name)[0]); \ 739 scratch_size -= (len) * sizeof ((name)[0]); 740 741#define utf16_index() var1.u32 742 743 WCHAR *pchars = (WCHAR *) scratch; 744 unsigned int chars_len = 0; 745 for (unsigned int i = 0; i < buffer->len; i++) 746 { 747 hb_codepoint_t c = buffer->info[i].codepoint; 748 buffer->info[i].utf16_index() = chars_len; 749 if (likely (c < 0x10000)) 750 pchars[chars_len++] = c; 751 else if (unlikely (c >= 0x110000)) 752 pchars[chars_len++] = 0xFFFD; 753 else { 754 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 755 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 756 } 757 } 758 759 ALLOCATE_ARRAY (WCHAR, wchars, chars_len); 760 ALLOCATE_ARRAY (WORD, log_clusters, chars_len); 761 ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); 762 763 if (num_features) 764 { 765 /* Need log_clusters to assign features. */ 766 chars_len = 0; 767 for (unsigned int i = 0; i < buffer->len; i++) 768 { 769 hb_codepoint_t c = buffer->info[i].codepoint; 770 unsigned int cluster = buffer->info[i].cluster; 771 log_clusters[chars_len++] = cluster; 772 if (c >= 0x10000 && c < 0x110000) 773 log_clusters[chars_len++] = cluster; /* Surrogates. */ 774 } 775 } 776 777 /* On Windows, we don't care about alignment...*/ 778 unsigned int glyphs_size = scratch_size / (sizeof (WORD) + 779 sizeof (SCRIPT_GLYPHPROP) + 780 sizeof (int) + 781 sizeof (GOFFSET) + 782 sizeof (uint32_t)); 783 784 ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); 785 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); 786 ALLOCATE_ARRAY (int, advances, glyphs_size); 787 ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); 788 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); 789 790 /* Note: 791 * We can't touch the contents of glyph_props. Our fallback 792 * implementations of Shape and Place functions use that buffer 793 * by casting it to a different type. It works because they 794 * both agree about it, but if we want to access it here we 795 * need address that issue first. 796 */ 797 798#undef ALLOCATE_ARRAY 799 800#define MAX_ITEMS 256 801 802 SCRIPT_ITEM items[MAX_ITEMS + 1]; 803 SCRIPT_CONTROL bidi_control = {0}; 804 SCRIPT_STATE bidi_state = {0}; 805 ULONG script_tags[MAX_ITEMS]; 806 int item_count; 807 808 /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ 809 //bidi_control.fMergeNeutralItems = true; 810 *(uint32_t*)&bidi_control |= 1<<24; 811 812 bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 813 bidi_state.fOverrideDirection = 1; 814 815 hr = funcs->ScriptItemizeOpenType (wchars, 816 chars_len, 817 MAX_ITEMS, 818 &bidi_control, 819 &bidi_state, 820 items, 821 script_tags, 822 &item_count); 823 if (unlikely (FAILED (hr))) 824 FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr); 825 826#undef MAX_ITEMS 827 828 OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language)); 829 hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties; 830 hb_auto_array_t<int> range_char_counts; 831 832 unsigned int glyphs_offset = 0; 833 unsigned int glyphs_len; 834 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 835 for (unsigned int j = 0; j < item_count; j++) 836 { 837 unsigned int i = backward ? item_count - 1 - j : j; 838 unsigned int chars_offset = items[i].iCharPos; 839 unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; 840 841 if (num_features) 842 { 843 range_properties.shrink (0); 844 range_char_counts.shrink (0); 845 846 range_record_t *last_range = &range_records[0]; 847 848 for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++) 849 { 850 range_record_t *range = last_range; 851 while (log_clusters[k] < range->index_first) 852 range--; 853 while (log_clusters[k] > range->index_last) 854 range++; 855 if (!range_properties.len || 856 &range->props != range_properties[range_properties.len - 1]) 857 { 858 TEXTRANGE_PROPERTIES **props = range_properties.push (); 859 int *c = range_char_counts.push (); 860 if (unlikely (!props || !c)) 861 { 862 range_properties.shrink (0); 863 range_char_counts.shrink (0); 864 break; 865 } 866 *props = &range->props; 867 *c = 1; 868 } 869 else 870 { 871 range_char_counts[range_char_counts.len - 1]++; 872 } 873 874 last_range = range; 875 } 876 } 877 878 retry_shape: 879 hr = funcs->ScriptShapeOpenType (font_data->hdc, 880 &font_data->script_cache, 881 &items[i].a, 882 script_tags[i], 883 language_tag, 884 range_char_counts.array, 885 range_properties.array, 886 range_properties.len, 887 wchars + chars_offset, 888 item_chars_len, 889 glyphs_size - glyphs_offset, 890 /* out */ 891 log_clusters + chars_offset, 892 char_props + chars_offset, 893 glyphs + glyphs_offset, 894 glyph_props + glyphs_offset, 895 (int *) &glyphs_len); 896 897 if (unlikely (items[i].a.fNoGlyphIndex)) 898 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); 899 if (unlikely (hr == E_OUTOFMEMORY)) 900 { 901 buffer->ensure (buffer->allocated * 2); 902 if (buffer->in_error) 903 FAIL ("Buffer resize failed"); 904 goto retry; 905 } 906 if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) 907 { 908 if (items[i].a.eScript == SCRIPT_UNDEFINED) 909 FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); 910 items[i].a.eScript = SCRIPT_UNDEFINED; 911 goto retry_shape; 912 } 913 if (unlikely (FAILED (hr))) 914 { 915 FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr); 916 } 917 918 for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) 919 log_clusters[j] += glyphs_offset; 920 921 hr = funcs->ScriptPlaceOpenType (font_data->hdc, 922 &font_data->script_cache, 923 &items[i].a, 924 script_tags[i], 925 language_tag, 926 range_char_counts.array, 927 range_properties.array, 928 range_properties.len, 929 wchars + chars_offset, 930 log_clusters + chars_offset, 931 char_props + chars_offset, 932 item_chars_len, 933 glyphs + glyphs_offset, 934 glyph_props + glyphs_offset, 935 glyphs_len, 936 /* out */ 937 advances + glyphs_offset, 938 offsets + glyphs_offset, 939 NULL); 940 if (unlikely (FAILED (hr))) 941 FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr); 942 943 glyphs_offset += glyphs_len; 944 } 945 glyphs_len = glyphs_offset; 946 947 /* Ok, we've got everything we need, now compose output buffer, 948 * very, *very*, carefully! */ 949 950 /* Calculate visual-clusters. That's what we ship. */ 951 for (unsigned int i = 0; i < glyphs_len; i++) 952 vis_clusters[i] = -1; 953 for (unsigned int i = 0; i < buffer->len; i++) { 954 uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; 955 *p = MIN (*p, buffer->info[i].cluster); 956 } 957 if (!backward) { 958 for (unsigned int i = 1; i < glyphs_len; i++) 959 if (vis_clusters[i] == -1) 960 vis_clusters[i] = vis_clusters[i - 1]; 961 } else { 962 for (int i = glyphs_len - 2; i >= 0; i--) 963 if (vis_clusters[i] == -1) 964 vis_clusters[i] = vis_clusters[i + 1]; 965 } 966 967#undef utf16_index 968 969 buffer->ensure (glyphs_len); 970 if (buffer->in_error) 971 FAIL ("Buffer in error"); 972 973#undef FAIL 974 975 /* Set glyph infos */ 976 buffer->len = 0; 977 for (unsigned int i = 0; i < glyphs_len; i++) 978 { 979 hb_glyph_info_t *info = &buffer->info[buffer->len++]; 980 981 info->codepoint = glyphs[i]; 982 info->cluster = vis_clusters[i]; 983 984 /* The rest is crap. Let's store position info there for now. */ 985 info->mask = advances[i]; 986 info->var1.u32 = offsets[i].du; 987 info->var2.u32 = offsets[i].dv; 988 } 989 990 /* Set glyph positions */ 991 buffer->clear_positions (); 992 for (unsigned int i = 0; i < glyphs_len; i++) 993 { 994 hb_glyph_info_t *info = &buffer->info[i]; 995 hb_glyph_position_t *pos = &buffer->pos[i]; 996 997 /* TODO vertical */ 998 pos->x_advance = info->mask; 999 pos->x_offset = info->var1.u32; 1000 pos->y_offset = info->var2.u32; 1001 } 1002 1003 /* Wow, done! */ 1004 return true; 1005} 1006 1007 1008