dwrite: Add support for memory font resources in CreateFontFaceFromHdc().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5d31184dff
commit
a0c8f066d4
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
Loading…
Reference in New Issue