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
25 #include "dwrite_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
29 struct scriptshaping_cache
31 IDWriteFontFace
*fontface
;
35 HRESULT
create_scriptshaping_cache(IDWriteFontFace
*fontface
, const WCHAR
*locale
, struct scriptshaping_cache
**cache
)
37 struct scriptshaping_cache
*ret
;
39 ret
= heap_alloc(sizeof(*ret
));
43 ret
->fontface
= fontface
;
44 IDWriteFontFace_AddRef(fontface
);
46 ret
->language_tag
= DWRITE_MAKE_OPENTYPE_TAG('d','f','l','t');
49 if (GetLocaleInfoEx(locale
, LOCALE_SOPENTYPELANGUAGETAG
, tag
, sizeof(tag
)/sizeof(WCHAR
)))
50 ret
->language_tag
= DWRITE_MAKE_OPENTYPE_TAG(tag
[0],tag
[1],tag
[2],tag
[3]);
58 void release_scriptshaping_cache(struct scriptshaping_cache
*cache
)
62 IDWriteFontFace_Release(cache
->fontface
);
66 static void shape_update_clusters_from_glyphprop(UINT32 glyphcount
, UINT32 text_len
, UINT16
*clustermap
, DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
)
70 for (i
= 0; i
< glyphcount
; i
++) {
71 if (!glyph_props
[i
].isClusterStart
) {
74 for (j
= 0; j
< text_len
; j
++) {
75 if (clustermap
[j
] == i
) {
77 while (k
>= 0 && k
< text_len
&& !glyph_props
[clustermap
[k
]].isClusterStart
)
80 if (k
>= 0 && k
< text_len
&& glyph_props
[clustermap
[k
]].isClusterStart
)
81 clustermap
[j
] = clustermap
[k
];
88 static int compare_clustersearch(const void *a
, const void* b
)
90 UINT16 target
= *(UINT16
*)a
;
91 UINT16 index
= *(UINT16
*)b
;
96 else if (target
< index
)
102 /* Maps given glyph position in glyph indices array to text index this glyph represents.
103 Lowest possible index is returned.
105 clustermap [I] Text index to index in glyph indices array map
106 len [I] Clustermap size
107 target [I] Index in glyph indices array to map
109 static INT32
map_glyph_to_text_pos(const UINT16
*clustermap
, UINT32 len
, UINT16 target
)
114 ptr
= bsearch(&target
, clustermap
, len
, sizeof(UINT16
), compare_clustersearch
);
118 /* get to the beginning */
119 for (k
= (ptr
- clustermap
) - 1; k
>= 0 && clustermap
[k
] == target
; k
--)
126 static HRESULT
default_set_text_glyphs_props(struct scriptshaping_cache
*cache
, const WCHAR
*text
, UINT32 len
, UINT16
*clustermap
, UINT16
*glyph_indices
,
127 UINT32 glyphcount
, DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
, DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
)
131 for (i
= 0; i
< glyphcount
; i
++) {
132 UINT32 char_index
[20];
133 UINT32 char_count
= 0;
136 k
= map_glyph_to_text_pos(clustermap
, len
, i
);
138 for (; k
< len
&& clustermap
[k
] == i
; k
++)
139 char_index
[char_count
++] = k
;
145 if (char_count
== 1 && isspaceW(text
[char_index
[0]])) {
146 glyph_props
[i
].justification
= SCRIPT_JUSTIFY_BLANK
;
147 text_props
[char_index
[0]].isShapedAlone
= text
[char_index
[0]] == ' ';
150 glyph_props
[i
].justification
= SCRIPT_JUSTIFY_CHARACTER
;
153 /* FIXME: update properties using GDEF table */
154 shape_update_clusters_from_glyphprop(glyphcount
, len
, clustermap
, glyph_props
);
159 static HRESULT
latn_set_text_glyphs_props(struct scriptshaping_cache
*cache
, const WCHAR
*text
, UINT32 len
, UINT16
*clustermap
, UINT16
*glyph_indices
,
160 UINT32 glyphcount
, DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
, DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
)
165 hr
= default_set_text_glyphs_props(cache
, text
, len
, clustermap
, glyph_indices
, glyphcount
, text_props
, glyph_props
);
167 for (i
= 0; i
< glyphcount
; i
++)
168 if (glyph_props
[i
].isZeroWidthSpace
)
169 glyph_props
[i
].justification
= SCRIPT_JUSTIFY_NONE
;
174 const struct scriptshaping_ops latn_shaping_ops
=
177 latn_set_text_glyphs_props
180 const struct scriptshaping_ops default_shaping_ops
=
183 default_set_text_glyphs_props