1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-uniscribe.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1019 @@ 1.4 +/* 1.5 + * Copyright © 2011,2012,2013 Google, Inc. 1.6 + * 1.7 + * This is part of HarfBuzz, a text shaping library. 1.8 + * 1.9 + * Permission is hereby granted, without written agreement and without 1.10 + * license or royalty fees, to use, copy, modify, and distribute this 1.11 + * software and its documentation for any purpose, provided that the 1.12 + * above copyright notice and the following two paragraphs appear in 1.13 + * all copies of this software. 1.14 + * 1.15 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.16 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.17 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.18 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.19 + * DAMAGE. 1.20 + * 1.21 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.22 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.23 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.24 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.25 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.26 + * 1.27 + * Google Author(s): Behdad Esfahbod 1.28 + */ 1.29 + 1.30 +#define _WIN32_WINNT 0x0600 1.31 +#define WIN32_LEAN_AND_MEAN 1.32 + 1.33 +#define HB_SHAPER uniscribe 1.34 +#include "hb-shaper-impl-private.hh" 1.35 + 1.36 +#include <windows.h> 1.37 +#include <usp10.h> 1.38 +#include <rpc.h> 1.39 + 1.40 +#include "hb-uniscribe.h" 1.41 + 1.42 +#include "hb-open-file-private.hh" 1.43 +#include "hb-ot-name-table.hh" 1.44 +#include "hb-ot-tag.h" 1.45 + 1.46 + 1.47 +#ifndef HB_DEBUG_UNISCRIBE 1.48 +#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) 1.49 +#endif 1.50 + 1.51 + 1.52 +typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/( 1.53 + const WCHAR *pwcInChars, 1.54 + int cInChars, 1.55 + int cMaxItems, 1.56 + const SCRIPT_CONTROL *psControl, 1.57 + const SCRIPT_STATE *psState, 1.58 + SCRIPT_ITEM *pItems, 1.59 + OPENTYPE_TAG *pScriptTags, 1.60 + int *pcItems 1.61 +); 1.62 + 1.63 +typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/( 1.64 + HDC hdc, 1.65 + SCRIPT_CACHE *psc, 1.66 + SCRIPT_ANALYSIS *psa, 1.67 + OPENTYPE_TAG tagScript, 1.68 + OPENTYPE_TAG tagLangSys, 1.69 + int *rcRangeChars, 1.70 + TEXTRANGE_PROPERTIES **rpRangeProperties, 1.71 + int cRanges, 1.72 + const WCHAR *pwcChars, 1.73 + int cChars, 1.74 + int cMaxGlyphs, 1.75 + WORD *pwLogClust, 1.76 + SCRIPT_CHARPROP *pCharProps, 1.77 + WORD *pwOutGlyphs, 1.78 + SCRIPT_GLYPHPROP *pOutGlyphProps, 1.79 + int *pcGlyphs 1.80 +); 1.81 + 1.82 +typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/( 1.83 + HDC hdc, 1.84 + SCRIPT_CACHE *psc, 1.85 + SCRIPT_ANALYSIS *psa, 1.86 + OPENTYPE_TAG tagScript, 1.87 + OPENTYPE_TAG tagLangSys, 1.88 + int *rcRangeChars, 1.89 + TEXTRANGE_PROPERTIES **rpRangeProperties, 1.90 + int cRanges, 1.91 + const WCHAR *pwcChars, 1.92 + WORD *pwLogClust, 1.93 + SCRIPT_CHARPROP *pCharProps, 1.94 + int cChars, 1.95 + const WORD *pwGlyphs, 1.96 + const SCRIPT_GLYPHPROP *pGlyphProps, 1.97 + int cGlyphs, 1.98 + int *piAdvance, 1.99 + GOFFSET *pGoffset, 1.100 + ABC *pABC 1.101 +); 1.102 + 1.103 + 1.104 +/* Fallback implementations. */ 1.105 + 1.106 +static HRESULT WINAPI 1.107 +hb_ScriptItemizeOpenType( 1.108 + const WCHAR *pwcInChars, 1.109 + int cInChars, 1.110 + int cMaxItems, 1.111 + const SCRIPT_CONTROL *psControl, 1.112 + const SCRIPT_STATE *psState, 1.113 + SCRIPT_ITEM *pItems, 1.114 + OPENTYPE_TAG *pScriptTags, 1.115 + int *pcItems 1.116 +) 1.117 +{ 1.118 +{ 1.119 + return ScriptItemize (pwcInChars, 1.120 + cInChars, 1.121 + cMaxItems, 1.122 + psControl, 1.123 + psState, 1.124 + pItems, 1.125 + pcItems); 1.126 +} 1.127 +} 1.128 + 1.129 +static HRESULT WINAPI 1.130 +hb_ScriptShapeOpenType( 1.131 + HDC hdc, 1.132 + SCRIPT_CACHE *psc, 1.133 + SCRIPT_ANALYSIS *psa, 1.134 + OPENTYPE_TAG tagScript, 1.135 + OPENTYPE_TAG tagLangSys, 1.136 + int *rcRangeChars, 1.137 + TEXTRANGE_PROPERTIES **rpRangeProperties, 1.138 + int cRanges, 1.139 + const WCHAR *pwcChars, 1.140 + int cChars, 1.141 + int cMaxGlyphs, 1.142 + WORD *pwLogClust, 1.143 + SCRIPT_CHARPROP *pCharProps, 1.144 + WORD *pwOutGlyphs, 1.145 + SCRIPT_GLYPHPROP *pOutGlyphProps, 1.146 + int *pcGlyphs 1.147 +) 1.148 +{ 1.149 + SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps; 1.150 + return ScriptShape (hdc, 1.151 + psc, 1.152 + pwcChars, 1.153 + cChars, 1.154 + cMaxGlyphs, 1.155 + psa, 1.156 + pwOutGlyphs, 1.157 + pwLogClust, 1.158 + psva, 1.159 + pcGlyphs); 1.160 +} 1.161 + 1.162 +static HRESULT WINAPI 1.163 +hb_ScriptPlaceOpenType( 1.164 + HDC hdc, 1.165 + SCRIPT_CACHE *psc, 1.166 + SCRIPT_ANALYSIS *psa, 1.167 + OPENTYPE_TAG tagScript, 1.168 + OPENTYPE_TAG tagLangSys, 1.169 + int *rcRangeChars, 1.170 + TEXTRANGE_PROPERTIES **rpRangeProperties, 1.171 + int cRanges, 1.172 + const WCHAR *pwcChars, 1.173 + WORD *pwLogClust, 1.174 + SCRIPT_CHARPROP *pCharProps, 1.175 + int cChars, 1.176 + const WORD *pwGlyphs, 1.177 + const SCRIPT_GLYPHPROP *pGlyphProps, 1.178 + int cGlyphs, 1.179 + int *piAdvance, 1.180 + GOFFSET *pGoffset, 1.181 + ABC *pABC 1.182 +) 1.183 +{ 1.184 + SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps; 1.185 + return ScriptPlace (hdc, 1.186 + psc, 1.187 + pwGlyphs, 1.188 + cGlyphs, 1.189 + psva, 1.190 + psa, 1.191 + piAdvance, 1.192 + pGoffset, 1.193 + pABC); 1.194 +} 1.195 + 1.196 + 1.197 +struct hb_uniscribe_shaper_funcs_t { 1.198 + SIOT ScriptItemizeOpenType; 1.199 + SSOT ScriptShapeOpenType; 1.200 + SPOT ScriptPlaceOpenType; 1.201 + 1.202 + inline void init (void) 1.203 + { 1.204 + HMODULE hinstLib; 1.205 + this->ScriptItemizeOpenType = NULL; 1.206 + this->ScriptShapeOpenType = NULL; 1.207 + this->ScriptPlaceOpenType = NULL; 1.208 + 1.209 + hinstLib = GetModuleHandle (TEXT ("usp10.dll")); 1.210 + if (hinstLib) 1.211 + { 1.212 + this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType"); 1.213 + this->ScriptShapeOpenType = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType"); 1.214 + this->ScriptPlaceOpenType = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType"); 1.215 + } 1.216 + if (!this->ScriptItemizeOpenType || 1.217 + !this->ScriptShapeOpenType || 1.218 + !this->ScriptPlaceOpenType) 1.219 + { 1.220 + DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back."); 1.221 + this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType; 1.222 + this->ScriptShapeOpenType = hb_ScriptShapeOpenType; 1.223 + this->ScriptPlaceOpenType = hb_ScriptPlaceOpenType; 1.224 + } 1.225 + } 1.226 +}; 1.227 +static hb_uniscribe_shaper_funcs_t *uniscribe_funcs; 1.228 + 1.229 +static inline void 1.230 +free_uniscribe_funcs (void) 1.231 +{ 1.232 + free (uniscribe_funcs); 1.233 +} 1.234 + 1.235 +static hb_uniscribe_shaper_funcs_t * 1.236 +hb_uniscribe_shaper_get_funcs (void) 1.237 +{ 1.238 +retry: 1.239 + hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs); 1.240 + 1.241 + if (unlikely (!funcs)) 1.242 + { 1.243 + funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t)); 1.244 + if (unlikely (!funcs)) 1.245 + return NULL; 1.246 + 1.247 + funcs->init (); 1.248 + 1.249 + if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) { 1.250 + free (funcs); 1.251 + goto retry; 1.252 + } 1.253 + 1.254 +#ifdef HAVE_ATEXIT 1.255 + atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */ 1.256 +#endif 1.257 + } 1.258 + 1.259 + return funcs; 1.260 +} 1.261 + 1.262 + 1.263 +struct active_feature_t { 1.264 + OPENTYPE_FEATURE_RECORD rec; 1.265 + unsigned int order; 1.266 + 1.267 + static int cmp (const active_feature_t *a, const active_feature_t *b) { 1.268 + return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 : 1.269 + a->order < b->order ? -1 : a->order > b->order ? 1 : 1.270 + a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 : 1.271 + 0; 1.272 + } 1.273 + bool operator== (const active_feature_t *f) { 1.274 + return cmp (this, f) == 0; 1.275 + } 1.276 +}; 1.277 + 1.278 +struct feature_event_t { 1.279 + unsigned int index; 1.280 + bool start; 1.281 + active_feature_t feature; 1.282 + 1.283 + static int cmp (const feature_event_t *a, const feature_event_t *b) { 1.284 + return a->index < b->index ? -1 : a->index > b->index ? 1 : 1.285 + a->start < b->start ? -1 : a->start > b->start ? 1 : 1.286 + active_feature_t::cmp (&a->feature, &b->feature); 1.287 + } 1.288 +}; 1.289 + 1.290 +struct range_record_t { 1.291 + TEXTRANGE_PROPERTIES props; 1.292 + unsigned int index_first; /* == start */ 1.293 + unsigned int index_last; /* == end - 1 */ 1.294 +}; 1.295 + 1.296 +HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face) 1.297 +HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font) 1.298 + 1.299 + 1.300 +/* 1.301 + * shaper face data 1.302 + */ 1.303 + 1.304 +struct hb_uniscribe_shaper_face_data_t { 1.305 + HANDLE fh; 1.306 + hb_uniscribe_shaper_funcs_t *funcs; 1.307 + wchar_t face_name[LF_FACESIZE]; 1.308 +}; 1.309 + 1.310 +/* face_name should point to a wchar_t[LF_FACESIZE] object. */ 1.311 +static void 1.312 +_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen) 1.313 +{ 1.314 + /* We'll create a private name for the font from a UUID using a simple, 1.315 + * somewhat base64-like encoding scheme */ 1.316 + const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; 1.317 + UUID id; 1.318 + UuidCreate ((UUID*) &id); 1.319 + unsigned int name_str_len = 0; 1.320 + face_name[name_str_len++] = 'F'; 1.321 + face_name[name_str_len++] = '_'; 1.322 + unsigned char *p = (unsigned char *) &id; 1.323 + for (unsigned int i = 0; i < 16; i += 2) 1.324 + { 1.325 + /* Spread the 16 bits from two bytes of the UUID across three chars of face_name, 1.326 + * using the bits in groups of 5,5,6 to select chars from enc. 1.327 + * This will generate 24 characters; with the 'F_' prefix we already provided, 1.328 + * the name will be 26 chars (plus the NUL terminator), so will always fit within 1.329 + * face_name (LF_FACESIZE = 32). */ 1.330 + face_name[name_str_len++] = enc[p[i] >> 3]; 1.331 + face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f]; 1.332 + face_name[name_str_len++] = enc[p[i + 1] & 0x3f]; 1.333 + } 1.334 + face_name[name_str_len] = 0; 1.335 + if (plen) 1.336 + *plen = name_str_len; 1.337 +} 1.338 + 1.339 +/* Destroys blob. */ 1.340 +static hb_blob_t * 1.341 +_hb_rename_font (hb_blob_t *blob, wchar_t *new_name) 1.342 +{ 1.343 + /* Create a copy of the font data, with the 'name' table replaced by a 1.344 + * table that names the font with our private F_* name created above. 1.345 + * For simplicity, we just append a new 'name' table and update the 1.346 + * sfnt directory; the original table is left in place, but unused. 1.347 + * 1.348 + * The new table will contain just 5 name IDs: family, style, unique, 1.349 + * full, PS. All of them point to the same name data with our unique name. 1.350 + */ 1.351 + 1.352 + blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob); 1.353 + 1.354 + unsigned int length, new_length, name_str_len; 1.355 + const char *orig_sfnt_data = hb_blob_get_data (blob, &length); 1.356 + 1.357 + _hb_generate_unique_face_name (new_name, &name_str_len); 1.358 + 1.359 + static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 }; 1.360 + 1.361 + unsigned int name_table_length = OT::name::min_size + 1.362 + ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size + 1.363 + name_str_len * 2; /* for name data in UTF16BE form */ 1.364 + unsigned int name_table_offset = (length + 3) & ~3; 1.365 + 1.366 + new_length = name_table_offset + ((name_table_length + 3) & ~3); 1.367 + void *new_sfnt_data = calloc (1, new_length); 1.368 + if (!new_sfnt_data) 1.369 + { 1.370 + hb_blob_destroy (blob); 1.371 + return NULL; 1.372 + } 1.373 + 1.374 + memcpy(new_sfnt_data, orig_sfnt_data, length); 1.375 + 1.376 + OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset); 1.377 + name.format.set (0); 1.378 + name.count.set (ARRAY_LENGTH (name_IDs)); 1.379 + name.stringOffset.set (name.get_size ()); 1.380 + for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++) 1.381 + { 1.382 + OT::NameRecord &record = name.nameRecord[i]; 1.383 + record.platformID.set (3); 1.384 + record.encodingID.set (1); 1.385 + record.languageID.set (0x0409); /* English */ 1.386 + record.nameID.set (name_IDs[i]); 1.387 + record.length.set (name_str_len * 2); 1.388 + record.offset.set (0); 1.389 + } 1.390 + 1.391 + /* Copy string data from new_name, converting wchar_t to UTF16BE. */ 1.392 + unsigned char *p = &OT::StructAfter<unsigned char> (name); 1.393 + for (unsigned int i = 0; i < name_str_len; i++) 1.394 + { 1.395 + *p++ = new_name[i] >> 8; 1.396 + *p++ = new_name[i] & 0xff; 1.397 + } 1.398 + 1.399 + /* Adjust name table entry to point to new name table */ 1.400 + const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data); 1.401 + unsigned int face_count = file.get_face_count (); 1.402 + for (unsigned int face_index = 0; face_index < face_count; face_index++) 1.403 + { 1.404 + /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be 1.405 + * toe-stepping. But we don't really care. */ 1.406 + const OT::OpenTypeFontFace &face = file.get_face (face_index); 1.407 + unsigned int index; 1.408 + if (face.find_table_index (HB_OT_TAG_name, &index)) 1.409 + { 1.410 + OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index)); 1.411 + record.checkSum.set_for_data (&name, name_table_length); 1.412 + record.offset.set (name_table_offset); 1.413 + record.length.set (name_table_length); 1.414 + } 1.415 + else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */ 1.416 + { 1.417 + free (new_sfnt_data); 1.418 + hb_blob_destroy (blob); 1.419 + return NULL; 1.420 + } 1.421 + } 1.422 + 1.423 + /* The checkSumAdjustment field in the 'head' table is now wrong, 1.424 + * but that doesn't actually seem to cause any problems so we don't 1.425 + * bother. */ 1.426 + 1.427 + hb_blob_destroy (blob); 1.428 + return hb_blob_create ((const char *) new_sfnt_data, new_length, 1.429 + HB_MEMORY_MODE_WRITABLE, NULL, free); 1.430 +} 1.431 + 1.432 +hb_uniscribe_shaper_face_data_t * 1.433 +_hb_uniscribe_shaper_face_data_create (hb_face_t *face) 1.434 +{ 1.435 + hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t)); 1.436 + if (unlikely (!data)) 1.437 + return NULL; 1.438 + 1.439 + data->funcs = hb_uniscribe_shaper_get_funcs (); 1.440 + if (unlikely (!data->funcs)) 1.441 + { 1.442 + free (data); 1.443 + return NULL; 1.444 + } 1.445 + 1.446 + hb_blob_t *blob = hb_face_reference_blob (face); 1.447 + if (unlikely (!hb_blob_get_length (blob))) 1.448 + DEBUG_MSG (UNISCRIBE, face, "Face has empty blob"); 1.449 + 1.450 + blob = _hb_rename_font (blob, data->face_name); 1.451 + if (unlikely (!blob)) 1.452 + { 1.453 + free (data); 1.454 + return NULL; 1.455 + } 1.456 + 1.457 + DWORD num_fonts_installed; 1.458 + data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL), 1.459 + hb_blob_get_length (blob), 1.460 + 0, &num_fonts_installed); 1.461 + if (unlikely (!data->fh)) 1.462 + { 1.463 + DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed"); 1.464 + free (data); 1.465 + return NULL; 1.466 + } 1.467 + 1.468 + return data; 1.469 +} 1.470 + 1.471 +void 1.472 +_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data) 1.473 +{ 1.474 + RemoveFontMemResourceEx (data->fh); 1.475 + free (data); 1.476 +} 1.477 + 1.478 + 1.479 +/* 1.480 + * shaper font data 1.481 + */ 1.482 + 1.483 +struct hb_uniscribe_shaper_font_data_t { 1.484 + HDC hdc; 1.485 + LOGFONTW log_font; 1.486 + HFONT hfont; 1.487 + SCRIPT_CACHE script_cache; 1.488 +}; 1.489 + 1.490 +static bool 1.491 +populate_log_font (LOGFONTW *lf, 1.492 + hb_font_t *font) 1.493 +{ 1.494 + memset (lf, 0, sizeof (*lf)); 1.495 + lf->lfHeight = -font->y_scale; 1.496 + lf->lfCharSet = DEFAULT_CHARSET; 1.497 + 1.498 + hb_face_t *face = font->face; 1.499 + hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 1.500 + 1.501 + memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName)); 1.502 + 1.503 + return true; 1.504 +} 1.505 + 1.506 +hb_uniscribe_shaper_font_data_t * 1.507 +_hb_uniscribe_shaper_font_data_create (hb_font_t *font) 1.508 +{ 1.509 + if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL; 1.510 + 1.511 + hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t)); 1.512 + if (unlikely (!data)) 1.513 + return NULL; 1.514 + 1.515 + data->hdc = GetDC (NULL); 1.516 + 1.517 + if (unlikely (!populate_log_font (&data->log_font, font))) { 1.518 + DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed"); 1.519 + _hb_uniscribe_shaper_font_data_destroy (data); 1.520 + return NULL; 1.521 + } 1.522 + 1.523 + data->hfont = CreateFontIndirectW (&data->log_font); 1.524 + if (unlikely (!data->hfont)) { 1.525 + DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed"); 1.526 + _hb_uniscribe_shaper_font_data_destroy (data); 1.527 + return NULL; 1.528 + } 1.529 + 1.530 + if (!SelectObject (data->hdc, data->hfont)) { 1.531 + DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed"); 1.532 + _hb_uniscribe_shaper_font_data_destroy (data); 1.533 + return NULL; 1.534 + } 1.535 + 1.536 + return data; 1.537 +} 1.538 + 1.539 +void 1.540 +_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data) 1.541 +{ 1.542 + if (data->hdc) 1.543 + ReleaseDC (NULL, data->hdc); 1.544 + if (data->hfont) 1.545 + DeleteObject (data->hfont); 1.546 + if (data->script_cache) 1.547 + ScriptFreeCache (&data->script_cache); 1.548 + free (data); 1.549 +} 1.550 + 1.551 +LOGFONTW * 1.552 +hb_uniscribe_font_get_logfontw (hb_font_t *font) 1.553 +{ 1.554 + if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; 1.555 + hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 1.556 + return &font_data->log_font; 1.557 +} 1.558 + 1.559 +HFONT 1.560 +hb_uniscribe_font_get_hfont (hb_font_t *font) 1.561 +{ 1.562 + if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; 1.563 + hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 1.564 + return font_data->hfont; 1.565 +} 1.566 + 1.567 + 1.568 +/* 1.569 + * shaper shape_plan data 1.570 + */ 1.571 + 1.572 +struct hb_uniscribe_shaper_shape_plan_data_t {}; 1.573 + 1.574 +hb_uniscribe_shaper_shape_plan_data_t * 1.575 +_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 1.576 + const hb_feature_t *user_features HB_UNUSED, 1.577 + unsigned int num_user_features HB_UNUSED) 1.578 +{ 1.579 + return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 1.580 +} 1.581 + 1.582 +void 1.583 +_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED) 1.584 +{ 1.585 +} 1.586 + 1.587 + 1.588 +/* 1.589 + * shaper 1.590 + */ 1.591 + 1.592 + 1.593 +hb_bool_t 1.594 +_hb_uniscribe_shape (hb_shape_plan_t *shape_plan, 1.595 + hb_font_t *font, 1.596 + hb_buffer_t *buffer, 1.597 + const hb_feature_t *features, 1.598 + unsigned int num_features) 1.599 +{ 1.600 + hb_face_t *face = font->face; 1.601 + hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 1.602 + hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 1.603 + hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs; 1.604 + 1.605 + /* 1.606 + * Set up features. 1.607 + */ 1.608 + hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records; 1.609 + hb_auto_array_t<range_record_t> range_records; 1.610 + if (num_features) 1.611 + { 1.612 + /* Sort features by start/end events. */ 1.613 + hb_auto_array_t<feature_event_t> feature_events; 1.614 + for (unsigned int i = 0; i < num_features; i++) 1.615 + { 1.616 + active_feature_t feature; 1.617 + feature.rec.tagFeature = hb_uint32_swap (features[i].tag); 1.618 + feature.rec.lParameter = features[i].value; 1.619 + feature.order = i; 1.620 + 1.621 + feature_event_t *event; 1.622 + 1.623 + event = feature_events.push (); 1.624 + if (unlikely (!event)) 1.625 + goto fail_features; 1.626 + event->index = features[i].start; 1.627 + event->start = true; 1.628 + event->feature = feature; 1.629 + 1.630 + event = feature_events.push (); 1.631 + if (unlikely (!event)) 1.632 + goto fail_features; 1.633 + event->index = features[i].end; 1.634 + event->start = false; 1.635 + event->feature = feature; 1.636 + } 1.637 + feature_events.sort (); 1.638 + /* Add a strategic final event. */ 1.639 + { 1.640 + active_feature_t feature; 1.641 + feature.rec.tagFeature = 0; 1.642 + feature.rec.lParameter = 0; 1.643 + feature.order = num_features + 1; 1.644 + 1.645 + feature_event_t *event = feature_events.push (); 1.646 + if (unlikely (!event)) 1.647 + goto fail_features; 1.648 + event->index = 0; /* This value does magic. */ 1.649 + event->start = false; 1.650 + event->feature = feature; 1.651 + } 1.652 + 1.653 + /* Scan events and save features for each range. */ 1.654 + hb_auto_array_t<active_feature_t> active_features; 1.655 + unsigned int last_index = 0; 1.656 + for (unsigned int i = 0; i < feature_events.len; i++) 1.657 + { 1.658 + feature_event_t *event = &feature_events[i]; 1.659 + 1.660 + if (event->index != last_index) 1.661 + { 1.662 + /* Save a snapshot of active features and the range. */ 1.663 + range_record_t *range = range_records.push (); 1.664 + if (unlikely (!range)) 1.665 + goto fail_features; 1.666 + 1.667 + unsigned int offset = feature_records.len; 1.668 + 1.669 + active_features.sort (); 1.670 + for (unsigned int j = 0; j < active_features.len; j++) 1.671 + { 1.672 + if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature) 1.673 + { 1.674 + OPENTYPE_FEATURE_RECORD *feature = feature_records.push (); 1.675 + if (unlikely (!feature)) 1.676 + goto fail_features; 1.677 + *feature = active_features[j].rec; 1.678 + } 1.679 + else 1.680 + { 1.681 + /* Overrides value for existing feature. */ 1.682 + feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter; 1.683 + } 1.684 + } 1.685 + 1.686 + /* Will convert to pointer after all is ready, since feature_records.array 1.687 + * may move as we grow it. */ 1.688 + range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset); 1.689 + range->props.cotfRecords = feature_records.len - offset; 1.690 + range->index_first = last_index; 1.691 + range->index_last = event->index - 1; 1.692 + 1.693 + last_index = event->index; 1.694 + } 1.695 + 1.696 + if (event->start) { 1.697 + active_feature_t *feature = active_features.push (); 1.698 + if (unlikely (!feature)) 1.699 + goto fail_features; 1.700 + *feature = event->feature; 1.701 + } else { 1.702 + active_feature_t *feature = active_features.find (&event->feature); 1.703 + if (feature) 1.704 + active_features.remove (feature - active_features.array); 1.705 + } 1.706 + } 1.707 + 1.708 + if (!range_records.len) /* No active feature found. */ 1.709 + goto fail_features; 1.710 + 1.711 + /* Fixup the pointers. */ 1.712 + for (unsigned int i = 0; i < range_records.len; i++) 1.713 + { 1.714 + range_record_t *range = &range_records[i]; 1.715 + range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords); 1.716 + } 1.717 + } 1.718 + else 1.719 + { 1.720 + fail_features: 1.721 + num_features = 0; 1.722 + } 1.723 + 1.724 +#define FAIL(...) \ 1.725 + HB_STMT_START { \ 1.726 + DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \ 1.727 + return false; \ 1.728 + } HB_STMT_END; 1.729 + 1.730 + HRESULT hr; 1.731 + 1.732 +retry: 1.733 + 1.734 + unsigned int scratch_size; 1.735 + hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 1.736 + 1.737 +#define ALLOCATE_ARRAY(Type, name, len) \ 1.738 + Type *name = (Type *) scratch; \ 1.739 + { \ 1.740 + unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 1.741 + assert (_consumed <= scratch_size); \ 1.742 + scratch += _consumed; \ 1.743 + scratch_size -= _consumed; \ 1.744 + } 1.745 + 1.746 +#define utf16_index() var1.u32 1.747 + 1.748 + ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2); 1.749 + 1.750 + unsigned int chars_len = 0; 1.751 + for (unsigned int i = 0; i < buffer->len; i++) 1.752 + { 1.753 + hb_codepoint_t c = buffer->info[i].codepoint; 1.754 + buffer->info[i].utf16_index() = chars_len; 1.755 + if (likely (c < 0x10000)) 1.756 + pchars[chars_len++] = c; 1.757 + else if (unlikely (c >= 0x110000)) 1.758 + pchars[chars_len++] = 0xFFFD; 1.759 + else { 1.760 + pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 1.761 + pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 1.762 + } 1.763 + } 1.764 + 1.765 + ALLOCATE_ARRAY (WORD, log_clusters, chars_len); 1.766 + ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); 1.767 + 1.768 + if (num_features) 1.769 + { 1.770 + /* Need log_clusters to assign features. */ 1.771 + chars_len = 0; 1.772 + for (unsigned int i = 0; i < buffer->len; i++) 1.773 + { 1.774 + hb_codepoint_t c = buffer->info[i].codepoint; 1.775 + unsigned int cluster = buffer->info[i].cluster; 1.776 + log_clusters[chars_len++] = cluster; 1.777 + if (c >= 0x10000 && c < 0x110000) 1.778 + log_clusters[chars_len++] = cluster; /* Surrogates. */ 1.779 + } 1.780 + } 1.781 + 1.782 + /* The -2 in the following is to compensate for possible 1.783 + * alignment needed after the WORD array. sizeof(WORD) == 2. */ 1.784 + unsigned int glyphs_size = (scratch_size * sizeof (int) - 2) 1.785 + / (sizeof (WORD) + 1.786 + sizeof (SCRIPT_GLYPHPROP) + 1.787 + sizeof (int) + 1.788 + sizeof (GOFFSET) + 1.789 + sizeof (uint32_t)); 1.790 + 1.791 + ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); 1.792 + ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); 1.793 + ALLOCATE_ARRAY (int, advances, glyphs_size); 1.794 + ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); 1.795 + ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); 1.796 + 1.797 + /* Note: 1.798 + * We can't touch the contents of glyph_props. Our fallback 1.799 + * implementations of Shape and Place functions use that buffer 1.800 + * by casting it to a different type. It works because they 1.801 + * both agree about it, but if we want to access it here we 1.802 + * need address that issue first. 1.803 + */ 1.804 + 1.805 +#undef ALLOCATE_ARRAY 1.806 + 1.807 +#define MAX_ITEMS 256 1.808 + 1.809 + SCRIPT_ITEM items[MAX_ITEMS + 1]; 1.810 + SCRIPT_CONTROL bidi_control = {0}; 1.811 + SCRIPT_STATE bidi_state = {0}; 1.812 + ULONG script_tags[MAX_ITEMS]; 1.813 + int item_count; 1.814 + 1.815 + /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ 1.816 + //bidi_control.fMergeNeutralItems = true; 1.817 + *(uint32_t*)&bidi_control |= 1<<24; 1.818 + 1.819 + bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 1.820 + bidi_state.fOverrideDirection = 1; 1.821 + 1.822 + hr = funcs->ScriptItemizeOpenType (pchars, 1.823 + chars_len, 1.824 + MAX_ITEMS, 1.825 + &bidi_control, 1.826 + &bidi_state, 1.827 + items, 1.828 + script_tags, 1.829 + &item_count); 1.830 + if (unlikely (FAILED (hr))) 1.831 + FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr); 1.832 + 1.833 +#undef MAX_ITEMS 1.834 + 1.835 + OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language)); 1.836 + hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties; 1.837 + hb_auto_array_t<int> range_char_counts; 1.838 + 1.839 + unsigned int glyphs_offset = 0; 1.840 + unsigned int glyphs_len; 1.841 + bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 1.842 + for (unsigned int i = 0; i < item_count; i++) 1.843 + { 1.844 + unsigned int chars_offset = items[i].iCharPos; 1.845 + unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; 1.846 + 1.847 + if (num_features) 1.848 + { 1.849 + range_properties.shrink (0); 1.850 + range_char_counts.shrink (0); 1.851 + 1.852 + range_record_t *last_range = &range_records[0]; 1.853 + 1.854 + for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++) 1.855 + { 1.856 + range_record_t *range = last_range; 1.857 + while (log_clusters[k] < range->index_first) 1.858 + range--; 1.859 + while (log_clusters[k] > range->index_last) 1.860 + range++; 1.861 + if (!range_properties.len || 1.862 + &range->props != range_properties[range_properties.len - 1]) 1.863 + { 1.864 + TEXTRANGE_PROPERTIES **props = range_properties.push (); 1.865 + int *c = range_char_counts.push (); 1.866 + if (unlikely (!props || !c)) 1.867 + { 1.868 + range_properties.shrink (0); 1.869 + range_char_counts.shrink (0); 1.870 + break; 1.871 + } 1.872 + *props = &range->props; 1.873 + *c = 1; 1.874 + } 1.875 + else 1.876 + { 1.877 + range_char_counts[range_char_counts.len - 1]++; 1.878 + } 1.879 + 1.880 + last_range = range; 1.881 + } 1.882 + } 1.883 + 1.884 + /* Asking for glyphs in logical order circumvents at least 1.885 + * one bug in Uniscribe. */ 1.886 + items[i].a.fLogicalOrder = true; 1.887 + 1.888 + retry_shape: 1.889 + hr = funcs->ScriptShapeOpenType (font_data->hdc, 1.890 + &font_data->script_cache, 1.891 + &items[i].a, 1.892 + script_tags[i], 1.893 + language_tag, 1.894 + range_char_counts.array, 1.895 + range_properties.array, 1.896 + range_properties.len, 1.897 + pchars + chars_offset, 1.898 + item_chars_len, 1.899 + glyphs_size - glyphs_offset, 1.900 + /* out */ 1.901 + log_clusters + chars_offset, 1.902 + char_props + chars_offset, 1.903 + glyphs + glyphs_offset, 1.904 + glyph_props + glyphs_offset, 1.905 + (int *) &glyphs_len); 1.906 + 1.907 + if (unlikely (items[i].a.fNoGlyphIndex)) 1.908 + FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); 1.909 + if (unlikely (hr == E_OUTOFMEMORY)) 1.910 + { 1.911 + buffer->ensure (buffer->allocated * 2); 1.912 + if (buffer->in_error) 1.913 + FAIL ("Buffer resize failed"); 1.914 + goto retry; 1.915 + } 1.916 + if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) 1.917 + { 1.918 + if (items[i].a.eScript == SCRIPT_UNDEFINED) 1.919 + FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); 1.920 + items[i].a.eScript = SCRIPT_UNDEFINED; 1.921 + goto retry_shape; 1.922 + } 1.923 + if (unlikely (FAILED (hr))) 1.924 + { 1.925 + FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr); 1.926 + } 1.927 + 1.928 + for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) 1.929 + log_clusters[j] += glyphs_offset; 1.930 + 1.931 + hr = funcs->ScriptPlaceOpenType (font_data->hdc, 1.932 + &font_data->script_cache, 1.933 + &items[i].a, 1.934 + script_tags[i], 1.935 + language_tag, 1.936 + range_char_counts.array, 1.937 + range_properties.array, 1.938 + range_properties.len, 1.939 + pchars + chars_offset, 1.940 + log_clusters + chars_offset, 1.941 + char_props + chars_offset, 1.942 + item_chars_len, 1.943 + glyphs + glyphs_offset, 1.944 + glyph_props + glyphs_offset, 1.945 + glyphs_len, 1.946 + /* out */ 1.947 + advances + glyphs_offset, 1.948 + offsets + glyphs_offset, 1.949 + NULL); 1.950 + if (unlikely (FAILED (hr))) 1.951 + FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr); 1.952 + 1.953 + if (DEBUG_ENABLED (UNISCRIBE)) 1.954 + fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", 1.955 + i, 1.956 + items[i].a.fRTL, 1.957 + items[i].a.fLayoutRTL, 1.958 + items[i].a.fLogicalOrder, 1.959 + HB_UNTAG (hb_uint32_swap (script_tags[i]))); 1.960 + 1.961 + glyphs_offset += glyphs_len; 1.962 + } 1.963 + glyphs_len = glyphs_offset; 1.964 + 1.965 + /* Ok, we've got everything we need, now compose output buffer, 1.966 + * very, *very*, carefully! */ 1.967 + 1.968 + /* Calculate visual-clusters. That's what we ship. */ 1.969 + for (unsigned int i = 0; i < glyphs_len; i++) 1.970 + vis_clusters[i] = -1; 1.971 + for (unsigned int i = 0; i < buffer->len; i++) { 1.972 + uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; 1.973 + *p = MIN (*p, buffer->info[i].cluster); 1.974 + } 1.975 + for (unsigned int i = 1; i < glyphs_len; i++) 1.976 + if (vis_clusters[i] == -1) 1.977 + vis_clusters[i] = vis_clusters[i - 1]; 1.978 + 1.979 +#undef utf16_index 1.980 + 1.981 + buffer->ensure (glyphs_len); 1.982 + if (buffer->in_error) 1.983 + FAIL ("Buffer in error"); 1.984 + 1.985 +#undef FAIL 1.986 + 1.987 + /* Set glyph infos */ 1.988 + buffer->len = 0; 1.989 + for (unsigned int i = 0; i < glyphs_len; i++) 1.990 + { 1.991 + hb_glyph_info_t *info = &buffer->info[buffer->len++]; 1.992 + 1.993 + info->codepoint = glyphs[i]; 1.994 + info->cluster = vis_clusters[i]; 1.995 + 1.996 + /* The rest is crap. Let's store position info there for now. */ 1.997 + info->mask = advances[i]; 1.998 + info->var1.u32 = offsets[i].du; 1.999 + info->var2.u32 = offsets[i].dv; 1.1000 + } 1.1001 + 1.1002 + /* Set glyph positions */ 1.1003 + buffer->clear_positions (); 1.1004 + for (unsigned int i = 0; i < glyphs_len; i++) 1.1005 + { 1.1006 + hb_glyph_info_t *info = &buffer->info[i]; 1.1007 + hb_glyph_position_t *pos = &buffer->pos[i]; 1.1008 + 1.1009 + /* TODO vertical */ 1.1010 + pos->x_advance = info->mask; 1.1011 + pos->x_offset = backward ? -info->var1.u32 : info->var1.u32; 1.1012 + pos->y_offset = info->var2.u32; 1.1013 + } 1.1014 + 1.1015 + if (backward) 1.1016 + hb_buffer_reverse (buffer); 1.1017 + 1.1018 + /* Wow, done! */ 1.1019 + return true; 1.1020 +} 1.1021 + 1.1022 +