shlwapi: Remove unnecessary internal function SHLWAPI_DupSharedHandle.
[wine/wine-gecko.git] / dlls / dwrite / opentype.c
blob532c126ef8a865454728e379b34b6bbe83489ea1
1 /*
2 * Methods for dealing with opentype font tables
4 * Copyright 2014 Aric Stewart for CodeWeavers
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 #define COBJMACROS
23 #include "dwrite.h"
24 #include "dwrite_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
28 #define DWRITE_MAKE_OPENTYPE_TAG(ch0, ch1, ch2, ch3) \
29 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
30 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
32 #define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f')
33 #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O')
35 #ifdef WORDS_BIGENDIAN
36 #define GET_BE_WORD(x) (x)
37 #define GET_BE_DWORD(x) (x)
38 #else
39 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
40 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)))
41 #endif
43 typedef struct {
44 CHAR TTCTag[4];
45 DWORD Version;
46 DWORD numFonts;
47 DWORD OffsetTable[1];
48 } TTC_Header_V1;
50 typedef struct {
51 DWORD version;
52 WORD numTables;
53 WORD searchRange;
54 WORD entrySelector;
55 WORD rangeShift;
56 } TTC_SFNT_V1;
58 typedef struct {
59 CHAR tag[4];
60 DWORD checkSum;
61 DWORD offset;
62 DWORD length;
63 } TT_TableRecord;
65 typedef struct {
66 WORD platformID;
67 WORD encodingID;
68 DWORD offset;
69 } CMAP_EncodingRecord;
71 typedef struct {
72 WORD version;
73 WORD numTables;
74 CMAP_EncodingRecord tables[1];
75 } CMAP_Header;
77 typedef struct {
78 DWORD startCharCode;
79 DWORD endCharCode;
80 DWORD startGlyphID;
81 } CMAP_SegmentedCoverage_group;
83 typedef struct {
84 WORD format;
85 WORD reserved;
86 DWORD length;
87 DWORD language;
88 DWORD nGroups;
89 CMAP_SegmentedCoverage_group groups[1];
90 } CMAP_SegmentedCoverage;
92 typedef struct {
93 WORD format;
94 WORD length;
95 WORD language;
96 WORD segCountX2;
97 WORD searchRange;
98 WORD entrySelector;
99 WORD rangeShift;
100 WORD endCode[1];
101 } CMAP_SegmentMapping_0;
103 /* PANOSE is 10 bytes in size, need to pack the structure properly */
104 #include "pshpack2.h"
105 typedef struct
107 ULONG version;
108 ULONG revision;
109 ULONG checksumadj;
110 ULONG magic;
111 USHORT flags;
112 USHORT unitsPerEm;
113 ULONGLONG created;
114 ULONGLONG modified;
115 SHORT xMin;
116 SHORT yMin;
117 SHORT xMax;
118 SHORT yMax;
119 USHORT macStyle;
120 USHORT lowestRecPPEM;
121 SHORT direction_hint;
122 SHORT index_format;
123 SHORT glyphdata_format;
124 } TT_HEAD;
126 typedef struct
128 ULONG Version;
129 ULONG italicAngle;
130 SHORT underlinePosition;
131 SHORT underlineThickness;
132 ULONG fixed_pitch;
133 ULONG minmemType42;
134 ULONG maxmemType42;
135 ULONG minmemType1;
136 ULONG maxmemType1;
137 } TT_POST;
139 typedef struct
141 USHORT version;
142 SHORT xAvgCharWidth;
143 USHORT usWeightClass;
144 USHORT usWidthClass;
145 SHORT fsType;
146 SHORT ySubscriptXSize;
147 SHORT ySubscriptYSize;
148 SHORT ySubscriptXOffset;
149 SHORT ySubscriptYOffset;
150 SHORT ySuperscriptXSize;
151 SHORT ySuperscriptYSize;
152 SHORT ySuperscriptXOffset;
153 SHORT ySuperscriptYOffset;
154 SHORT yStrikeoutSize;
155 SHORT yStrikeoutPosition;
156 SHORT sFamilyClass;
157 PANOSE panose;
158 ULONG ulUnicodeRange1;
159 ULONG ulUnicodeRange2;
160 ULONG ulUnicodeRange3;
161 ULONG ulUnicodeRange4;
162 CHAR achVendID[4];
163 USHORT fsSelection;
164 USHORT usFirstCharIndex;
165 USHORT usLastCharIndex;
166 /* According to the Apple spec, original version didn't have the below fields,
167 * version numbers were taken from the OpenType spec.
169 /* version 0 (TrueType 1.5) */
170 USHORT sTypoAscender;
171 USHORT sTypoDescender;
172 USHORT sTypoLineGap;
173 USHORT usWinAscent;
174 USHORT usWinDescent;
175 /* version 1 (TrueType 1.66) */
176 ULONG ulCodePageRange1;
177 ULONG ulCodePageRange2;
178 /* version 2 (OpenType 1.2) */
179 SHORT sxHeight;
180 SHORT sCapHeight;
181 USHORT usDefaultChar;
182 USHORT usBreakChar;
183 USHORT usMaxContext;
184 } TT_OS2_V2;
185 #include "poppack.h"
187 HRESULT analyze_opentype_font(const void* font_data, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
189 /* TODO: Do font validation */
190 const char* tag = font_data;
192 *supported = FALSE;
193 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
194 if (face_type)
195 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
196 *font_count = 0;
198 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
200 const TTC_Header_V1 *header = font_data;
201 *font_count = GET_BE_DWORD(header->numFonts);
202 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
203 if (face_type)
204 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
205 *supported = TRUE;
207 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
209 *font_count = 1;
210 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
211 if (face_type)
212 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
213 *supported = TRUE;
215 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
217 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
219 return S_OK;
222 HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32 tag, const void** table_data, void** table_context, UINT32 *table_size, BOOL* found)
224 const CHAR *first_data;
225 void *first_context;
226 HRESULT hr;
227 TTC_SFNT_V1 *font_header = NULL;
228 void *sfnt_context;
229 TT_TableRecord *table_record = NULL;
230 void *table_record_context;
231 int i;
232 int table_count;
233 int table_offset = 0;
235 *found = FALSE;
237 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&first_data, 0, 4, &first_context);
238 if (SUCCEEDED(hr))
240 if (DWRITE_MAKE_OPENTYPE_TAG(first_data[0], first_data[1], first_data[2], first_data[3]) == MS_TTCF_TAG)
242 const TTC_Header_V1 *ttc_header;
243 void * ttc_context;
244 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
245 if (SUCCEEDED(hr))
247 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
248 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
249 hr = E_INVALIDARG;
250 else
251 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
252 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
255 else
257 if (font_index > 0)
258 hr = E_INVALIDARG;
259 else
260 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
262 IDWriteFontFileStream_ReleaseFileFragment(stream, first_context);
264 if (FAILED(hr))
265 return hr;
267 table_count = GET_BE_WORD(font_header->numTables);
268 table_offset += sizeof(*font_header);
269 for (i = 0; i < table_count; i++)
271 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
272 if (FAILED(hr))
273 break;
274 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
275 break;
276 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
277 table_offset += sizeof(*table_record);
280 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
281 if (SUCCEEDED(hr) && i < table_count)
283 int offset = GET_BE_DWORD(table_record->offset);
284 int length = GET_BE_DWORD(table_record->length);
285 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
287 *found = TRUE;
288 *table_size = length;
289 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
292 return hr;
295 /**********
296 * CMAP
297 **********/
299 static int compare_group(const void *a, const void* b)
301 const DWORD *chr = a;
302 const CMAP_SegmentedCoverage_group *group = b;
304 if (*chr < GET_BE_DWORD(group->startCharCode))
305 return -1;
306 if (*chr > GET_BE_DWORD(group->endCharCode))
307 return 1;
308 return 0;
311 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0* format, DWORD utf32c, LPWORD pgi)
313 WORD *startCode;
314 SHORT *idDelta;
315 WORD *idRangeOffset;
316 int segment;
318 int segment_count = GET_BE_WORD(format->segCountX2)/2;
319 /* This is correct because of the padding before startCode */
320 startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
321 idDelta = (SHORT*)(((BYTE*)startCode) + (sizeof(WORD) * segment_count));
322 idRangeOffset = (WORD*)(((BYTE*)idDelta) + (sizeof(WORD) * segment_count));
324 segment = 0;
325 while(GET_BE_WORD(format->endCode[segment]) < 0xffff)
327 if (utf32c <= GET_BE_WORD(format->endCode[segment]))
328 break;
329 segment++;
331 if (segment >= segment_count)
332 return;
333 TRACE("Segment %i of %i\n",segment, segment_count);
334 if (GET_BE_WORD(startCode[segment]) > utf32c)
335 return;
336 TRACE("In range %i -> %i\n", GET_BE_WORD(startCode[segment]), GET_BE_WORD(format->endCode[segment]));
337 if (GET_BE_WORD(idRangeOffset[segment]) == 0)
339 *pgi = (SHORT)(GET_BE_WORD(idDelta[segment])) + utf32c;
341 else
343 WORD ro = GET_BE_WORD(idRangeOffset[segment])/2;
344 WORD co = (utf32c - GET_BE_WORD(startCode[segment]));
345 WORD *index = (WORD*)((BYTE*)&idRangeOffset[segment] + (ro + co));
346 *pgi = GET_BE_WORD(*index);
350 static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage* format, DWORD utf32c, LPWORD pgi)
352 CMAP_SegmentedCoverage_group *group = NULL;
354 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
355 sizeof(CMAP_SegmentedCoverage_group), compare_group);
357 if (group)
359 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
360 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
364 VOID OpenType_CMAP_GetGlyphIndex(LPVOID data, DWORD utf32c, LPWORD pgi, DWORD flags)
366 int i;
367 CMAP_Header *CMAP_Table = NULL;
369 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
370 *pgi = 0xffff;
371 else
372 *pgi = 0;
374 CMAP_Table = data;
376 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
378 WORD type;
379 WORD *table;
381 if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
382 continue;
384 table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
385 type = GET_BE_WORD(*table);
386 TRACE("Type %i\n", type);
387 /* Break when we find a handled type */
388 switch(type)
390 case 4:
391 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi);
392 break;
393 case 12:
394 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi);
395 break;
396 default:
397 TRACE("Type %i unhandled.\n", type);
402 VOID get_font_properties(LPCVOID os2, LPCVOID head, LPCVOID post, DWRITE_FONT_METRICS *metrics, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style)
404 TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2;
405 TT_HEAD *tt_head = (TT_HEAD*)head;
406 TT_POST *tt_post = (TT_POST*)post;
408 /* default stretch, weight and style to normal */
409 *stretch = DWRITE_FONT_STRETCH_NORMAL;
410 *weight = DWRITE_FONT_WEIGHT_NORMAL;
411 *style = DWRITE_FONT_STYLE_NORMAL;
413 memset(metrics, 0, sizeof(*metrics));
415 /* DWRITE_FONT_STRETCH enumeration values directly match font data values */
416 if (tt_os2)
418 if (GET_BE_WORD(tt_os2->usWidthClass) <= DWRITE_FONT_STRETCH_ULTRA_EXPANDED)
419 *stretch = GET_BE_WORD(tt_os2->usWidthClass);
421 *weight = GET_BE_WORD(tt_os2->usWeightClass);
422 TRACE("stretch=%d, weight=%d\n", *stretch, *weight);
424 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
425 metrics->descent = GET_BE_WORD(tt_os2->sTypoDescender);
426 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
427 metrics->capHeight = GET_BE_WORD(tt_os2->sCapHeight);
428 metrics->xHeight = GET_BE_WORD(tt_os2->sxHeight);
429 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
430 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
433 if (tt_head)
435 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
436 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
437 if (macStyle & 0x0002)
438 *style = DWRITE_FONT_STYLE_ITALIC;
442 if (tt_post)
444 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
445 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);