2 * Glyph shaping support
4 * Copyright 2010 Aric Stewart for CodeWeavers
5 * Copyright 2014 Nikolay Sivov for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "dwrite_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
28 struct scriptshaping_cache
30 IDWriteFontFace
*fontface
;
34 HRESULT
create_scriptshaping_cache(IDWriteFontFace
*fontface
, const WCHAR
*locale
, struct scriptshaping_cache
**cache
)
36 struct scriptshaping_cache
*ret
;
38 ret
= heap_alloc(sizeof(*ret
));
42 ret
->fontface
= fontface
;
43 IDWriteFontFace_AddRef(fontface
);
45 ret
->language_tag
= DWRITE_MAKE_OPENTYPE_TAG('d','f','l','t');
48 if (GetLocaleInfoEx(locale
, LOCALE_SOPENTYPELANGUAGETAG
, tag
, sizeof(tag
)/sizeof(WCHAR
)))
49 ret
->language_tag
= DWRITE_MAKE_OPENTYPE_TAG(tag
[0],tag
[1],tag
[2],tag
[3]);
57 void release_scriptshaping_cache(struct scriptshaping_cache
*cache
)
61 IDWriteFontFace_Release(cache
->fontface
);
65 static void shape_update_clusters_from_glyphprop(UINT32 glyphcount
, UINT32 text_len
, UINT16
*clustermap
, DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
)
69 for (i
= 0; i
< glyphcount
; i
++) {
70 if (!glyph_props
[i
].isClusterStart
) {
73 for (j
= 0; j
< text_len
; j
++) {
74 if (clustermap
[j
] == i
) {
76 while (k
>= 0 && k
< text_len
&& !glyph_props
[clustermap
[k
]].isClusterStart
)
79 if (k
>= 0 && k
< text_len
&& glyph_props
[clustermap
[k
]].isClusterStart
)
80 clustermap
[j
] = clustermap
[k
];
87 static int compare_clustersearch(const void *a
, const void* b
)
89 UINT16 target
= *(UINT16
*)a
;
90 UINT16 index
= *(UINT16
*)b
;
95 else if (target
< index
)
101 /* Maps given glyph position in glyph indices array to text index this glyph represents.
102 Lowest possible index is returned.
104 clustermap [I] Text index to index in glyph indices array map
105 len [I] Clustermap size
106 target [I] Index in glyph indices array to map
108 static INT32
map_glyph_to_text_pos(const UINT16
*clustermap
, UINT32 len
, UINT16 target
)
113 ptr
= bsearch(&target
, clustermap
, len
, sizeof(UINT16
), compare_clustersearch
);
117 /* get to the beginning */
118 for (k
= (ptr
- clustermap
) - 1; k
>= 0 && clustermap
[k
] == target
; k
--)
125 static HRESULT
default_set_text_glyphs_props(struct scriptshaping_cache
*cache
, const WCHAR
*text
, UINT32 len
, UINT16
*clustermap
, UINT16
*glyph_indices
,
126 UINT32 glyphcount
, DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
, DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
)
130 for (i
= 0; i
< glyphcount
; i
++) {
131 UINT32 char_index
[20];
132 UINT32 char_count
= 0;
135 k
= map_glyph_to_text_pos(clustermap
, len
, i
);
137 for (; k
< len
&& clustermap
[k
] == i
; k
++)
138 char_index
[char_count
++] = k
;
144 if (char_count
== 1 && isspaceW(text
[char_index
[0]])) {
145 glyph_props
[i
].justification
= SCRIPT_JUSTIFY_BLANK
;
146 text_props
[char_index
[0]].isShapedAlone
= text
[char_index
[0]] == ' ';
149 glyph_props
[i
].justification
= SCRIPT_JUSTIFY_CHARACTER
;
152 /* FIXME: update properties using GDEF table */
153 shape_update_clusters_from_glyphprop(glyphcount
, len
, clustermap
, glyph_props
);
158 static HRESULT
latn_set_text_glyphs_props(struct scriptshaping_cache
*cache
, const WCHAR
*text
, UINT32 len
, UINT16
*clustermap
, UINT16
*glyph_indices
,
159 UINT32 glyphcount
, DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
, DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
)
164 hr
= default_set_text_glyphs_props(cache
, text
, len
, clustermap
, glyph_indices
, glyphcount
, text_props
, glyph_props
);
166 for (i
= 0; i
< glyphcount
; i
++)
167 if (glyph_props
[i
].isZeroWidthSpace
)
168 glyph_props
[i
].justification
= SCRIPT_JUSTIFY_NONE
;
173 const struct scriptshaping_ops latn_shaping_ops
=
176 latn_set_text_glyphs_props
179 const struct scriptshaping_ops default_shaping_ops
=
182 default_set_text_glyphs_props