Commit a0c8f066 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

dwrite: Add support for memory font resources in CreateFontFaceFromHdc().

parent 5d31184d
......@@ -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;
......
/*
* 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());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment