[PATCH] dwrite: Add support for memory font resources in CreateFontFaceFromHdc().
Nikolay Sivov
nsivov at codeweavers.com
Thu Nov 22 05:29:14 CST 2018
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/gdiinterop.c | 200 ++++++++++++++++++++++++++++++++++++++-
dlls/dwrite/tests/font.c | 71 ++++++++++++--
2 files changed, 261 insertions(+), 10 deletions(-)
diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c
index 5501f377c4..2e4a949286 100644
--- a/dlls/dwrite/gdiinterop.c
+++ b/dlls/dwrite/gdiinterop.c
@@ -2,7 +2,7 @@
* GDI Interop
*
* Copyright 2011 Huw Davies
- * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
+ * Copyright 2012, 2014-2018 Nikolay Sivov for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -54,10 +54,17 @@ struct rendertarget {
struct gdiinterop {
IDWriteGdiInterop1 IDWriteGdiInterop1_iface;
+ IDWriteFontFileLoader IDWriteFontFileLoader_iface;
LONG ref;
IDWriteFactory5 *factory;
};
+struct memresource_stream {
+ IDWriteFontFileStream IDWriteFontFileStream_iface;
+ LONG ref;
+ DWORD key;
+};
+
static inline int get_dib_stride(int width, int bpp)
{
return ((width * bpp + 31) >> 3) & ~3;
@@ -111,6 +118,16 @@ static inline struct gdiinterop *impl_from_IDWriteGdiInterop1(IDWriteGdiInterop1
return CONTAINING_RECORD(iface, struct gdiinterop, IDWriteGdiInterop1_iface);
}
+static inline struct gdiinterop *impl_from_IDWriteFontFileLoader(IDWriteFontFileLoader *iface)
+{
+ return CONTAINING_RECORD(iface, struct gdiinterop, IDWriteFontFileLoader_iface);
+}
+
+static inline struct memresource_stream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
+{
+ return CONTAINING_RECORD(iface, struct memresource_stream, IDWriteFontFileStream_iface);
+}
+
static HRESULT WINAPI rendertarget_sink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **obj)
{
if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
@@ -637,6 +654,7 @@ static ULONG WINAPI gdiinterop_Release(IDWriteGdiInterop1 *iface)
TRACE("(%p)->(%d)\n", This, ref);
if (!ref) {
+ IDWriteFactory5_UnregisterFontFileLoader(This->factory, &This->IDWriteFontFileLoader_iface);
factory_detach_gdiinterop(This->factory, iface);
heap_free(This);
}
@@ -728,6 +746,7 @@ struct font_fileinfo {
/* Undocumented gdi32 exports, used to access actually selected font information */
extern BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info);
extern BOOL WINAPI GetFontFileInfo(DWORD instance_id, DWORD unknown, struct font_fileinfo *info, SIZE_T size, SIZE_T *needed);
+extern BOOL WINAPI GetFontFileData(DWORD instance_id, DWORD unknown, UINT64 offset, void *buff, DWORD buff_size);
static HRESULT WINAPI gdiinterop_CreateFontFaceFromHdc(IDWriteGdiInterop1 *iface,
HDC hdc, IDWriteFontFace **fontface)
@@ -773,8 +792,12 @@ static HRESULT WINAPI gdiinterop_CreateFontFaceFromHdc(IDWriteGdiInterop1 *iface
return E_FAIL;
}
- hr = IDWriteFactory5_CreateFontFileReference(This->factory, fileinfo->path, &fileinfo->writetime,
- &file);
+ if (*fileinfo->path)
+ hr = IDWriteFactory5_CreateFontFileReference(This->factory, fileinfo->path, &fileinfo->writetime, &file);
+ else
+ hr = IDWriteFactory5_CreateCustomFontFileReference(This->factory, &info.instance_id, sizeof(info.instance_id),
+ &This->IDWriteFontFileLoader_iface, &file);
+
heap_free(fileinfo);
if (FAILED(hr))
return hr;
@@ -897,6 +920,175 @@ static const struct IDWriteGdiInterop1Vtbl gdiinteropvtbl = {
gdiinterop1_GetMatchingFontsByLOGFONT
};
+static HRESULT WINAPI memresourcestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **out)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+
+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
+
+ if (IsEqualIID(&IID_IDWriteFontFileStream, riid) || IsEqualIID(&IID_IUnknown, riid)) {
+ *out = iface;
+ IDWriteFontFileStream_AddRef(iface);
+ return S_OK;
+ }
+
+ *out = NULL;
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI memresourcestream_AddRef(IDWriteFontFileStream *iface)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("(%p)->(%d)\n", This, ref);
+ return ref;
+}
+
+static ULONG WINAPI memresourcestream_Release(IDWriteFontFileStream *iface)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p)->(%d)\n", This, ref);
+
+ if (!ref)
+ heap_free(This);
+
+ return ref;
+}
+
+static HRESULT WINAPI memresourcestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
+ UINT64 offset, UINT64 fragment_size, void **fragment_context)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+ struct font_fileinfo fileinfo;
+ void *fragment;
+
+ TRACE("(%p)->(%p %s %s %p)\n", This, fragment_start, wine_dbgstr_longlong(offset),
+ wine_dbgstr_longlong(fragment_size), fragment_context);
+
+ *fragment_context = NULL;
+ *fragment_start = NULL;
+
+ if (!GetFontFileInfo(This->key, 0, &fileinfo, sizeof(fileinfo), NULL))
+ return E_INVALIDARG;
+
+ if ((offset >= fileinfo.size.QuadPart - 1) || (fragment_size > fileinfo.size.QuadPart - offset))
+ return E_INVALIDARG;
+
+ if (!(fragment = heap_alloc(fragment_size)))
+ return E_OUTOFMEMORY;
+
+ if (!GetFontFileData(This->key, 0, offset, fragment, fragment_size))
+ return E_FAIL;
+
+ *fragment_start = *fragment_context = fragment;
+ return S_OK;
+}
+
+static void WINAPI memresourcestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+
+ TRACE("(%p)->(%p)\n", This, fragment_context);
+
+ heap_free(fragment_context);
+}
+
+static HRESULT WINAPI memresourcestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+ struct font_fileinfo fileinfo;
+
+ TRACE("(%p)->(%p)\n", This, size);
+
+ if (!GetFontFileInfo(This->key, 0, &fileinfo, sizeof(fileinfo), NULL))
+ return E_INVALIDARG;
+
+ *size = fileinfo.size.QuadPart;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI memresourcestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
+{
+ struct memresource_stream *This = impl_from_IDWriteFontFileStream(iface);
+
+ TRACE("(%p)->(%p)\n", This, last_writetime);
+
+ return E_NOTIMPL;
+}
+
+static const struct IDWriteFontFileStreamVtbl memresourcestreamvtbl = {
+ memresourcestream_QueryInterface,
+ memresourcestream_AddRef,
+ memresourcestream_Release,
+ memresourcestream_ReadFileFragment,
+ memresourcestream_ReleaseFileFragment,
+ memresourcestream_GetFileSize,
+ memresourcestream_GetLastWriteTime,
+};
+
+static HRESULT WINAPI memresourceloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **out)
+{
+ struct gdiinterop *This = impl_from_IDWriteFontFileLoader(iface);
+
+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
+
+ if (IsEqualIID(&IID_IDWriteFontFileLoader, riid) || IsEqualIID(&IID_IUnknown, riid)) {
+ *out = iface;
+ IDWriteFontFileLoader_AddRef(iface);
+ return S_OK;
+ }
+
+ *out = NULL;
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI memresourceloader_AddRef(IDWriteFontFileLoader *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI memresourceloader_Release(IDWriteFontFileLoader *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI memresourceloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, void const *key,
+ UINT32 key_size, IDWriteFontFileStream **ret)
+{
+ struct gdiinterop *This = impl_from_IDWriteFontFileLoader(iface);
+ struct memresource_stream *stream;
+
+ TRACE("(%p)->(%p %u %p)\n", This, key, key_size, ret);
+
+ *ret = NULL;
+
+ if (!key || key_size != sizeof(DWORD))
+ return E_INVALIDARG;
+
+ if (!(stream = heap_alloc(sizeof(*stream))))
+ return E_OUTOFMEMORY;
+
+ stream->IDWriteFontFileStream_iface.lpVtbl = &memresourcestreamvtbl;
+ stream->ref = 1;
+ memcpy(&stream->key, key, sizeof(stream->key));
+
+ *ret = &stream->IDWriteFontFileStream_iface;
+
+ return S_OK;
+}
+
+static const struct IDWriteFontFileLoaderVtbl memresourceloadervtbl = {
+ memresourceloader_QueryInterface,
+ memresourceloader_AddRef,
+ memresourceloader_Release,
+ memresourceloader_CreateStreamFromKey,
+};
+
HRESULT create_gdiinterop(IDWriteFactory5 *factory, IDWriteGdiInterop1 **ret)
{
struct gdiinterop *interop;
@@ -907,8 +1099,10 @@ HRESULT create_gdiinterop(IDWriteFactory5 *factory, IDWriteGdiInterop1 **ret)
return E_OUTOFMEMORY;
interop->IDWriteGdiInterop1_iface.lpVtbl = &gdiinteropvtbl;
+ interop->IDWriteFontFileLoader_iface.lpVtbl = &memresourceloadervtbl;
interop->ref = 1;
IDWriteFactory5_AddRef(interop->factory = factory);
+ IDWriteFactory5_RegisterFontFileLoader(factory, &interop->IDWriteFontFileLoader_iface);
*ret = &interop->IDWriteGdiInterop1_iface;
return S_OK;
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 2ac81573de..86efb8cc05 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -1,7 +1,7 @@
/*
* Font related tests
*
- * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
+ * Copyright 2012, 2014-2018 Nikolay Sivov for CodeWeavers
* Copyright 2014 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
@@ -122,6 +122,8 @@ static void _expect_ref_broken(IUnknown* obj, ULONG ref, ULONG brokenref, int li
ok_(__FILE__,line)(rc == ref || broken(rc == brokenref), "expected refcount %d, got %d\n", ref, rc);
}
+static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, void *);
+
static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0};
static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
static const WCHAR arialW[] = {'A','r','i','a','l',0};
@@ -3735,10 +3737,22 @@ static void *map_font_file(const WCHAR *filename, DWORD *file_size)
return ptr;
}
+struct font_realization_info
+{
+ DWORD size;
+ DWORD flags;
+ DWORD cache_num;
+ DWORD instance_id;
+ DWORD unk;
+ WORD face_index;
+ WORD simulations;
+};
+
static void test_CreateFontFaceFromHdc(void)
{
IDWriteFontFileStream *stream, *stream2;
void *font_data, *fragment_context;
+ struct font_realization_info info;
const void *refkey, *fragment;
IDWriteFontFileLoader *loader;
DWORD data_size, num_fonts;
@@ -3748,10 +3762,10 @@ static void test_CreateFontFaceFromHdc(void)
UINT64 size, writetime;
IDWriteFontFile *file;
HFONT hfont, oldhfont;
+ UINT32 count, dummy;
LOGFONTW logfont;
HANDLE resource;
IUnknown *unk;
- UINT32 count;
LOGFONTA lf;
WCHAR *path;
HRESULT hr;
@@ -3761,6 +3775,8 @@ static void test_CreateFontFaceFromHdc(void)
factory = create_factory();
+ pGetFontRealizationInfo = (void *)GetProcAddress(GetModuleHandleA("gdi32"), "GetFontRealizationInfo");
+
interop = NULL;
hr = IDWriteFactory_GetGdiInterop(factory, &interop);
ok(hr == S_OK, "got 0x%08x\n", hr);
@@ -3789,7 +3805,23 @@ static void test_CreateFontFaceFromHdc(void)
fontface = NULL;
hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
- ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(hr == S_OK, "Failed to create font face, hr %#x.\n", hr);
+
+ count = 1;
+ hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
+ ok(hr == S_OK, "Failed to get font files, hr %#x.\n", hr);
+
+ hr = IDWriteFontFile_GetLoader(file, &loader);
+ ok(hr == S_OK, "Failed to get file loader, hr %#x.\n", hr);
+
+ hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
+ ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Vista */, "Expected local loader, hr %#x.\n", hr);
+ if (unk)
+ IUnknown_Release(unk);
+
+ IDWriteFontFileLoader_Release(loader);
+ IDWriteFontFile_Release(file);
+
IDWriteFontFace_Release(fontface);
DeleteObject(SelectObject(hdc, oldhfont));
@@ -3828,11 +3860,8 @@ static void test_CreateFontFaceFromHdc(void)
oldhfont = SelectObject(hdc, hfont);
hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
-todo_wine
ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
-if (fontface)
-{
count = 1;
hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
ok(hr == S_OK, "Failed to get font files, hr %#x.\n", hr);
@@ -3854,6 +3883,17 @@ if (fontface)
ok(hr == S_OK, "Failed to get ref key, hr %#x.\n", hr);
ok(count > 0, "Unexpected key length %u.\n", count);
+ if (pGetFontRealizationInfo)
+ {
+ info.size = sizeof(info);
+ ret = pGetFontRealizationInfo(hdc, &info);
+ ok(ret, "Failed to get realization info.\n");
+ ok(count == sizeof(info.instance_id), "Unexpected key size.\n");
+ ok(*(DWORD *)refkey == info.instance_id, "Unexpected stream key.\n");
+ }
+ else
+ win_skip("GetFontRealizationInfo() is not available.\n");
+
hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream);
ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
@@ -3862,6 +3902,17 @@ if (fontface)
ok(stream2 != stream, "Unexpected stream instance.\n");
IDWriteFontFileStream_Release(stream2);
+ dummy = 1;
+ hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, &dummy, count, &stream2);
+ ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
+
+ writetime = 1;
+ hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
+ ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
+ ok(writetime == 1, "Unexpected write time.\n");
+
+ IDWriteFontFileStream_Release(stream2);
+
hr = IDWriteFontFileStream_GetFileSize(stream, &size);
ok(hr == S_OK, "Failed to get stream size, hr %#x.\n", hr);
ok(size == data_size, "Unexpected stream size.\n");
@@ -3876,13 +3927,19 @@ if (fontface)
ok(fragment == fragment_context, "Unexpected data pointer %p, context %p.\n", fragment, fragment_context);
IDWriteFontFileStream_ReleaseFileFragment(stream, fragment_context);
+ hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size + 1, &fragment_context);
+ ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+
+ hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, size - 1, size / 2, &fragment_context);
+ ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+
IDWriteFontFileStream_Release(stream);
IDWriteFontFileLoader_Release(loader);
IDWriteFontFile_Release(file);
IDWriteFontFace_Release(fontface);
-}
+
ret = RemoveFontMemResourceEx(resource);
ok(ret, "Failed to remove memory resource font, %d.\n", GetLastError());
--
2.19.1
More information about the wine-devel
mailing list