From 95466a1c2f50f5df22c34be76c809db4a3dd18af Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Tue, 26 Aug 2014 08:11:59 -0700 Subject: [PATCH] dwrite: Beginning implementation of IDWriteLocalFontFileLoader. --- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/font.c | 245 +++++++++++++++++++++++++++++++++++ dlls/dwrite/main.c | 17 ++- dlls/dwrite/tests/font.c | 46 +++++++ 4 files changed, 307 insertions(+), 2 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index a64e6322f34..0f386ce6219 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -90,6 +90,7 @@ extern HRESULT get_system_fontcollection(IDWriteFontCollection**) DECLSPEC_HIDDE extern void release_system_fontcollection(void) DECLSPEC_HIDDEN; extern HRESULT get_textanalyzer(IDWriteTextAnalyzer**) DECLSPEC_HIDDEN; extern HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file) DECLSPEC_HIDDEN; +extern HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) DECLSPEC_HIDDEN; extern HRESULT font_create_fontface(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index, DWRITE_FONT_SIMULATIONS sim_flags, IDWriteFontFace **font_face) DECLSPEC_HIDDEN; /* Opentype font table functions */ diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 277046ef277..6c3d1626da8 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -1296,3 +1296,248 @@ HRESULT font_create_fontface(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE facety return S_OK; } + +/* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */ + +struct dwrite_localfontfilestream +{ + IDWriteFontFileStream IDWriteFontFileStream_iface; + LONG ref; + + HANDLE handle; +}; + +struct dwrite_localfontfileloader { + IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface; + LONG ref; +}; + +static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface) +{ + return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface); +} + +static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface) +{ + return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface); +} + +static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream)) + { + *obj = iface; + IDWriteFontFileStream_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p)->(%d)\n", This, ref); + return ref; +} + +static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%d)\n", This, ref); + + if (!ref) + { + if (This->handle != INVALID_HANDLE_VALUE) + CloseHandle(This->handle); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + LARGE_INTEGER distance; + DWORD bytes = fragment_size; + DWORD read; + + TRACE("(%p)->(%p, %s, %s, %p)\n",This, fragment_start, + wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context); + + *fragment_context = NULL; + distance.QuadPart = offset; + if (!SetFilePointerEx(This->handle, distance, NULL, FILE_BEGIN)) + return E_FAIL; + *fragment_start = *fragment_context = heap_alloc(bytes); + if (!*fragment_context) + return E_FAIL; + if (!ReadFile(This->handle, *fragment_context, bytes, &read, NULL)) + { + heap_free(*fragment_context); + return E_FAIL; + } + + return S_OK; +} + +static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + TRACE("(%p)->(%p)\n", This, fragment_context); + heap_free(fragment_context); +} + +static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + LARGE_INTEGER li; + TRACE("(%p)->(%p)\n",This, size); + GetFileSizeEx(This->handle, &li); + *size = li.QuadPart; + return S_OK; +} + +static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime) +{ + struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); + FIXME("(%p)->(%p): stub\n",This, last_writetime); + *last_writetime = 0; + return E_NOTIMPL; +} + +static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl = +{ + localfontfilestream_QueryInterface, + localfontfilestream_AddRef, + localfontfilestream_Release, + localfontfilestream_ReadFileFragment, + localfontfilestream_ReleaseFileFragment, + localfontfilestream_GetFileSize, + localfontfilestream_GetLastWriteTime +}; + +static HRESULT create_localfontfilestream(HANDLE handle, IDWriteFontFileStream** iface) +{ + struct dwrite_localfontfilestream *This = heap_alloc(sizeof(struct dwrite_localfontfilestream)); + if (!This) + return E_OUTOFMEMORY; + + This->ref = 1; + This->handle = handle; + This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl; + + *iface = &This->IDWriteFontFileStream_iface; + return S_OK; +} + +static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj) +{ + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader)) + { + *obj = iface; + IDWriteLocalFontFileLoader_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface) +{ + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p)->(%d)\n", This, ref); + return ref; +} + +static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface) +{ + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%d)\n", This, ref); + + if (!ref) + heap_free(This); + + return ref; +} + +static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *fontFileReferenceKey, UINT32 fontFileReferenceKeySize, IDWriteFontFileStream **fontFileStream) +{ + HANDLE handle; + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + const WCHAR *name = (const WCHAR*)fontFileReferenceKey; + + TRACE("(%p)->(%p, %i, %p)\n",This, fontFileReferenceKey, fontFileReferenceKeySize, fontFileStream); + + TRACE("name: %s\n",debugstr_w(name)); + handle = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) + return E_FAIL; + + return create_localfontfilestream(handle, fontFileStream); +} + +static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length) +{ + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + TRACE("(%p)->(%p, %i, %p)\n",This, key, key_size, length); + *length = key_size; + return S_OK; +} + +static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length) +{ + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + TRACE("(%p)->(%p, %i, %p, %i)\n",This, key, key_size, path, length); + if (length < key_size) + return E_INVALIDARG; + lstrcpynW((WCHAR*)key, path, key_size); + return S_OK; +} + +static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime) +{ + struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); + FIXME("(%p)->(%p, %i, %p):stub \n",This, key, key_size, writetime); + return E_NOTIMPL; +} + +static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = { + localfontfileloader_QueryInterface, + localfontfileloader_AddRef, + localfontfileloader_Release, + localfontfileloader_CreateStreamFromKey, + localfontfileloader_GetFilePathLengthFromKey, + localfontfileloader_GetFilePathFromKey, + localfontfileloader_GetLastWriteTimeFromKey +}; + +HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) +{ + struct dwrite_localfontfileloader *This = heap_alloc(sizeof(struct dwrite_localfontfileloader)); + if (!This) + return E_OUTOFMEMORY; + + This->ref = 1; + This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl; + + *iface = &This->IDWriteLocalFontFileLoader_iface; + return S_OK; +} diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c index abe61643238..59d9d64ae3e 100644 --- a/dlls/dwrite/main.c +++ b/dlls/dwrite/main.c @@ -363,6 +363,8 @@ struct dwritefactory{ IDWriteFactory IDWriteFactory_iface; LONG ref; + IDWriteLocalFontFileLoader* localfontfileloader; + IDWriteFontCollectionLoader **loaders; LONG loader_count; IDWriteFontFileLoader **file_loaders; @@ -410,6 +412,8 @@ static ULONG WINAPI dwritefactory_Release(IDWriteFactory *iface) if (!ref) { int i; + if (This->localfontfileloader) + IDWriteLocalFontFileLoader_Release(This->localfontfileloader); for (i = 0; i < This->loader_count; i++) if (This->loaders[i]) IDWriteFontCollectionLoader_Release(This->loaders[i]); @@ -501,9 +505,17 @@ static HRESULT WINAPI dwritefactory_UnregisterFontCollectionLoader(IDWriteFactor static HRESULT WINAPI dwritefactory_CreateFontFileReference(IDWriteFactory *iface, WCHAR const *path, FILETIME const *writetime, IDWriteFontFile **font_file) { + HRESULT hr; struct dwritefactory *This = impl_from_IDWriteFactory(iface); - FIXME("(%p)->(%s %p %p): stub\n", This, debugstr_w(path), writetime, font_file); - return E_NOTIMPL; + TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(path), writetime, font_file); + + if (!This->localfontfileloader) + { + hr = create_localfontfileloader(&This->localfontfileloader); + if (FAILED(hr)) + return hr; + } + return create_font_file((IDWriteFontFileLoader*)This->localfontfileloader, path, sizeof(WCHAR) * (strlenW(path)+1), font_file); } static HRESULT WINAPI dwritefactory_CreateCustomFontFileReference(IDWriteFactory *iface, @@ -742,6 +754,7 @@ HRESULT WINAPI DWriteCreateFactory(DWRITE_FACTORY_TYPE type, REFIID riid, IUnkno This->IDWriteFactory_iface.lpVtbl = &dwritefactoryvtbl; This->ref = 1; + This->localfontfileloader = NULL; This->loader_count = 2; This->loaders = heap_alloc_zero(sizeof(*This->loaders) * 2); This->file_loader_count = 2; diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 93e3105bd69..7a90c58ff76 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -989,6 +989,51 @@ static void test_FontLoader(void) ok(hr == S_OK, "got 0x%08x\n", hr); } +static void test_CreateFontFileReference(void) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + HRESULT hr; + WCHAR font_name[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0}; + IDWriteFontFile *ffile = NULL; + BOOL support = 1; + DWRITE_FONT_FILE_TYPE type = 1; + DWRITE_FONT_FACE_TYPE face = 1; + UINT32 count = 1; + IDWriteFontFace *fface = NULL; + + file = CreateFileW(font_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "file creation failed\n" ); + if (file == INVALID_HANDLE_VALUE) return; + + res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); + + hr = IDWriteFactory_CreateFontFileReference(factory, font_name, NULL, &ffile); + ok(hr == S_OK, "got 0x%08x\n",hr); + + IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(support == TRUE, "got %i\n", support); + ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type); + ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face); + ok(count == 1, "got %i\n", count); + + hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, 0, &fface); + ok(hr == S_OK, "got 0x%08x\n",hr); + + IDWriteFontFace_Release(fface); + IDWriteFontFile_Release(ffile); + + DeleteFileW(font_name); +} + START_TEST(font) { HRESULT hr; @@ -1011,6 +1056,7 @@ START_TEST(font) test_ConvertFontFaceToLOGFONT(); test_CustomFontCollection(); test_FontLoader(); + test_CreateFontFileReference(); IDWriteFactory_Release(factory); }