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
32 #error "Cannot compile 'uniscribe' shaper with HB_NO_OT_TAG."
35 #include "hb-shaper-impl.hh"
41 #ifndef E_NOT_SUFFICIENT_BUFFER
42 #define E_NOT_SUFFICIENT_BUFFER HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)
45 #include "hb-uniscribe.h"
47 #include "hb-ms-feature-ranges.hh"
48 #include "hb-open-file.hh"
49 #include "hb-ot-name-table.hh"
50 #include "hb-ot-layout.h"
54 * SECTION:hb-uniscribe
55 * @title: hb-uniscribe
56 * @short_description: Windows integration
57 * @include: hb-uniscribe.h
59 * Functions for using HarfBuzz with Windows fonts.
62 typedef HRESULT (WINAPI
*SIOT
) /*ScriptItemizeOpenType*/(
63 const WCHAR
*pwcInChars
,
66 const SCRIPT_CONTROL
*psControl
,
67 const SCRIPT_STATE
*psState
,
69 OPENTYPE_TAG
*pScriptTags
,
73 typedef HRESULT (WINAPI
*SSOT
) /*ScriptShapeOpenType*/(
77 OPENTYPE_TAG tagScript
,
78 OPENTYPE_TAG tagLangSys
,
80 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
82 const WCHAR
*pwcChars
,
86 SCRIPT_CHARPROP
*pCharProps
,
88 SCRIPT_GLYPHPROP
*pOutGlyphProps
,
92 typedef HRESULT (WINAPI
*SPOT
) /*ScriptPlaceOpenType*/(
96 OPENTYPE_TAG tagScript
,
97 OPENTYPE_TAG tagLangSys
,
99 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
101 const WCHAR
*pwcChars
,
103 SCRIPT_CHARPROP
*pCharProps
,
105 const WORD
*pwGlyphs
,
106 const SCRIPT_GLYPHPROP
*pGlyphProps
,
114 /* Fallback implementations. */
116 static HRESULT WINAPI
117 hb_ScriptItemizeOpenType(
118 const WCHAR
*pwcInChars
,
121 const SCRIPT_CONTROL
*psControl
,
122 const SCRIPT_STATE
*psState
,
124 OPENTYPE_TAG
*pScriptTags
,
129 return ScriptItemize (pwcInChars
,
139 static HRESULT WINAPI
140 hb_ScriptShapeOpenType(
143 SCRIPT_ANALYSIS
*psa
,
144 OPENTYPE_TAG tagScript
,
145 OPENTYPE_TAG tagLangSys
,
147 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
149 const WCHAR
*pwcChars
,
153 SCRIPT_CHARPROP
*pCharProps
,
155 SCRIPT_GLYPHPROP
*pOutGlyphProps
,
159 SCRIPT_VISATTR
*psva
= (SCRIPT_VISATTR
*) pOutGlyphProps
;
160 return ScriptShape (hdc
,
172 static HRESULT WINAPI
173 hb_ScriptPlaceOpenType(
176 SCRIPT_ANALYSIS
*psa
,
177 OPENTYPE_TAG tagScript
,
178 OPENTYPE_TAG tagLangSys
,
180 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
182 const WCHAR
*pwcChars
,
184 SCRIPT_CHARPROP
*pCharProps
,
186 const WORD
*pwGlyphs
,
187 const SCRIPT_GLYPHPROP
*pGlyphProps
,
194 SCRIPT_VISATTR
*psva
= (SCRIPT_VISATTR
*) pGlyphProps
;
195 return ScriptPlace (hdc
,
207 struct hb_uniscribe_shaper_funcs_t
209 SIOT ScriptItemizeOpenType
;
210 SSOT ScriptShapeOpenType
;
211 SPOT ScriptPlaceOpenType
;
216 this->ScriptItemizeOpenType
= nullptr;
217 this->ScriptShapeOpenType
= nullptr;
218 this->ScriptPlaceOpenType
= nullptr;
220 hinstLib
= GetModuleHandle (TEXT ("usp10.dll"));
223 #pragma GCC diagnostic push
224 #pragma GCC diagnostic ignored "-Wcast-function-type"
225 this->ScriptItemizeOpenType
= (SIOT
) GetProcAddress (hinstLib
, "ScriptItemizeOpenType");
226 this->ScriptShapeOpenType
= (SSOT
) GetProcAddress (hinstLib
, "ScriptShapeOpenType");
227 this->ScriptPlaceOpenType
= (SPOT
) GetProcAddress (hinstLib
, "ScriptPlaceOpenType");
228 #pragma GCC diagnostic pop
230 if (!this->ScriptItemizeOpenType
||
231 !this->ScriptShapeOpenType
||
232 !this->ScriptPlaceOpenType
)
234 DEBUG_MSG (UNISCRIBE
, nullptr, "OpenType versions of functions not found; falling back.");
235 this->ScriptItemizeOpenType
= hb_ScriptItemizeOpenType
;
236 this->ScriptShapeOpenType
= hb_ScriptShapeOpenType
;
237 this->ScriptPlaceOpenType
= hb_ScriptPlaceOpenType
;
242 static inline void free_static_uniscribe_shaper_funcs ();
244 static struct hb_uniscribe_shaper_funcs_lazy_loader_t
: hb_lazy_loader_t
<hb_uniscribe_shaper_funcs_t
,
245 hb_uniscribe_shaper_funcs_lazy_loader_t
>
247 static hb_uniscribe_shaper_funcs_t
*create ()
249 hb_uniscribe_shaper_funcs_t
*funcs
= (hb_uniscribe_shaper_funcs_t
*) hb_calloc (1, sizeof (hb_uniscribe_shaper_funcs_t
));
250 if (unlikely (!funcs
))
255 hb_atexit (free_static_uniscribe_shaper_funcs
);
259 static void destroy (hb_uniscribe_shaper_funcs_t
*p
)
261 hb_free ((void *) p
);
263 static hb_uniscribe_shaper_funcs_t
*get_null ()
267 } static_uniscribe_shaper_funcs
;
270 void free_static_uniscribe_shaper_funcs ()
272 static_uniscribe_shaper_funcs
.free_instance ();
275 static hb_uniscribe_shaper_funcs_t
*
276 hb_uniscribe_shaper_get_funcs ()
278 return static_uniscribe_shaper_funcs
.get_unconst ();
286 struct hb_uniscribe_face_data_t
{
288 hb_uniscribe_shaper_funcs_t
*funcs
;
289 wchar_t face_name
[LF_FACESIZE
];
292 /* face_name should point to a wchar_t[LF_FACESIZE] object. */
294 _hb_generate_unique_face_name (wchar_t *face_name
, unsigned int *plen
)
296 /* We'll create a private name for the font from a UUID using a simple,
297 * somewhat base64-like encoding scheme */
298 const char *enc
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
300 UuidCreate ((UUID
*) &id
);
301 static_assert ((2 + 3 * (16/2) < LF_FACESIZE
), "");
302 unsigned int name_str_len
= 0;
303 face_name
[name_str_len
++] = 'F';
304 face_name
[name_str_len
++] = '_';
305 unsigned char *p
= (unsigned char *) &id
;
306 for (unsigned int i
= 0; i
< 16; i
+= 2)
308 /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
309 * using the bits in groups of 5,5,6 to select chars from enc.
310 * This will generate 24 characters; with the 'F_' prefix we already provided,
311 * the name will be 26 chars (plus the NUL terminator), so will always fit within
312 * face_name (LF_FACESIZE = 32). */
313 face_name
[name_str_len
++] = enc
[p
[i
] >> 3];
314 face_name
[name_str_len
++] = enc
[((p
[i
] << 2) | (p
[i
+ 1] >> 6)) & 0x1f];
315 face_name
[name_str_len
++] = enc
[p
[i
+ 1] & 0x3f];
317 face_name
[name_str_len
] = 0;
319 *plen
= name_str_len
;
324 _hb_rename_font (hb_blob_t
*blob
, wchar_t *new_name
)
326 /* Create a copy of the font data, with the 'name' table replaced by a
327 * table that names the font with our private F_* name created above.
328 * For simplicity, we just append a new 'name' table and update the
329 * sfnt directory; the original table is left in place, but unused.
331 * The new table will contain just 5 name IDs: family, style, unique,
332 * full, PS. All of them point to the same name data with our unique name.
335 blob
= hb_sanitize_context_t ().sanitize_blob
<OT::OpenTypeFontFile
> (blob
);
337 unsigned int length
, new_length
, name_str_len
;
338 const char *orig_sfnt_data
= hb_blob_get_data (blob
, &length
);
340 _hb_generate_unique_face_name (new_name
, &name_str_len
);
342 static const uint16_t name_IDs
[] = { 1, 2, 3, 4, 6 };
344 unsigned int name_table_length
= OT::name::min_size
+
345 ARRAY_LENGTH (name_IDs
) * OT::NameRecord::static_size
+
346 name_str_len
* 2; /* for name data in UTF16BE form */
347 unsigned int padded_name_table_length
= ((name_table_length
+ 3) & ~3);
348 unsigned int name_table_offset
= (length
+ 3) & ~3;
350 new_length
= name_table_offset
+ padded_name_table_length
;
351 void *new_sfnt_data
= hb_calloc (1, new_length
);
354 hb_blob_destroy (blob
);
358 memcpy(new_sfnt_data
, orig_sfnt_data
, length
);
360 OT::name
&name
= StructAtOffset
<OT::name
> (new_sfnt_data
, name_table_offset
);
362 name
.count
= ARRAY_LENGTH (name_IDs
);
363 name
.stringOffset
= name
.get_size ();
364 for (unsigned int i
= 0; i
< ARRAY_LENGTH (name_IDs
); i
++)
366 OT::NameRecord
&record
= name
.nameRecordZ
[i
];
367 record
.platformID
= 3;
368 record
.encodingID
= 1;
369 record
.languageID
= 0x0409u
; /* English */
370 record
.nameID
= name_IDs
[i
];
371 record
.length
= name_str_len
* 2;
375 /* Copy string data from new_name, converting wchar_t to UTF16BE. */
376 unsigned char *p
= &StructAfter
<unsigned char> (name
);
377 for (unsigned int i
= 0; i
< name_str_len
; i
++)
379 *p
++ = new_name
[i
] >> 8;
380 *p
++ = new_name
[i
] & 0xff;
383 /* Adjust name table entry to point to new name table */
384 const OT::OpenTypeFontFile
&file
= * (OT::OpenTypeFontFile
*) (new_sfnt_data
);
385 unsigned int face_count
= file
.get_face_count ();
386 for (unsigned int face_index
= 0; face_index
< face_count
; face_index
++)
388 /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be
389 * toe-stepping. But we don't really care. */
390 const OT::OpenTypeFontFace
&face
= file
.get_face (face_index
);
392 if (face
.find_table_index (HB_OT_TAG_name
, &index
))
394 OT::TableRecord
&record
= const_cast<OT::TableRecord
&> (face
.get_table (index
));
395 record
.checkSum
.set_for_data (&name
, padded_name_table_length
);
396 record
.offset
= name_table_offset
;
397 record
.length
= name_table_length
;
399 else if (face_index
== 0) /* Fail if first face doesn't have 'name' table. */
401 hb_free (new_sfnt_data
);
402 hb_blob_destroy (blob
);
407 /* The checkSumAdjustment field in the 'head' table is now wrong,
408 * but that doesn't actually seem to cause any problems so we don't
411 hb_blob_destroy (blob
);
412 return hb_blob_create ((const char *) new_sfnt_data
, new_length
,
413 HB_MEMORY_MODE_WRITABLE
, new_sfnt_data
, hb_free
);
416 hb_uniscribe_face_data_t
*
417 _hb_uniscribe_shaper_face_data_create (hb_face_t
*face
)
419 hb_uniscribe_face_data_t
*data
= (hb_uniscribe_face_data_t
*) hb_calloc (1, sizeof (hb_uniscribe_face_data_t
));
420 if (unlikely (!data
))
423 data
->funcs
= hb_uniscribe_shaper_get_funcs ();
424 if (unlikely (!data
->funcs
))
430 hb_blob_t
*blob
= hb_face_reference_blob (face
);
431 if (unlikely (!hb_blob_get_length (blob
)))
432 DEBUG_MSG (UNISCRIBE
, face
, "Face has empty blob");
434 blob
= _hb_rename_font (blob
, data
->face_name
);
435 if (unlikely (!blob
))
441 DWORD num_fonts_installed
;
442 data
->fh
= AddFontMemResourceEx ((void *) hb_blob_get_data (blob
, nullptr),
443 hb_blob_get_length (blob
),
444 0, &num_fonts_installed
);
445 if (unlikely (!data
->fh
))
447 DEBUG_MSG (UNISCRIBE
, face
, "Face AddFontMemResourceEx() failed");
456 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t
*data
)
458 RemoveFontMemResourceEx (data
->fh
);
467 struct hb_uniscribe_font_data_t
470 mutable LOGFONTW log_font
;
472 mutable SCRIPT_CACHE script_cache
;
473 double x_mult
, y_mult
; /* From LOGFONT space to HB space. */
477 populate_log_font (LOGFONTW
*lf
,
479 unsigned int font_size
)
481 memset (lf
, 0, sizeof (*lf
));
482 lf
->lfHeight
= - (int) font_size
;
483 lf
->lfCharSet
= DEFAULT_CHARSET
;
485 memcpy (lf
->lfFaceName
, font
->face
->data
.uniscribe
->face_name
, sizeof (lf
->lfFaceName
));
490 hb_uniscribe_font_data_t
*
491 _hb_uniscribe_shaper_font_data_create (hb_font_t
*font
)
493 hb_uniscribe_font_data_t
*data
= (hb_uniscribe_font_data_t
*) hb_calloc (1, sizeof (hb_uniscribe_font_data_t
));
494 if (unlikely (!data
))
497 int font_size
= font
->face
->get_upem (); /* Default... */
498 /* No idea if the following is even a good idea. */
500 font_size
= font
->y_ppem
;
503 font_size
= -font_size
;
504 data
->x_mult
= (double) font
->x_scale
/ font_size
;
505 data
->y_mult
= (double) font
->y_scale
/ font_size
;
507 data
->hdc
= GetDC (nullptr);
509 if (unlikely (!populate_log_font (&data
->log_font
, font
, font_size
))) {
510 DEBUG_MSG (UNISCRIBE
, font
, "Font populate_log_font() failed");
511 _hb_uniscribe_shaper_font_data_destroy (data
);
515 data
->hfont
= CreateFontIndirectW (&data
->log_font
);
516 if (unlikely (!data
->hfont
)) {
517 DEBUG_MSG (UNISCRIBE
, font
, "Font CreateFontIndirectW() failed");
518 _hb_uniscribe_shaper_font_data_destroy (data
);
522 if (!SelectObject (data
->hdc
, data
->hfont
)) {
523 DEBUG_MSG (UNISCRIBE
, font
, "Font SelectObject() failed");
524 _hb_uniscribe_shaper_font_data_destroy (data
);
532 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t
*data
)
535 ReleaseDC (nullptr, data
->hdc
);
537 DeleteObject (data
->hfont
);
538 if (data
->script_cache
)
539 ScriptFreeCache (&data
->script_cache
);
544 * hb_uniscribe_font_get_logfontw:
545 * @font: The #hb_font_t to work upon
547 * Fetches the LOGFONTW structure that corresponds to the
548 * specified #hb_font_t font.
550 * Return value: a pointer to the LOGFONTW retrieved
554 hb_uniscribe_font_get_logfontw (hb_font_t
*font
)
556 const hb_uniscribe_font_data_t
*data
= font
->data
.uniscribe
;
557 return data
? &data
->log_font
: nullptr;
561 * hb_uniscribe_font_get_hfont:
562 * @font: The #hb_font_t to work upon
564 * Fetches the HFONT handle that corresponds to the
565 * specified #hb_font_t font.
567 * Return value: the HFONT retreieved
571 hb_uniscribe_font_get_hfont (hb_font_t
*font
)
573 const hb_uniscribe_font_data_t
*data
= font
->data
.uniscribe
;
574 return data
? data
->hfont
: nullptr;
584 _hb_uniscribe_shape (hb_shape_plan_t
*shape_plan
,
587 const hb_feature_t
*features
,
588 unsigned int num_features
)
590 hb_face_t
*face
= font
->face
;
591 const hb_uniscribe_face_data_t
*face_data
= face
->data
.uniscribe
;
592 const hb_uniscribe_font_data_t
*font_data
= font
->data
.uniscribe
;
593 hb_uniscribe_shaper_funcs_t
*funcs
= face_data
->funcs
;
597 DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
605 unsigned int scratch_size
;
606 hb_buffer_t::scratch_buffer_t
*scratch
= buffer
->get_scratch_buffer (&scratch_size
);
608 #define ALLOCATE_ARRAY(Type, name, len) \
609 Type *name = (Type *) scratch; \
611 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
612 assert (_consumed <= scratch_size); \
613 scratch += _consumed; \
614 scratch_size -= _consumed; \
617 #define utf16_index() var1.u32
619 ALLOCATE_ARRAY (WCHAR
, pchars
, buffer
->len
* 2);
621 unsigned int chars_len
= 0;
622 for (unsigned int i
= 0; i
< buffer
->len
; i
++)
624 hb_codepoint_t c
= buffer
->info
[i
].codepoint
;
625 buffer
->info
[i
].utf16_index() = chars_len
;
626 if (likely (c
<= 0xFFFFu
))
627 pchars
[chars_len
++] = c
;
628 else if (unlikely (c
> 0x10FFFFu
))
629 pchars
[chars_len
++] = 0xFFFDu
;
631 pchars
[chars_len
++] = 0xD800u
+ ((c
- 0x10000u
) >> 10);
632 pchars
[chars_len
++] = 0xDC00u
+ ((c
- 0x10000u
) & ((1u << 10) - 1));
636 ALLOCATE_ARRAY (WORD
, log_clusters
, chars_len
);
637 ALLOCATE_ARRAY (SCRIPT_CHARPROP
, char_props
, chars_len
);
641 /* Need log_clusters to assign features. */
643 for (unsigned int i
= 0; i
< buffer
->len
; i
++)
645 hb_codepoint_t c
= buffer
->info
[i
].codepoint
;
646 unsigned int cluster
= buffer
->info
[i
].cluster
;
647 log_clusters
[chars_len
++] = cluster
;
648 if (hb_in_range (c
, 0x10000u
, 0x10FFFFu
))
649 log_clusters
[chars_len
++] = cluster
; /* Surrogates. */
653 /* The -2 in the following is to compensate for possible
654 * alignment needed after the WORD array. sizeof(WORD) == 2. */
655 unsigned int glyphs_size
= (scratch_size
* sizeof (int) - 2)
657 sizeof (SCRIPT_GLYPHPROP
) +
662 ALLOCATE_ARRAY (WORD
, glyphs
, glyphs_size
);
663 ALLOCATE_ARRAY (SCRIPT_GLYPHPROP
, glyph_props
, glyphs_size
);
664 ALLOCATE_ARRAY (int, advances
, glyphs_size
);
665 ALLOCATE_ARRAY (GOFFSET
, offsets
, glyphs_size
);
666 ALLOCATE_ARRAY (uint32_t, vis_clusters
, glyphs_size
);
669 * We can't touch the contents of glyph_props. Our fallback
670 * implementations of Shape and Place functions use that buffer
671 * by casting it to a different type. It works because they
672 * both agree about it, but if we want to access it here we
673 * need address that issue first.
676 #undef ALLOCATE_ARRAY
678 #define MAX_ITEMS 256
680 SCRIPT_ITEM items
[MAX_ITEMS
+ 1];
681 SCRIPT_CONTROL bidi_control
= {0};
682 SCRIPT_STATE bidi_state
= {0};
683 ULONG script_tags
[MAX_ITEMS
];
686 /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
687 //bidi_control.fMergeNeutralItems = true;
688 *(uint32_t*)&bidi_control
|= 1u<<24;
690 bidi_state
.uBidiLevel
= HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
) ? 0 : 1;
691 bidi_state
.fOverrideDirection
= 1;
693 hr
= funcs
->ScriptItemizeOpenType (pchars
,
701 if (unlikely (FAILED (hr
)))
702 FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr
);
707 unsigned int lang_count
= 1;
708 hb_ot_tags_from_script_and_language (buffer
->props
.script
,
709 buffer
->props
.language
,
711 &lang_count
, &lang_tag
);
712 OPENTYPE_TAG language_tag
= hb_uint32_swap (lang_count
? lang_tag
: HB_TAG_NONE
);
717 static_assert ((sizeof (TEXTRANGE_PROPERTIES
) == sizeof (hb_ms_features_t
)), "");
718 static_assert ((sizeof (OPENTYPE_FEATURE_RECORD
) == sizeof (hb_ms_feature_t
)), "");
719 hb_vector_t
<hb_ms_feature_t
> feature_records
;
720 hb_vector_t
<hb_ms_range_record_t
> range_records
;
721 bool has_features
= false;
723 has_features
= hb_ms_setup_features (features
,
728 hb_vector_t
<hb_ms_features_t
*> range_properties
;
729 hb_vector_t
<uint32_t> range_char_counts
;
731 unsigned int glyphs_offset
= 0;
732 unsigned int glyphs_len
;
733 bool backward
= HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
);
734 for (int i
= 0; i
< item_count
; i
++)
736 unsigned int chars_offset
= items
[i
].iCharPos
;
737 unsigned int item_chars_len
= items
[i
+ 1].iCharPos
- chars_offset
;
740 hb_ms_make_feature_ranges (feature_records
,
748 /* Asking for glyphs in logical order circumvents at least
749 * one bug in Uniscribe. */
750 items
[i
].a
.fLogicalOrder
= true;
753 hr
= funcs
->ScriptShapeOpenType (font_data
->hdc
,
754 &font_data
->script_cache
,
758 (int *) range_char_counts
.arrayZ
,
759 (TEXTRANGE_PROPERTIES
**) range_properties
.arrayZ
,
760 range_properties
.length
,
761 pchars
+ chars_offset
,
763 glyphs_size
- glyphs_offset
,
765 log_clusters
+ chars_offset
,
766 char_props
+ chars_offset
,
767 glyphs
+ glyphs_offset
,
768 glyph_props
+ glyphs_offset
,
769 (int *) &glyphs_len
);
771 if (unlikely (items
[i
].a
.fNoGlyphIndex
))
772 FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
773 if (unlikely (hr
== E_OUTOFMEMORY
|| hr
== E_NOT_SUFFICIENT_BUFFER
))
775 if (unlikely (!buffer
->ensure (buffer
->allocated
* 2)))
776 FAIL ("Buffer resize failed");
779 if (unlikely (hr
== USP_E_SCRIPT_NOT_IN_FONT
))
781 if (items
[i
].a
.eScript
== SCRIPT_UNDEFINED
)
782 FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
783 items
[i
].a
.eScript
= SCRIPT_UNDEFINED
;
786 if (unlikely (FAILED (hr
)))
788 FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr
);
791 for (unsigned int j
= chars_offset
; j
< chars_offset
+ item_chars_len
; j
++)
792 log_clusters
[j
] += glyphs_offset
;
794 hr
= funcs
->ScriptPlaceOpenType (font_data
->hdc
,
795 &font_data
->script_cache
,
799 (int *) range_char_counts
.arrayZ
,
800 (TEXTRANGE_PROPERTIES
**) range_properties
.arrayZ
,
801 range_properties
.length
,
802 pchars
+ chars_offset
,
803 log_clusters
+ chars_offset
,
804 char_props
+ chars_offset
,
806 glyphs
+ glyphs_offset
,
807 glyph_props
+ glyphs_offset
,
810 advances
+ glyphs_offset
,
811 offsets
+ glyphs_offset
,
813 if (unlikely (FAILED (hr
)))
814 FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr
);
816 if (DEBUG_ENABLED (UNISCRIBE
))
817 fprintf (stderr
, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
820 items
[i
].a
.fLayoutRTL
,
821 items
[i
].a
.fLogicalOrder
,
822 HB_UNTAG (hb_uint32_swap (script_tags
[i
])));
824 glyphs_offset
+= glyphs_len
;
826 glyphs_len
= glyphs_offset
;
828 /* Ok, we've got everything we need, now compose output buffer,
829 * very, *very*, carefully! */
831 /* Calculate visual-clusters. That's what we ship. */
832 for (unsigned int i
= 0; i
< glyphs_len
; i
++)
833 vis_clusters
[i
] = (uint32_t) -1;
834 for (unsigned int i
= 0; i
< buffer
->len
; i
++) {
835 uint32_t *p
= &vis_clusters
[log_clusters
[buffer
->info
[i
].utf16_index()]];
836 *p
= hb_min (*p
, buffer
->info
[i
].cluster
);
838 for (unsigned int i
= 1; i
< glyphs_len
; i
++)
839 if (vis_clusters
[i
] == (uint32_t) -1)
840 vis_clusters
[i
] = vis_clusters
[i
- 1];
844 if (unlikely (!buffer
->ensure (glyphs_len
)))
845 FAIL ("Buffer in error");
849 /* Set glyph infos */
851 for (unsigned int i
= 0; i
< glyphs_len
; i
++)
853 hb_glyph_info_t
*info
= &buffer
->info
[buffer
->len
++];
855 info
->codepoint
= glyphs
[i
];
856 info
->cluster
= vis_clusters
[i
];
858 /* The rest is crap. Let's store position info there for now. */
859 info
->mask
= advances
[i
];
860 info
->var1
.i32
= offsets
[i
].du
;
861 info
->var2
.i32
= offsets
[i
].dv
;
864 /* Set glyph positions */
865 buffer
->clear_positions ();
866 double x_mult
= font_data
->x_mult
, y_mult
= font_data
->y_mult
;
867 for (unsigned int i
= 0; i
< glyphs_len
; i
++)
869 hb_glyph_info_t
*info
= &buffer
->info
[i
];
870 hb_glyph_position_t
*pos
= &buffer
->pos
[i
];
873 pos
->x_advance
= x_mult
* (int32_t) info
->mask
;
874 pos
->x_offset
= x_mult
* (backward
? -info
->var1
.i32
: info
->var1
.i32
);
875 pos
->y_offset
= y_mult
* info
->var2
.i32
;
879 hb_buffer_reverse (buffer
);
881 buffer
->clear_glyph_flags ();
882 buffer
->unsafe_to_break ();