dwrite: Implement TryGetFontTable and ReleaseFontTable.
[wine.git] / dlls / dwrite / opentype.c
blob6c90a961b8711a3789f7dd46325438b4ed10e50a
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 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)
67 /* TODO: Do font validation */
68 const char* tag = font_data;
70 *supported = FALSE;
71 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
72 if (face_type)
73 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
74 *font_count = 0;
76 if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_TTCF_TAG)
78 const TTC_Header_V1 *header = font_data;
79 *font_count = GET_BE_DWORD(header->numFonts);
80 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION;
81 if (face_type)
82 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION;
83 *supported = TRUE;
85 else if (GET_BE_DWORD(*(DWORD*)font_data) == 0x10000)
87 *font_count = 1;
88 *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
89 if (face_type)
90 *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
91 *supported = TRUE;
93 else if (DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]) == MS_OTTO_TAG)
95 *file_type = DWRITE_FONT_FILE_TYPE_CFF;
97 return S_OK;
100 HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32 tag, const void** table_data, void** table_context, UINT32 *table_size, BOOL* found)
102 const CHAR *first_data;
103 void *first_context;
104 HRESULT hr;
105 TTC_SFNT_V1 *font_header = NULL;
106 void *sfnt_context;
107 TT_TableRecord *table_record = NULL;
108 void *table_record_context;
109 int i;
110 int table_count;
111 int table_offset = 0;
113 *found = FALSE;
115 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&first_data, 0, 4, &first_context);
116 if (SUCCEEDED(hr))
118 if (DWRITE_MAKE_OPENTYPE_TAG(first_data[0], first_data[1], first_data[2], first_data[3]) == MS_TTCF_TAG)
120 const TTC_Header_V1 *ttc_header;
121 void * ttc_context;
122 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context);
123 if (SUCCEEDED(hr))
125 table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]);
126 if (font_index >= GET_BE_DWORD(ttc_header->numFonts))
127 hr = E_INVALIDARG;
128 else
129 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context);
130 IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context);
133 else
135 if (font_index > 0)
136 hr = E_INVALIDARG;
137 else
138 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context);
140 IDWriteFontFileStream_ReleaseFileFragment(stream, first_context);
142 if (FAILED(hr))
143 return hr;
145 table_count = GET_BE_WORD(font_header->numTables);
146 table_offset += sizeof(*font_header);
147 for (i = 0; i < table_count; i++)
149 hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context);
150 if (FAILED(hr))
151 break;
152 if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag)
153 break;
154 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
155 table_offset += sizeof(*table_record);
158 IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context);
159 if (SUCCEEDED(hr) && i < table_count)
161 int offset = GET_BE_DWORD(table_record->offset);
162 int length = GET_BE_DWORD(table_record->length);
163 IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context);
165 *found = TRUE;
166 *table_size = length;
167 hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context);
170 return hr;