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
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)
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)))
69 } CMAP_EncodingRecord
;
74 CMAP_EncodingRecord tables
[1];
81 } CMAP_SegmentedCoverage_group
;
89 CMAP_SegmentedCoverage_group groups
[1];
90 } CMAP_SegmentedCoverage
;
101 } CMAP_SegmentMapping_0
;
103 /* PANOSE is 10 bytes in size, need to pack the structure properly */
104 #include "pshpack2.h"
120 USHORT lowestRecPPEM
;
121 SHORT direction_hint
;
123 SHORT glyphdata_format
;
130 SHORT underlinePosition
;
131 SHORT underlineThickness
;
143 USHORT usWeightClass
;
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
;
158 ULONG ulUnicodeRange1
;
159 ULONG ulUnicodeRange2
;
160 ULONG ulUnicodeRange3
;
161 ULONG ulUnicodeRange4
;
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
;
175 /* version 1 (TrueType 1.66) */
176 ULONG ulCodePageRange1
;
177 ULONG ulCodePageRange2
;
178 /* version 2 (OpenType 1.2) */
181 USHORT usDefaultChar
;
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
;
193 *file_type
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
195 *face_type
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
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
;
204 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION
;
207 else if (GET_BE_DWORD(*(DWORD
*)font_data
) == 0x10000)
210 *file_type
= DWRITE_FONT_FILE_TYPE_TRUETYPE
;
212 *face_type
= DWRITE_FONT_FACE_TYPE_TRUETYPE
;
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
;
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
;
227 TTC_SFNT_V1
*font_header
= NULL
;
229 TT_TableRecord
*table_record
= NULL
;
230 void *table_record_context
;
233 int table_offset
= 0;
237 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&first_data
, 0, 4, &first_context
);
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
;
244 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&ttc_header
, 0, sizeof(*ttc_header
), &ttc_context
);
247 table_offset
= GET_BE_DWORD(ttc_header
->OffsetTable
[0]);
248 if (font_index
>= GET_BE_DWORD(ttc_header
->numFonts
))
251 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, table_offset
, sizeof(*font_header
), &sfnt_context
);
252 IDWriteFontFileStream_ReleaseFileFragment(stream
, ttc_context
);
260 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, (const void**)&font_header
, 0, sizeof(*font_header
), &sfnt_context
);
262 IDWriteFontFileStream_ReleaseFileFragment(stream
, first_context
);
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
);
274 if (DWRITE_MAKE_OPENTYPE_TAG(table_record
->tag
[0], table_record
->tag
[1], table_record
->tag
[2], table_record
->tag
[3]) == tag
)
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
);
288 *table_size
= length
;
289 hr
= IDWriteFontFileStream_ReadFileFragment(stream
, table_data
, offset
, length
, table_context
);
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
))
306 if (*chr
> GET_BE_DWORD(group
->endCharCode
))
311 static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0
* format
, DWORD utf32c
, LPWORD pgi
)
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
));
325 while(GET_BE_WORD(format
->endCode
[segment
]) < 0xffff)
327 if (utf32c
<= GET_BE_WORD(format
->endCode
[segment
]))
331 if (segment
>= segment_count
)
333 TRACE("Segment %i of %i\n",segment
, segment_count
);
334 if (GET_BE_WORD(startCode
[segment
]) > utf32c
)
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
;
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
);
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
)
367 CMAP_Header
*CMAP_Table
= NULL
;
369 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
376 for (i
= 0; i
< GET_BE_WORD(CMAP_Table
->numTables
); i
++)
381 if (GET_BE_WORD(CMAP_Table
->tables
[i
].platformID
) != 3)
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 */
391 CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0
*) table
, utf32c
, pgi
);
394 CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage
*) table
, utf32c
, pgi
);
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 */
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
);
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
;
444 metrics
->underlinePosition
= GET_BE_WORD(tt_post
->underlinePosition
);
445 metrics
->underlineThickness
= GET_BE_WORD(tt_post
->underlineThickness
);