|
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<uintptr_t> (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 /* The -2 in the following is to compensate for possible |
|
780 * alignment needed after the WORD array. sizeof(WORD) == 2. */ |
|
781 unsigned int glyphs_size = (scratch_size * sizeof (int) - 2) |
|
782 / (sizeof (WORD) + |
|
783 sizeof (SCRIPT_GLYPHPROP) + |
|
784 sizeof (int) + |
|
785 sizeof (GOFFSET) + |
|
786 sizeof (uint32_t)); |
|
787 |
|
788 ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); |
|
789 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); |
|
790 ALLOCATE_ARRAY (int, advances, glyphs_size); |
|
791 ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); |
|
792 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); |
|
793 |
|
794 /* Note: |
|
795 * We can't touch the contents of glyph_props. Our fallback |
|
796 * implementations of Shape and Place functions use that buffer |
|
797 * by casting it to a different type. It works because they |
|
798 * both agree about it, but if we want to access it here we |
|
799 * need address that issue first. |
|
800 */ |
|
801 |
|
802 #undef ALLOCATE_ARRAY |
|
803 |
|
804 #define MAX_ITEMS 256 |
|
805 |
|
806 SCRIPT_ITEM items[MAX_ITEMS + 1]; |
|
807 SCRIPT_CONTROL bidi_control = {0}; |
|
808 SCRIPT_STATE bidi_state = {0}; |
|
809 ULONG script_tags[MAX_ITEMS]; |
|
810 int item_count; |
|
811 |
|
812 /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ |
|
813 //bidi_control.fMergeNeutralItems = true; |
|
814 *(uint32_t*)&bidi_control |= 1<<24; |
|
815 |
|
816 bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; |
|
817 bidi_state.fOverrideDirection = 1; |
|
818 |
|
819 hr = funcs->ScriptItemizeOpenType (pchars, |
|
820 chars_len, |
|
821 MAX_ITEMS, |
|
822 &bidi_control, |
|
823 &bidi_state, |
|
824 items, |
|
825 script_tags, |
|
826 &item_count); |
|
827 if (unlikely (FAILED (hr))) |
|
828 FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr); |
|
829 |
|
830 #undef MAX_ITEMS |
|
831 |
|
832 OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language)); |
|
833 hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties; |
|
834 hb_auto_array_t<int> range_char_counts; |
|
835 |
|
836 unsigned int glyphs_offset = 0; |
|
837 unsigned int glyphs_len; |
|
838 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); |
|
839 for (unsigned int i = 0; i < item_count; i++) |
|
840 { |
|
841 unsigned int chars_offset = items[i].iCharPos; |
|
842 unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; |
|
843 |
|
844 if (num_features) |
|
845 { |
|
846 range_properties.shrink (0); |
|
847 range_char_counts.shrink (0); |
|
848 |
|
849 range_record_t *last_range = &range_records[0]; |
|
850 |
|
851 for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++) |
|
852 { |
|
853 range_record_t *range = last_range; |
|
854 while (log_clusters[k] < range->index_first) |
|
855 range--; |
|
856 while (log_clusters[k] > range->index_last) |
|
857 range++; |
|
858 if (!range_properties.len || |
|
859 &range->props != range_properties[range_properties.len - 1]) |
|
860 { |
|
861 TEXTRANGE_PROPERTIES **props = range_properties.push (); |
|
862 int *c = range_char_counts.push (); |
|
863 if (unlikely (!props || !c)) |
|
864 { |
|
865 range_properties.shrink (0); |
|
866 range_char_counts.shrink (0); |
|
867 break; |
|
868 } |
|
869 *props = &range->props; |
|
870 *c = 1; |
|
871 } |
|
872 else |
|
873 { |
|
874 range_char_counts[range_char_counts.len - 1]++; |
|
875 } |
|
876 |
|
877 last_range = range; |
|
878 } |
|
879 } |
|
880 |
|
881 /* Asking for glyphs in logical order circumvents at least |
|
882 * one bug in Uniscribe. */ |
|
883 items[i].a.fLogicalOrder = true; |
|
884 |
|
885 retry_shape: |
|
886 hr = funcs->ScriptShapeOpenType (font_data->hdc, |
|
887 &font_data->script_cache, |
|
888 &items[i].a, |
|
889 script_tags[i], |
|
890 language_tag, |
|
891 range_char_counts.array, |
|
892 range_properties.array, |
|
893 range_properties.len, |
|
894 pchars + chars_offset, |
|
895 item_chars_len, |
|
896 glyphs_size - glyphs_offset, |
|
897 /* out */ |
|
898 log_clusters + chars_offset, |
|
899 char_props + chars_offset, |
|
900 glyphs + glyphs_offset, |
|
901 glyph_props + glyphs_offset, |
|
902 (int *) &glyphs_len); |
|
903 |
|
904 if (unlikely (items[i].a.fNoGlyphIndex)) |
|
905 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); |
|
906 if (unlikely (hr == E_OUTOFMEMORY)) |
|
907 { |
|
908 buffer->ensure (buffer->allocated * 2); |
|
909 if (buffer->in_error) |
|
910 FAIL ("Buffer resize failed"); |
|
911 goto retry; |
|
912 } |
|
913 if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) |
|
914 { |
|
915 if (items[i].a.eScript == SCRIPT_UNDEFINED) |
|
916 FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); |
|
917 items[i].a.eScript = SCRIPT_UNDEFINED; |
|
918 goto retry_shape; |
|
919 } |
|
920 if (unlikely (FAILED (hr))) |
|
921 { |
|
922 FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr); |
|
923 } |
|
924 |
|
925 for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) |
|
926 log_clusters[j] += glyphs_offset; |
|
927 |
|
928 hr = funcs->ScriptPlaceOpenType (font_data->hdc, |
|
929 &font_data->script_cache, |
|
930 &items[i].a, |
|
931 script_tags[i], |
|
932 language_tag, |
|
933 range_char_counts.array, |
|
934 range_properties.array, |
|
935 range_properties.len, |
|
936 pchars + chars_offset, |
|
937 log_clusters + chars_offset, |
|
938 char_props + chars_offset, |
|
939 item_chars_len, |
|
940 glyphs + glyphs_offset, |
|
941 glyph_props + glyphs_offset, |
|
942 glyphs_len, |
|
943 /* out */ |
|
944 advances + glyphs_offset, |
|
945 offsets + glyphs_offset, |
|
946 NULL); |
|
947 if (unlikely (FAILED (hr))) |
|
948 FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr); |
|
949 |
|
950 if (DEBUG_ENABLED (UNISCRIBE)) |
|
951 fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", |
|
952 i, |
|
953 items[i].a.fRTL, |
|
954 items[i].a.fLayoutRTL, |
|
955 items[i].a.fLogicalOrder, |
|
956 HB_UNTAG (hb_uint32_swap (script_tags[i]))); |
|
957 |
|
958 glyphs_offset += glyphs_len; |
|
959 } |
|
960 glyphs_len = glyphs_offset; |
|
961 |
|
962 /* Ok, we've got everything we need, now compose output buffer, |
|
963 * very, *very*, carefully! */ |
|
964 |
|
965 /* Calculate visual-clusters. That's what we ship. */ |
|
966 for (unsigned int i = 0; i < glyphs_len; i++) |
|
967 vis_clusters[i] = -1; |
|
968 for (unsigned int i = 0; i < buffer->len; i++) { |
|
969 uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; |
|
970 *p = MIN (*p, buffer->info[i].cluster); |
|
971 } |
|
972 for (unsigned int i = 1; i < glyphs_len; i++) |
|
973 if (vis_clusters[i] == -1) |
|
974 vis_clusters[i] = vis_clusters[i - 1]; |
|
975 |
|
976 #undef utf16_index |
|
977 |
|
978 buffer->ensure (glyphs_len); |
|
979 if (buffer->in_error) |
|
980 FAIL ("Buffer in error"); |
|
981 |
|
982 #undef FAIL |
|
983 |
|
984 /* Set glyph infos */ |
|
985 buffer->len = 0; |
|
986 for (unsigned int i = 0; i < glyphs_len; i++) |
|
987 { |
|
988 hb_glyph_info_t *info = &buffer->info[buffer->len++]; |
|
989 |
|
990 info->codepoint = glyphs[i]; |
|
991 info->cluster = vis_clusters[i]; |
|
992 |
|
993 /* The rest is crap. Let's store position info there for now. */ |
|
994 info->mask = advances[i]; |
|
995 info->var1.u32 = offsets[i].du; |
|
996 info->var2.u32 = offsets[i].dv; |
|
997 } |
|
998 |
|
999 /* Set glyph positions */ |
|
1000 buffer->clear_positions (); |
|
1001 for (unsigned int i = 0; i < glyphs_len; i++) |
|
1002 { |
|
1003 hb_glyph_info_t *info = &buffer->info[i]; |
|
1004 hb_glyph_position_t *pos = &buffer->pos[i]; |
|
1005 |
|
1006 /* TODO vertical */ |
|
1007 pos->x_advance = info->mask; |
|
1008 pos->x_offset = backward ? -info->var1.u32 : info->var1.u32; |
|
1009 pos->y_offset = info->var2.u32; |
|
1010 } |
|
1011 |
|
1012 if (backward) |
|
1013 hb_buffer_reverse (buffer); |
|
1014 |
|
1015 /* Wow, done! */ |
|
1016 return true; |
|
1017 } |
|
1018 |
|
1019 |