2 * Copyright © 2011,2012,2013 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Google Author(s): Behdad Esfahbod
27 #define _WIN32_WINNT 0x0600
28 #define WIN32_LEAN_AND_MEAN
30 #define HB_SHAPER uniscribe
31 #include "hb-shaper-impl-private.hh"
37 #include "hb-uniscribe.h"
39 #include "hb-open-file-private.hh"
40 #include "hb-ot-name-table.hh"
41 #include "hb-ot-tag.h"
44 #ifndef HB_DEBUG_UNISCRIBE
45 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
49 typedef HRESULT (WINAPI
*SIOT
) /*ScriptItemizeOpenType*/(
50 const WCHAR
*pwcInChars
,
53 const SCRIPT_CONTROL
*psControl
,
54 const SCRIPT_STATE
*psState
,
56 OPENTYPE_TAG
*pScriptTags
,
60 typedef HRESULT (WINAPI
*SSOT
) /*ScriptShapeOpenType*/(
64 OPENTYPE_TAG tagScript
,
65 OPENTYPE_TAG tagLangSys
,
67 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
69 const WCHAR
*pwcChars
,
73 SCRIPT_CHARPROP
*pCharProps
,
75 SCRIPT_GLYPHPROP
*pOutGlyphProps
,
79 typedef HRESULT (WINAPI
*SPOT
) /*ScriptPlaceOpenType*/(
83 OPENTYPE_TAG tagScript
,
84 OPENTYPE_TAG tagLangSys
,
86 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
88 const WCHAR
*pwcChars
,
90 SCRIPT_CHARPROP
*pCharProps
,
93 const SCRIPT_GLYPHPROP
*pGlyphProps
,
101 /* Fallback implementations. */
103 static HRESULT WINAPI
104 hb_ScriptItemizeOpenType(
105 const WCHAR
*pwcInChars
,
108 const SCRIPT_CONTROL
*psControl
,
109 const SCRIPT_STATE
*psState
,
111 OPENTYPE_TAG
*pScriptTags
,
116 return ScriptItemize (pwcInChars
,
126 static HRESULT WINAPI
127 hb_ScriptShapeOpenType(
130 SCRIPT_ANALYSIS
*psa
,
131 OPENTYPE_TAG tagScript
,
132 OPENTYPE_TAG tagLangSys
,
134 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
136 const WCHAR
*pwcChars
,
140 SCRIPT_CHARPROP
*pCharProps
,
142 SCRIPT_GLYPHPROP
*pOutGlyphProps
,
146 SCRIPT_VISATTR
*psva
= (SCRIPT_VISATTR
*) pOutGlyphProps
;
147 return ScriptShape (hdc
,
159 static HRESULT WINAPI
160 hb_ScriptPlaceOpenType(
163 SCRIPT_ANALYSIS
*psa
,
164 OPENTYPE_TAG tagScript
,
165 OPENTYPE_TAG tagLangSys
,
167 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
169 const WCHAR
*pwcChars
,
171 SCRIPT_CHARPROP
*pCharProps
,
173 const WORD
*pwGlyphs
,
174 const SCRIPT_GLYPHPROP
*pGlyphProps
,
181 SCRIPT_VISATTR
*psva
= (SCRIPT_VISATTR
*) pGlyphProps
;
182 return ScriptPlace (hdc
,
194 struct hb_uniscribe_shaper_funcs_t
{
195 SIOT ScriptItemizeOpenType
;
196 SSOT ScriptShapeOpenType
;
197 SPOT ScriptPlaceOpenType
;
199 inline void init (void)
202 this->ScriptItemizeOpenType
= NULL
;
203 this->ScriptShapeOpenType
= NULL
;
204 this->ScriptPlaceOpenType
= NULL
;
206 hinstLib
= GetModuleHandle (TEXT ("usp10.dll"));
209 this->ScriptItemizeOpenType
= (SIOT
) GetProcAddress (hinstLib
, "ScriptItemizeOpenType");
210 this->ScriptShapeOpenType
= (SSOT
) GetProcAddress (hinstLib
, "ScriptShapeOpenType");
211 this->ScriptPlaceOpenType
= (SPOT
) GetProcAddress (hinstLib
, "ScriptPlaceOpenType");
213 if (!this->ScriptItemizeOpenType
||
214 !this->ScriptShapeOpenType
||
215 !this->ScriptPlaceOpenType
)
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
;
224 static hb_uniscribe_shaper_funcs_t
*uniscribe_funcs
;
227 free_uniscribe_funcs (void)
229 free (uniscribe_funcs
);
232 static hb_uniscribe_shaper_funcs_t
*
233 hb_uniscribe_shaper_get_funcs (void)
236 hb_uniscribe_shaper_funcs_t
*funcs
= (hb_uniscribe_shaper_funcs_t
*) hb_atomic_ptr_get (&uniscribe_funcs
);
238 if (unlikely (!funcs
))
240 funcs
= (hb_uniscribe_shaper_funcs_t
*) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t
));
241 if (unlikely (!funcs
))
246 if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs
, NULL
, funcs
)) {
252 atexit (free_uniscribe_funcs
); /* First person registers atexit() callback. */
260 struct active_feature_t
{
261 OPENTYPE_FEATURE_RECORD rec
;
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 :
270 bool operator== (const active_feature_t
*f
) {
271 return cmp (this, f
) == 0;
275 struct feature_event_t
{
278 active_feature_t feature
;
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
);
287 struct range_record_t
{
288 TEXTRANGE_PROPERTIES props
;
289 unsigned int index_first
; /* == start */
290 unsigned int index_last
; /* == end - 1 */
293 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe
, face
)
294 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe
, font
)
301 struct hb_uniscribe_shaper_face_data_t
{
303 hb_uniscribe_shaper_funcs_t
*funcs
;
304 wchar_t face_name
[LF_FACESIZE
];
307 /* face_name should point to a wchar_t[LF_FACESIZE] object. */
309 _hb_generate_unique_face_name (wchar_t *face_name
, unsigned int *plen
)
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+-";
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)
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];
331 face_name
[name_str_len
] = 0;
333 *plen
= name_str_len
;
338 _hb_rename_font (hb_blob_t
*blob
, wchar_t *new_name
)
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.
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.
349 blob
= OT::Sanitizer
<OT::OpenTypeFontFile
>::sanitize (blob
);
351 unsigned int length
, new_length
, name_str_len
;
352 const char *orig_sfnt_data
= hb_blob_get_data (blob
, &length
);
354 _hb_generate_unique_face_name (new_name
, &name_str_len
);
356 static const uint16_t name_IDs
[] = { 1, 2, 3, 4, 6 };
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;
363 new_length
= name_table_offset
+ ((name_table_length
+ 3) & ~3);
364 void *new_sfnt_data
= calloc (1, new_length
);
367 hb_blob_destroy (blob
);
371 memcpy(new_sfnt_data
, orig_sfnt_data
, length
);
373 OT::name
&name
= OT::StructAtOffset
<OT::name
> (new_sfnt_data
, name_table_offset
);
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
++)
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);
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
++)
392 *p
++ = new_name
[i
] >> 8;
393 *p
++ = new_name
[i
] & 0xff;
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
++)
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
);
405 if (face
.find_table_index (HB_OT_TAG_name
, &index
))
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
);
412 else if (face_index
== 0) /* Fail if first face doesn't have 'name' table. */
414 free (new_sfnt_data
);
415 hb_blob_destroy (blob
);
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
424 hb_blob_destroy (blob
);
425 return hb_blob_create ((const char *) new_sfnt_data
, new_length
,
426 HB_MEMORY_MODE_WRITABLE
, NULL
, free
);
429 hb_uniscribe_shaper_face_data_t
*
430 _hb_uniscribe_shaper_face_data_create (hb_face_t
*face
)
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
))
436 data
->funcs
= hb_uniscribe_shaper_get_funcs ();
437 if (unlikely (!data
->funcs
))
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");
447 blob
= _hb_rename_font (blob
, data
->face_name
);
448 if (unlikely (!blob
))
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
))
460 DEBUG_MSG (UNISCRIBE
, face
, "Face AddFontMemResourceEx() failed");
469 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t
*data
)
471 RemoveFontMemResourceEx (data
->fh
);
480 struct hb_uniscribe_shaper_font_data_t
{
484 SCRIPT_CACHE script_cache
;
488 populate_log_font (LOGFONTW
*lf
,
491 memset (lf
, 0, sizeof (*lf
));
492 lf
->lfHeight
= -font
->y_scale
;
493 lf
->lfCharSet
= DEFAULT_CHARSET
;
495 hb_face_t
*face
= font
->face
;
496 hb_uniscribe_shaper_face_data_t
*face_data
= HB_SHAPER_DATA_GET (face
);
498 memcpy (lf
->lfFaceName
, face_data
->face_name
, sizeof (lf
->lfFaceName
));
503 hb_uniscribe_shaper_font_data_t
*
504 _hb_uniscribe_shaper_font_data_create (hb_font_t
*font
)
506 if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font
->face
))) return NULL
;
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
))
512 data
->hdc
= GetDC (NULL
);
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
);
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
);
527 if (!SelectObject (data
->hdc
, data
->hfont
)) {
528 DEBUG_MSG (UNISCRIBE
, font
, "Font SelectObject() failed");
529 _hb_uniscribe_shaper_font_data_destroy (data
);
537 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t
*data
)
540 ReleaseDC (NULL
, data
->hdc
);
542 DeleteObject (data
->hfont
);
543 if (data
->script_cache
)
544 ScriptFreeCache (&data
->script_cache
);
549 hb_uniscribe_font_get_logfontw (hb_font_t
*font
)
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
;
557 hb_uniscribe_font_get_hfont (hb_font_t
*font
)
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
;
566 * shaper shape_plan data
569 struct hb_uniscribe_shaper_shape_plan_data_t
{};
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
)
576 return (hb_uniscribe_shaper_shape_plan_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
580 _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t
*data HB_UNUSED
)
591 _hb_uniscribe_shape (hb_shape_plan_t
*shape_plan
,
594 const hb_feature_t
*features
,
595 unsigned int num_features
)
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
;
605 hb_auto_array_t
<OPENTYPE_FEATURE_RECORD
> feature_records
;
606 hb_auto_array_t
<range_record_t
> range_records
;
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
++)
613 active_feature_t feature
;
614 feature
.rec
.tagFeature
= hb_uint32_swap (features
[i
].tag
);
615 feature
.rec
.lParameter
= features
[i
].value
;
618 feature_event_t
*event
;
620 event
= feature_events
.push ();
621 if (unlikely (!event
))
623 event
->index
= features
[i
].start
;
625 event
->feature
= feature
;
627 event
= feature_events
.push ();
628 if (unlikely (!event
))
630 event
->index
= features
[i
].end
;
631 event
->start
= false;
632 event
->feature
= feature
;
634 feature_events
.sort ();
635 /* Add a strategic final event. */
637 active_feature_t feature
;
638 feature
.rec
.tagFeature
= 0;
639 feature
.rec
.lParameter
= 0;
640 feature
.order
= num_features
+ 1;
642 feature_event_t
*event
= feature_events
.push ();
643 if (unlikely (!event
))
645 event
->index
= 0; /* This value does magic. */
646 event
->start
= false;
647 event
->feature
= feature
;
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
++)
655 feature_event_t
*event
= &feature_events
[i
];
657 if (event
->index
!= last_index
)
659 /* Save a snapshot of active features and the range. */
660 range_record_t
*range
= range_records
.push ();
661 if (unlikely (!range
))
664 unsigned int offset
= feature_records
.len
;
666 active_features
.sort ();
667 for (unsigned int j
= 0; j
< active_features
.len
; j
++)
669 if (!j
|| active_features
[j
].rec
.tagFeature
!= feature_records
[feature_records
.len
- 1].tagFeature
)
671 OPENTYPE_FEATURE_RECORD
*feature
= feature_records
.push ();
672 if (unlikely (!feature
))
674 *feature
= active_features
[j
].rec
;
678 /* Overrides value for existing feature. */
679 feature_records
[feature_records
.len
- 1].lParameter
= active_features
[j
].rec
.lParameter
;
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;
690 last_index
= event
->index
;
694 active_feature_t
*feature
= active_features
.push ();
695 if (unlikely (!feature
))
697 *feature
= event
->feature
;
699 active_feature_t
*feature
= active_features
.find (&event
->feature
);
701 active_features
.remove (feature
- active_features
.array
);
705 if (!range_records
.len
) /* No active feature found. */
708 /* Fixup the pointers. */
709 for (unsigned int i
= 0; i
< range_records
.len
; i
++)
711 range_record_t
*range
= &range_records
[i
];
712 range
->props
.potfRecords
= feature_records
.array
+ reinterpret_cast<unsigned int> (range
->props
.potfRecords
);
723 DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
731 unsigned int scratch_size
;
732 hb_buffer_t::scratch_buffer_t
*scratch
= buffer
->get_scratch_buffer (&scratch_size
);
734 #define ALLOCATE_ARRAY(Type, name, len) \
735 Type *name = (Type *) scratch; \
737 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
738 assert (_consumed <= scratch_size); \
739 scratch += _consumed; \
740 scratch_size -= _consumed; \
743 #define utf16_index() var1.u32
745 ALLOCATE_ARRAY (WCHAR
, pchars
, buffer
->len
* 2);
747 unsigned int chars_len
= 0;
748 for (unsigned int i
= 0; i
< buffer
->len
; i
++)
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;
757 pchars
[chars_len
++] = 0xD800 + ((c
- 0x10000) >> 10);
758 pchars
[chars_len
++] = 0xDC00 + ((c
- 0x10000) & ((1 << 10) - 1));
762 ALLOCATE_ARRAY (WORD
, log_clusters
, chars_len
);
763 ALLOCATE_ARRAY (SCRIPT_CHARPROP
, char_props
, chars_len
);
767 /* Need log_clusters to assign features. */
769 for (unsigned int i
= 0; i
< buffer
->len
; i
++)
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. */
779 /* All the following types are sized in multiples of sizeof(int). */
780 unsigned int glyphs_size
= scratch_size
/ ((sizeof (WORD
) +
781 sizeof (SCRIPT_GLYPHPROP
) +
787 ALLOCATE_ARRAY (WORD
, glyphs
, glyphs_size
);
788 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP
, glyph_props
, glyphs_size
);
789 ALLOCATE_ARRAY (int, advances
, glyphs_size
);
790 ALLOCATE_ARRAY (GOFFSET
, offsets
, glyphs_size
);
791 ALLOCATE_ARRAY (uint32_t, vis_clusters
, glyphs_size
);
794 * We can't touch the contents of glyph_props. Our fallback
795 * implementations of Shape and Place functions use that buffer
796 * by casting it to a different type. It works because they
797 * both agree about it, but if we want to access it here we
798 * need address that issue first.
801 #undef ALLOCATE_ARRAY
803 #define MAX_ITEMS 256
805 SCRIPT_ITEM items
[MAX_ITEMS
+ 1];
806 SCRIPT_CONTROL bidi_control
= {0};
807 SCRIPT_STATE bidi_state
= {0};
808 ULONG script_tags
[MAX_ITEMS
];
811 /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
812 //bidi_control.fMergeNeutralItems = true;
813 *(uint32_t*)&bidi_control
|= 1<<24;
815 bidi_state
.uBidiLevel
= HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
) ? 0 : 1;
816 bidi_state
.fOverrideDirection
= 1;
818 hr
= funcs
->ScriptItemizeOpenType (pchars
,
826 if (unlikely (FAILED (hr
)))
827 FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr
);
831 OPENTYPE_TAG language_tag
= hb_uint32_swap (hb_ot_tag_from_language (buffer
->props
.language
));
832 hb_auto_array_t
<TEXTRANGE_PROPERTIES
*> range_properties
;
833 hb_auto_array_t
<int> range_char_counts
;
835 unsigned int glyphs_offset
= 0;
836 unsigned int glyphs_len
;
837 bool backward
= HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
);
838 for (unsigned int i
= 0; i
< item_count
; i
++)
840 unsigned int chars_offset
= items
[i
].iCharPos
;
841 unsigned int item_chars_len
= items
[i
+ 1].iCharPos
- chars_offset
;
845 range_properties
.shrink (0);
846 range_char_counts
.shrink (0);
848 range_record_t
*last_range
= &range_records
[0];
850 for (unsigned int k
= chars_offset
; k
< chars_offset
+ item_chars_len
; k
++)
852 range_record_t
*range
= last_range
;
853 while (log_clusters
[k
] < range
->index_first
)
855 while (log_clusters
[k
] > range
->index_last
)
857 if (!range_properties
.len
||
858 &range
->props
!= range_properties
[range_properties
.len
- 1])
860 TEXTRANGE_PROPERTIES
**props
= range_properties
.push ();
861 int *c
= range_char_counts
.push ();
862 if (unlikely (!props
|| !c
))
864 range_properties
.shrink (0);
865 range_char_counts
.shrink (0);
868 *props
= &range
->props
;
873 range_char_counts
[range_char_counts
.len
- 1]++;
880 /* Asking for glyphs in logical order circumvents at least
881 * one bug in Uniscribe. */
882 items
[i
].a
.fLogicalOrder
= true;
885 hr
= funcs
->ScriptShapeOpenType (font_data
->hdc
,
886 &font_data
->script_cache
,
890 range_char_counts
.array
,
891 range_properties
.array
,
892 range_properties
.len
,
893 pchars
+ chars_offset
,
895 glyphs_size
- glyphs_offset
,
897 log_clusters
+ chars_offset
,
898 char_props
+ chars_offset
,
899 glyphs
+ glyphs_offset
,
900 glyph_props
+ glyphs_offset
,
901 (int *) &glyphs_len
);
903 if (unlikely (items
[i
].a
.fNoGlyphIndex
))
904 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
905 if (unlikely (hr
== E_OUTOFMEMORY
))
907 buffer
->ensure (buffer
->allocated
* 2);
908 if (buffer
->in_error
)
909 FAIL ("Buffer resize failed");
912 if (unlikely (hr
== USP_E_SCRIPT_NOT_IN_FONT
))
914 if (items
[i
].a
.eScript
== SCRIPT_UNDEFINED
)
915 FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
916 items
[i
].a
.eScript
= SCRIPT_UNDEFINED
;
919 if (unlikely (FAILED (hr
)))
921 FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr
);
924 for (unsigned int j
= chars_offset
; j
< chars_offset
+ item_chars_len
; j
++)
925 log_clusters
[j
] += glyphs_offset
;
927 hr
= funcs
->ScriptPlaceOpenType (font_data
->hdc
,
928 &font_data
->script_cache
,
932 range_char_counts
.array
,
933 range_properties
.array
,
934 range_properties
.len
,
935 pchars
+ chars_offset
,
936 log_clusters
+ chars_offset
,
937 char_props
+ chars_offset
,
939 glyphs
+ glyphs_offset
,
940 glyph_props
+ glyphs_offset
,
943 advances
+ glyphs_offset
,
944 offsets
+ glyphs_offset
,
946 if (unlikely (FAILED (hr
)))
947 FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr
);
949 if (DEBUG_ENABLED (UNISCRIBE
))
950 fprintf (stderr
, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
953 items
[i
].a
.fLayoutRTL
,
954 items
[i
].a
.fLogicalOrder
,
955 HB_UNTAG (hb_uint32_swap (script_tags
[i
])));
957 glyphs_offset
+= glyphs_len
;
959 glyphs_len
= glyphs_offset
;
961 /* Ok, we've got everything we need, now compose output buffer,
962 * very, *very*, carefully! */
964 /* Calculate visual-clusters. That's what we ship. */
965 for (unsigned int i
= 0; i
< glyphs_len
; i
++)
966 vis_clusters
[i
] = -1;
967 for (unsigned int i
= 0; i
< buffer
->len
; i
++) {
968 uint32_t *p
= &vis_clusters
[log_clusters
[buffer
->info
[i
].utf16_index()]];
969 *p
= MIN (*p
, buffer
->info
[i
].cluster
);
971 for (unsigned int i
= 1; i
< glyphs_len
; i
++)
972 if (vis_clusters
[i
] == -1)
973 vis_clusters
[i
] = vis_clusters
[i
- 1];
977 buffer
->ensure (glyphs_len
);
978 if (buffer
->in_error
)
979 FAIL ("Buffer in error");
983 /* Set glyph infos */
985 for (unsigned int i
= 0; i
< glyphs_len
; i
++)
987 hb_glyph_info_t
*info
= &buffer
->info
[buffer
->len
++];
989 info
->codepoint
= glyphs
[i
];
990 info
->cluster
= vis_clusters
[i
];
992 /* The rest is crap. Let's store position info there for now. */
993 info
->mask
= advances
[i
];
994 info
->var1
.u32
= offsets
[i
].du
;
995 info
->var2
.u32
= offsets
[i
].dv
;
998 /* Set glyph positions */
999 buffer
->clear_positions ();
1000 for (unsigned int i
= 0; i
< glyphs_len
; i
++)
1002 hb_glyph_info_t
*info
= &buffer
->info
[i
];
1003 hb_glyph_position_t
*pos
= &buffer
->pos
[i
];
1006 pos
->x_advance
= info
->mask
;
1007 pos
->x_offset
= backward
? -info
->var1
.u32
: info
->var1
.u32
;
1008 pos
->y_offset
= info
->var2
.u32
;
1012 hb_buffer_reverse (buffer
);