usp10: Move GDEF functions to opentype.c.
[wine/multimedia.git] / dlls / usp10 / opentype.c
blob377558afbd2f954e2bdef9966222af173364c29e
1 /*
2 * Opentype font interfaces for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2012 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #ifdef WORDS_BIGENDIAN
39 #define GET_BE_WORD(x) (x)
40 #define GET_BE_DWORD(x) (x)
41 #else
42 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
43 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
44 #endif
46 /* These are all structures needed for the cmap format 12 table */
47 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
49 typedef struct {
50 WORD platformID;
51 WORD encodingID;
52 DWORD offset;
53 } CMAP_EncodingRecord;
55 typedef struct {
56 WORD version;
57 WORD numTables;
58 CMAP_EncodingRecord tables[1];
59 } CMAP_Header;
61 typedef struct {
62 DWORD startCharCode;
63 DWORD endCharCode;
64 DWORD startGlyphID;
65 } CMAP_SegmentedCoverage_group;
67 typedef struct {
68 WORD format;
69 WORD reserved;
70 DWORD length;
71 DWORD language;
72 DWORD nGroups;
73 CMAP_SegmentedCoverage_group groups[1];
74 } CMAP_SegmentedCoverage;
76 /* These are all structures needed for the GDEF table */
77 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
79 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
81 typedef struct {
82 DWORD Version;
83 WORD GlyphClassDef;
84 WORD AttachList;
85 WORD LigCaretList;
86 WORD MarkAttachClassDef;
87 } GDEF_Header;
89 typedef struct {
90 WORD ClassFormat;
91 WORD StartGlyph;
92 WORD GlyphCount;
93 WORD ClassValueArray[1];
94 } GDEF_ClassDefFormat1;
96 typedef struct {
97 WORD Start;
98 WORD End;
99 WORD Class;
100 } GDEF_ClassRangeRecord;
102 typedef struct {
103 WORD ClassFormat;
104 WORD ClassRangeCount;
105 GDEF_ClassRangeRecord ClassRangeRecord[1];
106 } GDEF_ClassDefFormat2;
108 /**********
109 * CMAP
110 **********/
112 static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
114 CMAP_Header *CMAP_Table = NULL;
115 int length;
116 int i;
118 if (!psc->CMAP_Table)
120 length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
121 if (length != GDI_ERROR)
123 psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
124 GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
125 TRACE("Loaded cmap table of %i bytes\n",length);
127 else
128 return NULL;
131 CMAP_Table = psc->CMAP_Table;
133 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
135 if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
136 (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
138 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
139 if (GET_BE_WORD(format->format) == 12)
140 return format;
143 return NULL;
146 static int compare_group(const void *a, const void* b)
148 const DWORD *chr = a;
149 const CMAP_SegmentedCoverage_group *group = b;
151 if (*chr < GET_BE_DWORD(group->startCharCode))
152 return -1;
153 if (*chr > GET_BE_DWORD(group->endCharCode))
154 return 1;
155 return 0;
158 DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
160 /* BMP: use gdi32 for ease */
161 if (utf32c < 0x10000)
163 WCHAR ch = utf32c;
164 return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
167 if (!psc->CMAP_format12_Table)
168 psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
170 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
171 *pgi = 0xffff;
172 else
173 *pgi = 0;
175 if (psc->CMAP_format12_Table)
177 CMAP_SegmentedCoverage *format = NULL;
178 CMAP_SegmentedCoverage_group *group = NULL;
180 format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
182 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
183 sizeof(CMAP_SegmentedCoverage_group), compare_group);
185 if (group)
187 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
188 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
189 return 0;
192 return 0;
195 /**********
196 * GDEF
197 **********/
199 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
201 int offset;
202 WORD class = 0;
203 const GDEF_ClassDefFormat1 *cf1;
205 if (!header)
206 return 0;
208 offset = GET_BE_WORD(header->GlyphClassDef);
209 if (!offset)
210 return 0;
212 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
213 if (GET_BE_WORD(cf1->ClassFormat) == 1)
215 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
217 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
218 if (index < GET_BE_WORD(cf1->GlyphCount))
219 class = GET_BE_WORD(cf1->ClassValueArray[index]);
222 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
224 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
225 int i, top;
226 top = GET_BE_WORD(cf2->ClassRangeCount);
227 for (i = 0; i < top; i++)
229 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
230 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
232 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
233 break;
237 else
238 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
240 return class;
243 static VOID *load_gdef_table(HDC hdc)
245 VOID* GDEF_Table = NULL;
246 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
247 if (length != GDI_ERROR)
249 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
250 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
251 TRACE("Loaded GDEF table of %i bytes\n",length);
253 return GDEF_Table;
256 void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
258 int i;
260 if (!psc->GDEF_Table)
261 psc->GDEF_Table = load_gdef_table(hdc);
263 for (i = 0; i < cGlyphs; i++)
265 WORD class;
266 int char_count = 0;
267 int k;
269 for (k = 0; k < cChars; k++)
270 if (pwLogClust[k] == i)
271 char_count++;
273 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
275 switch (class)
277 case 0:
278 case BaseGlyph:
279 pGlyphProp[i].sva.fClusterStart = 1;
280 pGlyphProp[i].sva.fDiacritic = 0;
281 pGlyphProp[i].sva.fZeroWidth = 0;
282 break;
283 case LigatureGlyph:
284 pGlyphProp[i].sva.fClusterStart = 1;
285 pGlyphProp[i].sva.fDiacritic = 0;
286 pGlyphProp[i].sva.fZeroWidth = 0;
287 break;
288 case MarkGlyph:
289 pGlyphProp[i].sva.fClusterStart = 0;
290 pGlyphProp[i].sva.fDiacritic = 1;
291 pGlyphProp[i].sva.fZeroWidth = 1;
292 break;
293 case ComponentGlyph:
294 pGlyphProp[i].sva.fClusterStart = 0;
295 pGlyphProp[i].sva.fDiacritic = 0;
296 pGlyphProp[i].sva.fZeroWidth = 0;
297 break;
298 default:
299 ERR("Unknown glyph class %i\n",class);
300 pGlyphProp[i].sva.fClusterStart = 1;
301 pGlyphProp[i].sva.fDiacritic = 0;
302 pGlyphProp[i].sva.fZeroWidth = 0;
305 if (char_count == 0)
306 pGlyphProp[i].sva.fClusterStart = 0;