Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/gdi32/tests/font.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 4f10e2f38d..dfb2f8e224 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -20,6 +20,7 @@ */
#include <stdarg.h> +#include <stdio.h> #include <assert.h>
#include "windef.h" @@ -6859,8 +6860,25 @@ static void test_long_names(void)
START_TEST(font) { + static const char *test_names[] = + { + "AddFontMemResource", + }; + char path_name[MAX_PATH]; + STARTUPINFOA startup; + char **argv; + int argc, i; + init();
+ argc = winetest_get_mainargs(&argv); + if (argc >= 3) + { + if (!strcmp(argv[2], "AddFontMemResource")) + test_AddFontMemResource(); + return; + } + test_stock_fonts(); test_logfont(); test_bitmap_font(); @@ -6879,7 +6897,6 @@ START_TEST(font) test_nonexistent_font(); test_orientation(); test_height_selection(); - test_AddFontMemResource(); test_EnumFonts(); test_EnumFonts_subst();
@@ -6928,4 +6945,19 @@ START_TEST(font) */ test_vertical_font(); test_CreateScalableFontResource(); + + winetest_get_mainargs( &argv ); + for (i = 0; i < ARRAY_SIZE(test_names); ++i) + { + PROCESS_INFORMATION info; + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + sprintf(path_name, "%s font %s", argv[0], test_names[i]); + ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), + "CreateProcess failed.\n"); + winetest_wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + } }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/gdiinterop.c | 4 +- dlls/gdi32/freetype.c | 6 +- dlls/gdi32/tests/font.c | 219 ++++++++++++++++++++++++++++++++------- 3 files changed, 189 insertions(+), 40 deletions(-)
diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c index ad95e94959..5501f377c4 100644 --- a/dlls/dwrite/gdiinterop.c +++ b/dlls/dwrite/gdiinterop.c @@ -727,7 +727,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, DWORD size, DWORD *needed); +extern BOOL WINAPI GetFontFileInfo(DWORD instance_id, DWORD unknown, struct font_fileinfo *info, SIZE_T size, SIZE_T *needed);
static HRESULT WINAPI gdiinterop_CreateFontFaceFromHdc(IDWriteGdiInterop1 *iface, HDC hdc, IDWriteFontFace **fontface) @@ -740,7 +740,7 @@ static HRESULT WINAPI gdiinterop_CreateFontFaceFromHdc(IDWriteGdiInterop1 *iface IDWriteFontFile *file; BOOL is_supported; UINT32 facenum; - DWORD needed; + SIZE_T needed; HRESULT hr;
TRACE("(%p)->(%p %p)\n", This, hdc, fontface); diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 3fc41c3241..1f46fc809f 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -8576,9 +8576,10 @@ static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr ) /************************************************************************* * GetFontFileInfo (GDI32.@) */ -BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed ) +BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, SIZE_T size, SIZE_T *needed ) { struct font_handle_entry *entry = handle_entry( instance_id ); + SIZE_T required_size; const GdiFont *font;
if (!entry) @@ -8587,6 +8588,9 @@ BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_filei return FALSE; }
+ if (!needed) + needed = &required_size; + font = entry->obj; *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR); if (*needed > size) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index dfb2f8e224..f492f7bfde 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -60,7 +60,7 @@ static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE); static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID); static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID); static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *); -static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *); +static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, SIZE_T, SIZE_T *); static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
static HMODULE hgdi32 = 0; @@ -4255,18 +4255,26 @@ todo_wine DeleteDC(hdc); }
-static void test_RealizationInfo(void) +struct font_realization_info { - struct font_realization_info { - DWORD size; - DWORD flags; - DWORD cache_num; - DWORD instance_id; - DWORD unk; - WORD face_index; - WORD simulations; - }; + DWORD size; + DWORD flags; + DWORD cache_num; + DWORD instance_id; + DWORD unk; + WORD face_index; + WORD simulations; +}; + +struct file_info +{ + FILETIME time; + LARGE_INTEGER size; + WCHAR path[MAX_PATH]; +};
+static void test_RealizationInfo(void) +{ struct realization_info_t { DWORD flags; @@ -4274,22 +4282,17 @@ static void test_RealizationInfo(void) DWORD instance_id; };
+ struct file_info file_info; HDC hdc; - DWORD info[4], info2[10]; - BOOL r, have_file = FALSE; + DWORD info[4], info2[32], read; HFONT hfont, hfont_old; + SIZE_T needed; LOGFONTA lf; - DWORD needed, read; HANDLE h; BYTE file[16], data[14]; - struct file_info - { - FILETIME time; - LARGE_INTEGER size; - WCHAR path[MAX_PATH]; - } file_info; FILETIME time; LARGE_INTEGER size; + BOOL r;
if(!pGdiRealizationInfo) { @@ -4375,11 +4378,11 @@ static void test_RealizationInfo(void)
needed = 0; r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed); - ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError()); + ok(r != 0, "Failed to get font file info, error %d.\n", GetLastError());
if (r) { - ok(needed > 0 && needed < sizeof(file_info), "got needed size %u\n", needed); + ok(needed > 0 && needed < sizeof(file_info), "Unexpected required size.\n");
h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError()); @@ -4392,7 +4395,6 @@ static void test_RealizationInfo(void) /* Read first 16 bytes from the file */ ReadFile(h, file, sizeof(file), &read, NULL); CloseHandle(h); - have_file = TRUE;
/* shorter buffer */ SetLastError(0xdeadbeef); @@ -4405,10 +4407,7 @@ static void test_RealizationInfo(void) r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data)); ok(r != 0, "ret 0 gle %d\n", GetLastError());
- if (have_file) - ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n"); - else - win_skip("GetFontFileInfo() failed, skipping\n"); + ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n"); } }
@@ -5050,9 +5049,14 @@ static void *load_font(const char *font_name, DWORD *font_size) HANDLE file, mapping; void *font;
- if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL; - strcat(file_name, "\fonts\"); - strcat(file_name, font_name); + if (font_name[1] == ':') + strcpy(file_name, font_name); + else + { + if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL; + strcat(file_name, "\fonts\"); + strcat(file_name, font_name); + }
file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); if (file == INVALID_HANDLE_VALUE) return NULL; @@ -5073,8 +5077,120 @@ static void *load_font(const char *font_name, DWORD *font_size) return font; }
+static void test_realization_info(const char *name, DWORD size, BOOL is_memory_resource) +{ + struct font_realization_info info; + struct file_info file_info; + HFONT hfont, hfont_prev; + SIZE_T needed; + LOGFONTA lf; + BYTE *data; + BOOL ret; + HDC hdc; + + if (!pGetFontRealizationInfo) + return; + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = 72; + strcpy(lf.lfFaceName, name); + + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "Failed to create a font, %u.\n", GetLastError()); + + hdc = GetDC(NULL); + + hfont_prev = SelectObject(hdc, hfont); + ok(hfont_prev != NULL, "Failed to select font.\n"); + + memset(&info, 0xcc, sizeof(info)); + info.size = sizeof(info); + ret = pGetFontRealizationInfo(hdc, (DWORD *)&info); + ok(ret != 0, "Unexpected return value %d.\n", ret); + + ok((info.flags & 0xf) == 0x3, "Unexpected flags %#x.\n", info.flags); + ok(info.cache_num != 0, "Unexpected cache num %u.\n", info.cache_num); + ok(info.instance_id != 0, "Unexpected instance id %u.\n", info.instance_id); + ok(info.simulations == 0, "Unexpected simulations %#x.\n", info.simulations); + ok(info.face_index == 0, "Unexpected face index %u.\n", info.face_index); + + ret = pGetFontFileInfo(info.instance_id, 0, NULL, 0, NULL); + ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n", + ret, GetLastError()); + + needed = 0; + ret = pGetFontFileInfo(info.instance_id, 0, NULL, 0, &needed); + ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n", + ret, GetLastError()); + + ret = pGetFontFileInfo(info.instance_id, 0, &file_info, 0, NULL); + ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n", + ret, GetLastError()); + + ret = pGetFontFileInfo(info.instance_id, 0, &file_info, needed - 1, NULL); + ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n", + ret, GetLastError()); + + ret = pGetFontFileInfo(info.instance_id, 0, &file_info, needed, NULL); + ok(ret != 0, "Failed to get font file info, ret %d gle %d.\n", ret, GetLastError()); + + memset(&file_info, 0xcc, sizeof(file_info)); + ret = pGetFontFileInfo(info.instance_id, 0, &file_info, sizeof(file_info), NULL); + ok(ret != 0, "Failed to get font file info, ret %d gle %d.\n", ret, GetLastError()); + if (ret) + { + todo_wine_if(is_memory_resource) + ok(is_memory_resource ? file_info.size.QuadPart == size : file_info.size.QuadPart > 0, "Unexpected file size.\n"); + ok(is_memory_resource ? !file_info.path[0] : file_info.path[0], "Unexpected file path %s.\n", + wine_dbgstr_w(file_info.path)); + } + +if (pGetFontFileData) +{ + size = file_info.size.LowPart; + data = HeapAlloc(GetProcessHeap(), 0, size + 16); + + memset(data, 0xcc, size); + ret = pGetFontFileData(info.instance_id, 0, 0, data, size); + ok(ret != 0, "Failed to get font file data, %d\n", GetLastError()); + ok(*(DWORD *)data == 0x00000100, "Unexpected sfnt header version %#x.\n", *(DWORD *)data); + ok(*(WORD *)(data + 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD *)(data + 4)); + + /* Larger than font data size. */ + memset(data, 0xcc, size); + ret = pGetFontFileData(info.instance_id, 0, 0, data, size + 16); + ok(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected return value %d, error %d\n", + ret, GetLastError()); + ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data); + + /* With offset. */ + memset(data, 0xcc, size); + ret = pGetFontFileData(info.instance_id, 0, 16, data, size - 16); + ok(ret != 0, "Failed to get font file data, %d\n", GetLastError()); + ok(*(DWORD *)data == 0x1000000, "Unexpected buffer contents %#x.\n", *(DWORD *)data); + + memset(data, 0xcc, size); + ret = pGetFontFileData(info.instance_id, 0, 16, data, size); + ok(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected return value %d, error %d\n", + ret, GetLastError()); + ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data); + + /* Zero buffer size. */ + memset(data, 0xcc, size); + ret = pGetFontFileData(info.instance_id, 0, 16, data, 0); + ok(ret == 0 && GetLastError() == ERROR_NOACCESS, "Unexpected return value %d, error %d\n", ret, GetLastError()); + ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data); + + HeapFree(GetProcessHeap(), 0, data); +} + SelectObject(hdc, hfont_prev); + DeleteObject(hfont); + ReleaseDC(NULL, hdc); +} + static void test_AddFontMemResource(void) { + char ttf_name[MAX_PATH]; void *font; DWORD font_size, num_fonts; HANDLE ret; @@ -5086,13 +5202,6 @@ static void test_AddFontMemResource(void) return; }
- font = load_font("sserife.fon", &font_size); - if (!font) - { - skip("Unable to locate and load font sserife.fon\n"); - return; - } - SetLastError(0xdeadbeef); ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL); ok(!ret, "AddFontMemResourceEx should fail\n"); @@ -5121,6 +5230,42 @@ static void test_AddFontMemResource(void) "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
+ /* Now with scalable font */ + bRet = write_ttf_file("wine_test.ttf", ttf_name); + ok(bRet, "Failed to create test font file.\n"); + + font = load_font(ttf_name, &font_size); + ok(font != NULL, "Failed to map font file.\n"); + + bRet = is_truetype_font_installed("wine_test"); + ok(!bRet, "Font wine_test should not be enumerated.\n"); + + num_fonts = 0; + ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts); + ok(ret != 0, "Failed to add resource, %d.\n", GetLastError()); + ok(num_fonts == 1, "Unexpected number of fonts %u.\n", num_fonts); + + bRet = is_truetype_font_installed("wine_test"); +todo_wine + ok(!bRet, "Font wine_test should not be enumerated.\n"); + + test_realization_info("wine_test", font_size, TRUE); + + bRet = pRemoveFontMemResourceEx(ret); + ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError()); + + free_font(font); + + bRet = DeleteFileA(ttf_name); + ok(bRet, "Failed to delete font file, %d.\n", GetLastError()); + + font = load_font("sserife.fon", &font_size); + if (!font) + { + skip("Unable to locate and load font sserife.fon\n"); + return; + } + SetLastError(0xdeadbeef); ret = pAddFontMemResourceEx(font, 0, NULL, NULL); ok(!ret, "AddFontMemResourceEx should fail\n");
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/gdi32/freetype.c | 1 + dlls/gdi32/tests/font.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 1f46fc809f..96e8e30deb 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -5335,6 +5335,7 @@ static void fill_fileinfo_from_face( GdiFont *font, Face *face ) if (!face->file) { font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo)); + font->fileinfo->size.QuadPart = face->font_data_size; return; }
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index f492f7bfde..468e7d9db1 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -5139,7 +5139,6 @@ static void test_realization_info(const char *name, DWORD size, BOOL is_memory_r ok(ret != 0, "Failed to get font file info, ret %d gle %d.\n", ret, GetLastError()); if (ret) { - todo_wine_if(is_memory_resource) ok(is_memory_resource ? file_info.size.QuadPart == size : file_info.size.QuadPart > 0, "Unexpected file size.\n"); ok(is_memory_resource ? !file_info.path[0] : file_info.path[0], "Unexpected file path %s.\n", wine_dbgstr_w(file_info.path));
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/gdi32/freetype.c | 27 +++++++++++++++++++++++++++ dlls/gdi32/gdi32.spec | 1 + dlls/gdi32/tests/font.c | 9 +++------ 3 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 96e8e30deb..56425a9feb 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -8574,6 +8574,33 @@ static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr ) return TRUE; }
+BOOL WINAPI GetFontFileData( DWORD instance_id, DWORD unknown, UINT64 offset, void *buff, DWORD buff_size ) +{ + struct font_handle_entry *entry = handle_entry( instance_id ); + DWORD tag = 0, size; + GdiFont *font; + + if (!entry) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + font = entry->obj; + if (font->ttc_item_offset) + tag = MS_TTCF_TAG; + + size = get_font_data( font, tag, 0, NULL, 0 ); + if (size < buff_size || offset > size - buff_size) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* For now this only works for SFNT case. */ + return get_font_data( font, tag, offset, buff, buff_size ) != 0; +} + /************************************************************************* * GetFontFileInfo (GDI32.@) */ diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index 2400a51038..2dc8f0e887 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -281,6 +281,7 @@ @ stdcall GetEnhMetaFileW(wstr) # @ stub GetFontAssocStatus @ stdcall GetFontData(long long long ptr long) +@ stdcall GetFontFileData(long long int64 ptr long) @ stdcall GetFontFileInfo(long long ptr long ptr) @ stdcall GetFontLanguageInfo(long) @ stdcall GetFontRealizationInfo(long ptr) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 468e7d9db1..75696946b2 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -61,7 +61,7 @@ static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID); static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID); static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *); static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, SIZE_T, SIZE_T *); -static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD); +static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, UINT64, void *, DWORD);
static HMODULE hgdi32 = 0; static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; @@ -4402,14 +4402,12 @@ static void test_RealizationInfo(void) ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError()); }
- if (pGetFontFileData) { /* Get bytes 2 - 16 using GetFontFileData */ r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data)); ok(r != 0, "ret 0 gle %d\n", GetLastError());
ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n"); } - }
DeleteObject(SelectObject(hdc, hfont_old));
@@ -5144,8 +5142,6 @@ static void test_realization_info(const char *name, DWORD size, BOOL is_memory_r wine_dbgstr_w(file_info.path)); }
-if (pGetFontFileData) -{ size = file_info.size.LowPart; data = HeapAlloc(GetProcessHeap(), 0, size + 16);
@@ -5177,11 +5173,12 @@ if (pGetFontFileData) /* Zero buffer size. */ memset(data, 0xcc, size); ret = pGetFontFileData(info.instance_id, 0, 16, data, 0); +todo_wine ok(ret == 0 && GetLastError() == ERROR_NOACCESS, "Unexpected return value %d, error %d\n", ret, GetLastError()); ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data);
HeapFree(GetProcessHeap(), 0, data); -} + SelectObject(hdc, hfont_prev); DeleteObject(hfont); ReleaseDC(NULL, hdc);
Signed-off-by: Huw Davies huw@codeweavers.com