Added stubs for SendIMEMessageEx[A,W].
[wine] / dlls / gdi / tests / metafile.c
1 /*
2  * Unit tests for metafile functions
3  *
4  * Copyright (c) 2002 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
29
30 static LOGFONTA orig_lf;
31 static BOOL emr_processed = FALSE;
32
33 static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
34     const ENHMETARECORD *emr, int n_objs, LPARAM param)
35 {
36     static int n_record;
37     DWORD i;
38     const INT *dx;
39     INT *orig_dx = (INT *)param;
40     LOGFONTA device_lf;
41     INT ret;
42
43     trace("hdc %p, emr->iType %ld, emr->nSize %ld, param %p\n",
44            hdc, emr->iType, emr->nSize, (void *)param);
45
46     PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
47
48     switch (emr->iType)
49     {
50     case EMR_HEADER:
51         n_record = 0;
52         break;
53
54     case EMR_EXTTEXTOUTA:
55     {
56         const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
57         dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
58
59         ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
60         ok( ret == sizeof(device_lf), "GetObjectA error %ld\n", GetLastError());
61
62         /* compare up to lfOutPrecision, other values are not interesting,
63          * and in fact sometimes arbitrary adapted by Win9x.
64          */
65         ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
66         ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
67
68         for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
69         {
70             ok(orig_dx[i] == dx[i], "pass %d: dx[%ld] (%d) didn't match %d\n",
71                                      n_record, i, dx[i], orig_dx[i]);
72         }
73         n_record++;
74         emr_processed = TRUE;
75         break;
76     }
77
78     case EMR_EXTTEXTOUTW:
79     {
80         const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
81         dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
82
83         ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
84         ok( ret == sizeof(device_lf), "GetObjectA error %ld\n", GetLastError());
85
86         /* compare up to lfOutPrecision, other values are not interesting,
87          * and in fact sometimes arbitrary adapted by Win9x.
88          */
89         ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
90         ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
91
92         for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
93         {
94             ok(orig_dx[i] == dx[i], "pass %d: dx[%ld] (%d) didn't match %d\n",
95                                      n_record, i, dx[i], orig_dx[i]);
96         }
97         n_record++;
98         emr_processed = TRUE;
99         break;
100     }
101
102     default:
103         break;
104     }
105
106     return 1;
107 }
108
109 static void test_ExtTextOut(void)
110 {
111     HWND hwnd;
112     HDC hdcDisplay, hdcMetafile;
113     HENHMETAFILE hMetafile;
114     HFONT hFont;
115     static const char text[] = "Simple text to test ExtTextOut on metafiles";
116     INT i, len, dx[256];
117     static const RECT rc = { 0, 0, 100, 100 };
118     BOOL ret;
119
120     assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
121
122     /* Win9x doesn't play EMFs on invisible windows */
123     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
124                            0, 0, 200, 200, 0, 0, 0, NULL);
125     ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
126
127     hdcDisplay = GetDC(hwnd);
128     ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
129
130     trace("hdcDisplay %p\n", hdcDisplay);
131
132     SetMapMode(hdcDisplay, MM_TEXT);
133
134     memset(&orig_lf, 0, sizeof(orig_lf));
135
136     orig_lf.lfCharSet = ANSI_CHARSET;
137     orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
138     orig_lf.lfWeight = FW_DONTCARE;
139     orig_lf.lfHeight = 7;
140     orig_lf.lfQuality = DEFAULT_QUALITY;
141     lstrcpyA(orig_lf.lfFaceName, "Arial");
142     hFont = CreateFontIndirectA(&orig_lf);
143     ok(hFont != 0, "CreateFontIndirectA error %ld\n", GetLastError());
144
145     hFont = SelectObject(hdcDisplay, hFont);
146
147     len = lstrlenA(text);
148     for (i = 0; i < len; i++)
149     {
150         ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
151         ok( ret, "GetCharWidthA error %ld\n", GetLastError());
152     }
153     hFont = SelectObject(hdcDisplay, hFont);
154
155     hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
156     ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
157
158     trace("hdcMetafile %p\n", hdcMetafile);
159
160     ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
161        "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
162
163     hFont = SelectObject(hdcMetafile, hFont);
164
165     /* 1. pass NULL lpDx */
166     ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
167     ok( ret, "ExtTextOutA error %ld\n", GetLastError());
168
169     /* 2. pass custom lpDx */
170     ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
171     ok( ret, "ExtTextOutA error %ld\n", GetLastError());
172
173     hFont = SelectObject(hdcMetafile, hFont);
174     ret = DeleteObject(hFont);
175     ok( ret, "DeleteObject error %ld\n", GetLastError());
176
177     hMetafile = CloseEnhMetaFile(hdcMetafile);
178     ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
179
180     ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
181
182     ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
183     ok( ret, "PlayEnhMetaFile error %ld\n", GetLastError());
184
185     ret = EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, &rc);
186     ok( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
187
188     ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
189
190     ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, NULL),
191        "A valid hdc has to require a valid rc\n");
192
193     ret = DeleteEnhMetaFile(hMetafile);
194     ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
195     ret = ReleaseDC(hwnd, hdcDisplay);
196     ok( ret, "ReleaseDC error %ld\n", GetLastError());
197 }
198
199 /* Win-format metafile (mfdrv) tests */
200 /* These tests compare the generated metafiles byte-by-byte */
201 /* with the nominal results. */
202
203 /* Maximum size of sample metafiles in bytes. */
204 #define MF_BUFSIZE 256
205
206 /* 8x8 bitmap data for a pattern brush */
207 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
208     0x01, 0x00, 0x02, 0x00,
209     0x03, 0x00, 0x04, 0x00,
210     0x05, 0x00, 0x06, 0x00,
211     0x07, 0x00, 0x08, 0x00
212 };
213
214 /* Sample metafiles to be compared to the outputs of the
215  * test functions.
216  */
217
218 static const unsigned char MF_BLANK_BITS[] = {
219     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
220     0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
221     0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
222 };
223
224 static const unsigned char MF_GRAPHICS_BITS[] = {
225     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
226     0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
227     0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
228     0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
229     0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
230     0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
231     0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
232     0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
233     0x00, 0x00, 0x00, 0x00
234 };
235
236 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
237     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
238     0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
239     0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
240     0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
241     0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
242     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
243     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246     0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
247     0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
248     0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
249     0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
250     0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
251     0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
252     0x00, 0x00
253 };
254
255 /* For debugging or dumping the raw metafiles produced by
256  * new test functions.
257  */
258
259 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
260 {
261     char buf[MF_BUFSIZE];
262     UINT mfsize;
263     int i;
264
265     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
266     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
267
268     printf ("MetaFile %s has bits:\n{\n    ", desc);
269     for (i=0; i<mfsize; i++)
270     {
271         printf ("0x%.2hhx", buf[i]);
272         if (i == mfsize-1)
273             printf ("\n");
274         else if (i % 8 == 7)
275             printf (",\n    ");
276         else
277             printf (", ");
278     }
279     printf ("};\n");
280 }
281
282 /* Compare the metafile produced by a test function with the
283  * expected raw metafile data in "bits".
284  * Return value is 0 for a perfect match,
285  * -1 if lengths aren't equal,
286  * otherwise returns the number of non-matching bytes.
287  */
288
289 static int compare_mf_bits (const HMETAFILE mf, const char *bits, int bsize,
290     const char *desc)
291 {
292     char buf[MF_BUFSIZE];
293     UINT mfsize;
294     int i, diff;
295
296     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
297     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
298     if (mfsize < MF_BUFSIZE)
299         ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
300             desc, mfsize, bsize);
301     else
302         ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
303             desc, mfsize, bsize);
304     if (mfsize != bsize)
305         return -1;
306
307     diff = 0;
308     for (i=0; i<bsize; i++)
309     {
310        if (buf[i] !=  bits[i])
311            diff++;
312     }
313     ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
314         desc, mfsize, bsize, diff);
315
316     return diff; 
317 }
318
319 /* Test a blank metafile.  May be used as a template for new tests. */
320
321 static void test_mf_Blank(void)
322 {
323     HDC hdcMetafile;
324     HMETAFILE hMetafile;
325     INT caps;
326     BOOL ret;
327
328     hdcMetafile = CreateMetaFileA(NULL);
329     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
330     trace("hdcMetafile %p\n", hdcMetafile);
331
332 /* Tests on metafile initialization */
333     caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
334     ok (caps == DT_METAFILE,
335         "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
336
337     hMetafile = CloseMetaFile(hdcMetafile);
338     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
339     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
340
341     if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
342         "mf_blank") != 0)
343             dump_mf_bits (hMetafile, "mf_Blank");
344
345     ret = DeleteMetaFile(hMetafile);
346     ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
347 }
348
349 /* Simple APIs from mfdrv/graphics.c
350  */
351
352 static void test_mf_Graphics()
353 {
354     HDC hdcMetafile;
355     HMETAFILE hMetafile;
356     POINT oldpoint;
357     BOOL ret;
358
359     hdcMetafile = CreateMetaFileA(NULL);
360     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
361     trace("hdcMetafile %p\n", hdcMetafile);
362
363     ret = MoveToEx(hdcMetafile, 1, 1, NULL);
364     ok( ret, "MoveToEx error %ld.\n", GetLastError());
365     ret = LineTo(hdcMetafile, 2, 2);
366     ok( ret, "LineTo error %ld.\n", GetLastError());
367     ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
368     ok( ret, "MoveToEx error %ld.\n", GetLastError());
369
370 /* oldpoint gets garbage under Win XP, so the following test would
371  * work under Wine but fails under Windows:
372  *
373  *   ok((oldpoint.x == 2) && (oldpoint.y == 2),
374  *       "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
375  *       oldpoint.x, oldpoint.y);
376  */
377
378     ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
379     ok( ret, "Ellipse error %ld.\n", GetLastError());
380
381     hMetafile = CloseMetaFile(hdcMetafile);
382     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
383     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
384
385     if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
386         "mf_Graphics") != 0)
387             dump_mf_bits (hMetafile, "mf_Graphics");
388
389     ret = DeleteMetaFile(hMetafile);
390     ok( ret, "DeleteMetaFile(%p) error %ld\n",
391         hMetafile, GetLastError());
392 }
393
394 static void test_mf_PatternBrush(void)
395 {
396     HDC hdcMetafile;
397     HMETAFILE hMetafile;
398     LOGBRUSH *orig_lb;
399     HBRUSH hBrush;
400     BOOL ret;
401
402     orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
403
404     orig_lb->lbStyle = BS_PATTERN;
405     orig_lb->lbColor = RGB(0, 0, 0);
406     orig_lb->lbHatch = (INT) CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
407     ok((HBITMAP *)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
408
409     hBrush = CreateBrushIndirect (orig_lb);
410     ok(hBrush != 0, "CreateBrushIndirect error %ld\n", GetLastError());
411
412     hdcMetafile = CreateMetaFileA(NULL);
413     ok(hdcMetafile != 0, "CreateMetaFileA error %ld\n", GetLastError());
414     trace("hdcMetafile %p\n", hdcMetafile);
415
416     hBrush = SelectObject(hdcMetafile, hBrush);
417     ok(hBrush != 0, "SelectObject error %ld.\n", GetLastError());
418
419     hMetafile = CloseMetaFile(hdcMetafile);
420     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
421     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
422
423     if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
424         "mf_Pattern_Brush") != 0)
425             dump_mf_bits (hMetafile, "mf_Pattern_Brush");
426
427     ret = DeleteMetaFile(hMetafile);
428     ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
429     ret = DeleteObject(hBrush);
430     ok( ret, "DeleteObject(HBRUSH) error %ld\n", GetLastError());
431     ret = DeleteObject((HBITMAP *)orig_lb->lbHatch);
432     ok( ret, "DeleteObject(HBITMAP) error %ld\n",
433         GetLastError());
434     HeapFree (GetProcessHeap(), 0, orig_lb);
435 }
436
437 START_TEST(metafile)
438 {
439     /* For enhanced metafiles (enhmfdrv) */
440     test_ExtTextOut();
441
442     /* For win-format metafiles (mfdrv) */
443     test_mf_Blank();
444     test_mf_Graphics();
445     test_mf_PatternBrush();
446 }