From: Aric Stewart Subject: (resend 2)[5/5]dwrite: Implement TryGetFontTable and ReleaseFontTable Message-Id: <53F00880.1070106@codeweavers.com> Date: Sat, 16 Aug 2014 20:42:24 -0500 Some code cleanups and improvements found by later work. Track where the tables come from, Implement Release Font Table Fix a issues with truetype collections. --- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/font.c | 65 ++++++++++++++++++++++++++++++-- dlls/dwrite/opentype.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index f56b6f0..a64e632 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -94,3 +94,4 @@ extern HRESULT font_create_fontface(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE /* Opentype font table functions */ extern 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) DECLSPEC_HIDDEN; +extern HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32 tag, const void** table_data, void** table_context, UINT32 *table_size, BOOL* found) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 8c82d08..0b01d68 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -156,6 +156,14 @@ struct dwrite_font { WCHAR *facename; }; +#define DWRITE_FONTTABLE_MAGIC 0xededfafa + +struct dwrite_fonttable { + UINT32 magic; + LPVOID context; + UINT32 file_index; +}; + struct dwrite_fontface { IDWriteFontFace IDWriteFontFace_iface; LONG ref; @@ -384,14 +392,65 @@ static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace *iface, UIN const void **table_data, UINT32 *table_size, void **context, BOOL *exists) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); - FIXME("(%p)->(%u %p %p %p %p): stub\n", This, table_tag, table_data, table_size, context, exists); - return E_NOTIMPL; + if (This->is_system) + { + FIXME("(%p)->(%u %p %p %p %p): stub\n", This, table_tag, table_data, table_size, context, exists); + return E_NOTIMPL; + } + else + { + HRESULT hr; + int i; + struct dwrite_fonttable *table; + + TRACE("(%p)->(%u %p %p %p %p)\n", This, table_tag, table_data, table_size, context, exists); + + table = heap_alloc(sizeof(struct dwrite_fonttable)); + table->magic = DWRITE_FONTTABLE_MAGIC; + if (!table) + return E_OUTOFMEMORY; + + *exists = FALSE; + for (i = 0; i < This->file_count && !(*exists); i++) + { + IDWriteFontFileStream *stream; + hr = _dwritefontfile_GetFontFileStream(This->files[i], &stream); + if (FAILED(hr)) + continue; + table->file_index = i; + + hr = find_font_table(stream, This->index, table_tag, table_data, &table->context, table_size, exists); + + IDWriteFontFileStream_Release(stream); + } + if (FAILED(hr) && !*exists) + heap_free(table); + else + *context = (LPVOID)table; + return hr; + } } static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace *iface, void *table_context) { struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface); - FIXME("(%p)->(%p): stub\n", This, table_context); + struct dwrite_fonttable *table = (struct dwrite_fonttable *)table_context; + IDWriteFontFileStream *stream; + HRESULT hr; + TRACE("(%p)->(%p)\n", This, table_context); + + if (table->magic != DWRITE_FONTTABLE_MAGIC) + { + TRACE("Invalid table magic\n"); + return; + } + + hr = _dwritefontfile_GetFontFileStream(This->files[table->file_index], &stream); + if (FAILED(hr)) + return; + IDWriteFontFileStream_ReleaseFileFragment(stream, table->context); + IDWriteFontFileStream_Release(stream); + heap_free(table); } static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace *iface, FLOAT emSize, diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 538db98..6c90a96 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -47,6 +47,21 @@ typedef struct { DWORD OffsetTable[1]; } TTC_Header_V1; +typedef struct { + DWORD version; + WORD numTables; + WORD searchRange; + WORD entrySelector; + WORD rangeShift; +} TTC_SFNT_V1; + +typedef struct { + CHAR tag[4]; + DWORD checkSum; + DWORD offset; + DWORD length; +} TT_TableRecord; + 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) { /* TODO: Do font validation */ @@ -81,3 +96,76 @@ HRESULT analyze_opentype_font(const void* font_data, UINT32* font_count, DWRITE_ } return S_OK; } + +HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32 tag, const void** table_data, void** table_context, UINT32 *table_size, BOOL* found) +{ + const CHAR *first_data; + void *first_context; + HRESULT hr; + TTC_SFNT_V1 *font_header = NULL; + void *sfnt_context; + TT_TableRecord *table_record = NULL; + void *table_record_context; + int i; + int table_count; + int table_offset = 0; + + *found = FALSE; + + hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&first_data, 0, 4, &first_context); + if (SUCCEEDED(hr)) + { + if (DWRITE_MAKE_OPENTYPE_TAG(first_data[0], first_data[1], first_data[2], first_data[3]) == MS_TTCF_TAG) + { + const TTC_Header_V1 *ttc_header; + void * ttc_context; + hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&ttc_header, 0, sizeof(*ttc_header), &ttc_context); + if (SUCCEEDED(hr)) + { + table_offset = GET_BE_DWORD(ttc_header->OffsetTable[0]); + if (font_index >= GET_BE_DWORD(ttc_header->numFonts)) + hr = E_INVALIDARG; + else + hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, table_offset, sizeof(*font_header), &sfnt_context); + IDWriteFontFileStream_ReleaseFileFragment(stream, ttc_context); + } + } + else + { + if (font_index > 0) + hr = E_INVALIDARG; + else + hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, 0, sizeof(*font_header), &sfnt_context); + } + IDWriteFontFileStream_ReleaseFileFragment(stream, first_context); + } + if (FAILED(hr)) + return hr; + + table_count = GET_BE_WORD(font_header->numTables); + table_offset += sizeof(*font_header); + for (i = 0; i < table_count; i++) + { + hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&table_record, table_offset, sizeof(*table_record), &table_record_context); + if (FAILED(hr)) + break; + if (DWRITE_MAKE_OPENTYPE_TAG(table_record->tag[0], table_record->tag[1], table_record->tag[2], table_record->tag[3]) == tag) + break; + IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context); + table_offset += sizeof(*table_record); + } + + IDWriteFontFileStream_ReleaseFileFragment(stream, sfnt_context); + if (SUCCEEDED(hr) && i < table_count) + { + int offset = GET_BE_DWORD(table_record->offset); + int length = GET_BE_DWORD(table_record->length); + IDWriteFontFileStream_ReleaseFileFragment(stream, table_record_context); + + *found = TRUE; + *table_size = length; + hr = IDWriteFontFileStream_ReadFileFragment(stream, table_data, offset, length, table_context); + } + + return hr; +}