[GDI32_APITEST]: Fix the "missing braces around initializer" GCC error that I've...
[reactos.git] / rostests / apitests / gdi32 / AddFontMemResourceEx.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for AddFontMemResourceEx
5 * PROGRAMMERS: Mark Jansen
6 *
7 * PanosePitchTest + TTCTestV by Katayama Hirofumi MZ, licensed under CC BY
8 * Shadows_Into_Light by Kimberly Geswein, licensed under OFL
9 * Captured from firefox, embedded on reactos.org
10 */
11
12
13 #include <apitest.h>
14 #include <wingdi.h>
15 #include <winuser.h>
16
17 typedef struct _fnt_res
18 {
19 const char* FontName;
20 TEXTMETRICA tm;
21 } fnt_res;
22
23 typedef struct _fnt_test
24 {
25 const char* ResourceName;
26 int NumFaces;
27 fnt_res res[4];
28 } fnt_test;
29
30
31
32 static fnt_test test_data[] =
33 {
34 {
35 /* .ResourceName = */ "PanosePitchTest.ttf",
36 /* .NumFaces = */ 2,
37 /* .res = */
38 {
39 {
40 /* .FontName = */ "PanosePitchTest",
41 {
42 /* .tm.tmHeight = */ 11,
43 /* .tm.tmAscent = */ 11,
44 /* .tm.tmDescent = */ 0,
45 /* .tm.tmInternalLeading = */ -5,
46 /* .tm.tmExternalLeading = */ 1,
47 /* .tm.tmAveCharWidth = */ 8,
48 /* .tm.tmMaxCharWidth = */ 11,
49 /* .tm.tmWeight = */ FW_NORMAL,
50 /* .tm.tmOverhang = */ 0,
51 /* .tm.tmDigitizedAspectX = */ 96,
52 /* .tm.tmDigitizedAspectY = */ 96,
53 /* .tm.tmFirstChar = */ 63,
54 /* .tm.tmLastChar = */ 65,
55 /* .tm.tmDefaultChar = */ 165,
56 /* .tm.tmBreakChar = */ 65,
57 /* .tm.tmItalic = */ 0,
58 /* .tm.tmUnderlined = */ 0,
59 /* .tm.tmStruckOut = */ 0,
60 /* .tm.tmPitchAndFamily = */ TMPF_TRUETYPE | TMPF_VECTOR,
61 /* .tm.tmCharSet = */ SHIFTJIS_CHARSET,
62 }
63 },
64 {
65 /* .FontName = */ "@PanosePitchTest",
66 {
67 /* .tm.tmHeight = */ 11,
68 /* .tm.tmAscent = */ 11,
69 /* .tm.tmDescent = */ 0,
70 /* .tm.tmInternalLeading = */ -5,
71 /* .tm.tmExternalLeading = */ 1,
72 /* .tm.tmAveCharWidth = */ 8,
73 /* .tm.tmMaxCharWidth = */ 11,
74 /* .tm.tmWeight = */ FW_NORMAL,
75 /* .tm.tmOverhang = */ 0,
76 /* .tm.tmDigitizedAspectX = */ 96,
77 /* .tm.tmDigitizedAspectY = */ 96,
78 /* .tm.tmFirstChar = */ 63,
79 /* .tm.tmLastChar = */ 65,
80 /* .tm.tmDefaultChar = */ 165,
81 /* .tm.tmBreakChar = */ 65,
82 /* .tm.tmItalic = */ 0,
83 /* .tm.tmUnderlined = */ 0,
84 /* .tm.tmStruckOut = */ 0,
85 /* .tm.tmPitchAndFamily = */ TMPF_TRUETYPE | TMPF_VECTOR,
86 /* .tm.tmCharSet = */ SHIFTJIS_CHARSET,
87 }
88 },
89 },
90 },
91 {
92 /* .ResourceName = */ "TTCTestV.ttc",
93 /* .NumFaces = */ 3,
94 /* .res = */
95 {
96 {
97 /* .FontName = */ "No1Of3in1",
98 {
99 /* .tm.tmHeight = */ 12,
100 /* .tm.tmAscent = */ 12,
101 /* .tm.tmDescent = */ 0,
102 /* .tm.tmInternalLeading = */ -4,
103 /* .tm.tmExternalLeading = */ 1,
104 /* .tm.tmAveCharWidth = */ -525,
105 /* .tm.tmMaxCharWidth = */ 6,
106 /* .tm.tmWeight = */ FW_NORMAL,
107 /* .tm.tmOverhang = */ 0,
108 /* .tm.tmDigitizedAspectX = */ 96,
109 /* .tm.tmDigitizedAspectY = */ 96,
110 /* .tm.tmFirstChar = */ 63,
111 /* .tm.tmLastChar = */ 65,
112 /* .tm.tmDefaultChar = */ 64,
113 /* .tm.tmBreakChar = */ 65,
114 /* .tm.tmItalic = */ 0,
115 /* .tm.tmUnderlined = */ 0,
116 /* .tm.tmStruckOut = */ 0,
117 /* .tm.tmPitchAndFamily = */ TMPF_TRUETYPE | TMPF_VECTOR | TMPF_FIXED_PITCH,
118 /* .tm.tmCharSet = */ ANSI_CHARSET,
119 }
120 },
121 {
122 /* .FontName = */ "No2Of3in1",
123 {
124 /* .tm.tmHeight = */ 12,
125 /* .tm.tmAscent = */ 12,
126 /* .tm.tmDescent = */ 0,
127 /* .tm.tmInternalLeading = */ -4,
128 /* .tm.tmExternalLeading = */ 1,
129 /* .tm.tmAveCharWidth = */ 8,
130 /* .tm.tmMaxCharWidth = */ 7,
131 /* .tm.tmWeight = */ FW_NORMAL,
132 /* .tm.tmOverhang = */ 0,
133 /* .tm.tmDigitizedAspectX = */ 96,
134 /* .tm.tmDigitizedAspectY = */ 96,
135 /* .tm.tmFirstChar = */ 63,
136 /* .tm.tmLastChar = */ 65,
137 /* .tm.tmDefaultChar = */ 64,
138 /* .tm.tmBreakChar = */ 65,
139 /* .tm.tmItalic = */ 0,
140 /* .tm.tmUnderlined = */ 0,
141 /* .tm.tmStruckOut = */ 0,
142 /* .tm.tmPitchAndFamily = */ TMPF_TRUETYPE | TMPF_VECTOR | TMPF_FIXED_PITCH,
143 /* .tm.tmCharSet = */ ANSI_CHARSET,
144 }
145 },
146 {
147 /* .FontName = */ "No3Of3in1V",
148 {
149 /* .tm.tmHeight = */ 12,
150 /* .tm.tmAscent = */ 12,
151 /* .tm.tmDescent = */ 0,
152 /* .tm.tmInternalLeading = */ -4,
153 /* .tm.tmExternalLeading = */ 1,
154 /* .tm.tmAveCharWidth = */ 8,
155 /* .tm.tmMaxCharWidth = */ 13,
156 /* .tm.tmWeight = */ FW_NORMAL,
157 /* .tm.tmOverhang = */ 0,
158 /* .tm.tmDigitizedAspectX = */ 96,
159 /* .tm.tmDigitizedAspectY = */ 96,
160 /* .tm.tmFirstChar = */ 63,
161 /* .tm.tmLastChar = */ 65,
162 /* .tm.tmDefaultChar = */ 64,
163 /* .tm.tmBreakChar = */ 65,
164 /* .tm.tmItalic = */ 0,
165 /* .tm.tmUnderlined = */ 0,
166 /* .tm.tmStruckOut = */ 0,
167 /* .tm.tmPitchAndFamily = */ FF_MODERN | TMPF_TRUETYPE | TMPF_VECTOR,
168 /* .tm.tmCharSet = */ ANSI_CHARSET,
169 }
170 },
171 },
172 },
173 {
174 /* .ResourceName = */ "Shadows_Into_Light.ttf",
175 /* .NumFaces = */ 1,
176 /* .res = */
177 {
178 {
179 /* .FontName = */ "ufaXaAlLOxCUGYJ7KN51UP2Q==",
180 {
181 /* .tm.tmHeight = */ 26,
182 /* .tm.tmAscent = */ 19,
183 /* .tm.tmDescent = */ 7,
184 /* .tm.tmInternalLeading = */ 10,
185 /* .tm.tmExternalLeading = */ 0,
186 /* .tm.tmAveCharWidth = */ 7,
187 /* .tm.tmMaxCharWidth = */ 23,
188 /* .tm.tmWeight = */ FW_NORMAL,
189 /* .tm.tmOverhang = */ 0,
190 /* .tm.tmDigitizedAspectX = */ 96,
191 /* .tm.tmDigitizedAspectY = */ 96,
192 /* .tm.tmFirstChar = */ 30,
193 /* .tm.tmLastChar = */ 255,
194 /* .tm.tmDefaultChar = */ 31,
195 /* .tm.tmBreakChar = */ 32,
196 /* .tm.tmItalic = */ 0,
197 /* .tm.tmUnderlined = */ 0,
198 /* .tm.tmStruckOut = */ 0,
199 /* .tm.tmPitchAndFamily = */ TMPF_TRUETYPE | TMPF_VECTOR | TMPF_FIXED_PITCH,
200 /* .tm.tmCharSet = */ ANSI_CHARSET,
201 }
202 },
203 },
204 },
205 };
206
207
208 #define ok_int2(expression) \
209 do { \
210 int _value = (expression); \
211 ok(_value == (res->expression), "Wrong value for '%s', expected: %d, got: %d for %s/%s\n", \
212 #expression, (int)(res->expression), _value, test_name, res->FontName); \
213 } while (0)
214
215 #define ok_hex2(expression) \
216 do { \
217 int _value = (expression); \
218 ok(_value == (res->expression), "Wrong value for '%s', expected: 0x%x, got: 0x%x for %s/%s\n", \
219 #expression, (int)(res->expression), _value, test_name, res->FontName); \
220 } while (0)
221
222
223 static void test_font_caps(HDC hdc, int test_index)
224 {
225 HGDIOBJ old;
226 TEXTMETRICA tm = { 0 };
227 char name[64];
228 BOOL ret;
229 HFONT font;
230 int n;
231 const char* test_name = test_data[test_index].ResourceName;
232
233 for (n = 0; test_data[test_index].res[n].FontName; ++n)
234 {
235 fnt_res* res = test_data[test_index].res + n;
236 font = CreateFontA(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
237 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, res->FontName);
238
239 if (font)
240 {
241 old = SelectObject(hdc, font);
242
243 memset(&tm, 0xaa, sizeof(tm));
244 ret = GetTextMetricsA(hdc, &tm);
245 ok(ret, "GetTextMetricsA() for %s/%s\n", test_name, res->FontName);
246
247 SetLastError(0xdeadbeef);
248 ret = GetTextFaceA(hdc, sizeof(name), name);
249 ok(ret, "GetTextFaceA error %lu for %s/%s\n", GetLastError(), test_name, res->FontName);
250 if (ret)
251 {
252 ok(!strcmp(name, res->FontName), "FontName was %s, expected %s for %s/%s", name, res->FontName, test_name, res->FontName);
253 }
254
255 ok_int2(tm.tmHeight);
256 ok_int2(tm.tmAscent);
257 ok_int2(tm.tmDescent);
258 ok_int2(tm.tmInternalLeading);
259 ok_int2(tm.tmExternalLeading);
260 ok_int2(tm.tmAveCharWidth);
261 ok_int2(tm.tmMaxCharWidth);
262 ok_int2(tm.tmWeight);
263 ok_int2(tm.tmOverhang);
264 ok_int2(tm.tmDigitizedAspectX);
265 ok_int2(tm.tmDigitizedAspectY);
266 ok_int2(tm.tmFirstChar);
267 ok_int2(tm.tmLastChar);
268 ok_int2(tm.tmDefaultChar);
269 ok_int2(tm.tmBreakChar);
270 ok_int2(tm.tmItalic);
271 ok_int2(tm.tmUnderlined);
272 ok_int2(tm.tmStruckOut);
273 ok_hex2(tm.tmPitchAndFamily);
274 ok_int2(tm.tmCharSet);
275
276 SelectObject(hdc, old);
277 DeleteObject(font);
278 }
279 }
280 }
281
282
283 /* Not working as of 2017-04-08 on ReactOS */
284 static BOOL is_font_available(HDC hdc, const char* fontName)
285 {
286 char name[64];
287 BOOL ret;
288
289 HFONT font = CreateFontA(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
290 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, fontName);
291 HGDIOBJ old = SelectObject(hdc, font);
292
293
294 SetLastError(0xdeadbeef);
295
296 ret = GetTextFaceA(hdc, sizeof(name), name);
297 ok(ret, "GetTextFaceA error %lu for %s\n", GetLastError(), fontName);
298 SelectObject(hdc, old);
299 DeleteObject(font);
300
301 if (ret)
302 {
303 return !_strcmpi(name, fontName);
304 }
305 return FALSE;
306 }
307
308
309
310 START_TEST(AddFontMemResourceEx)
311 {
312 HMODULE mod;
313 HRSRC hRsrc;
314
315 HGLOBAL hTemplate;
316 DWORD dwSize, dwNumFonts;
317 LPVOID pFont;
318
319 HANDLE hFont;
320 fnt_test* data;
321 int n;
322
323 HDC hdc = CreateCompatibleDC(NULL);
324 BOOL is_font_available_broken = is_font_available(hdc, "Nonexisting font name here");
325
326 ok(!is_font_available_broken, "Validating font is broken! (CORE-13053)!\n");
327
328 for (n = 0; n < _countof(test_data); ++n)
329 {
330 data = test_data + n;
331
332 mod = GetModuleHandle(NULL);
333 hRsrc = FindResourceA(mod, data->ResourceName, MAKEINTRESOURCE(RT_RCDATA));
334
335 hTemplate = LoadResource(mod, hRsrc);
336 dwSize = SizeofResource(mod, hRsrc);
337 pFont = LockResource(hTemplate);
338
339 dwNumFonts = 0;
340 hFont = AddFontMemResourceEx(pFont, dwSize, NULL, &dwNumFonts);
341 ok(dwNumFonts == data->NumFaces, "dwNumFonts was %lu, expected %d for %s\n", dwNumFonts, data->NumFaces, data->ResourceName);
342 ok(hFont != NULL, "Expected valid handle for %s\n", data->ResourceName);
343
344 if (hFont)
345 {
346 test_font_caps(hdc, n);
347 RemoveFontMemResourceEx(hFont);
348 if (!is_font_available_broken)
349 {
350 ok (!is_font_available(hdc, data->ResourceName), "Expected font to be unregistered again for %s\n", data->ResourceName);
351 }
352 else
353 {
354 skip("Font unregister test for %s\n", data->ResourceName);
355 }
356 }
357
358 UnlockResource(hTemplate);
359 FreeResource(hTemplate);
360 }
361
362 DeleteDC(hdc);
363 }
364