From: Aric Stewart Subject: (resend)[5/5]dwrite: Implement TryGetFontTable Message-Id: <53EA66F6.3090609@codeweavers.com> Date: Tue, 12 Aug 2014 14:11:50 -0500 --- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/font.c | 28 +++++++++++++- dlls/dwrite/opentype.c | 87 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 2 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 c053bc5..a8d62cd 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -370,8 +370,32 @@ 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; + + TRACE("(%p)->(%u %p %p %p %p)\n", This, table_tag, table_data, table_size, context, exists); + + *exists = FALSE; + for (i = 0; i < This->file_count && !(*exists); i++) + { + IDWriteFontFileStream *stream; + hr = _dwritefontfile_GetFontFileStream(This->files[i], &stream); + if (FAILED(hr)) + continue; + + hr = find_font_table(stream, This->index, table_tag, table_data, context, table_size, exists); + + IDWriteFontFileStream_Release(stream); + } + return hr; + } } static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace *iface, void *table_context) diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 538db98..474a0cc 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,75 @@ 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; + + *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)) + { + if (font_index > GET_BE_DWORD(ttc_header->numFonts)) + hr = E_INVALIDARG; + else + hr = IDWriteFontFileStream_ReadFileFragment(stream, (const void**)&font_header, GET_BE_DWORD(ttc_header->OffsetTable[font_index]), 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; +}