gdiplus: Added GdipLoadImageFromFileICM (no icm yet).
[wine] / dlls / gdiplus / tests / graphics.c
1 /*
2  * Unit test suite for graphics objects
3  *
4  * Copyright (C) 2007 Google (Evan Stade)
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "windows.h"
22 #include "gdiplus.h"
23 #include "wingdi.h"
24 #include "wine/test.h"
25
26 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
27 #define TABLE_LEN (23)
28
29 static void test_constructor_destructor(void)
30 {
31     GpStatus stat;
32     GpGraphics *graphics = NULL;
33     HDC hdc = GetDC(0);
34
35     stat = GdipCreateFromHDC(NULL, &graphics);
36     expect(OutOfMemory, stat);
37     stat = GdipDeleteGraphics(graphics);
38     expect(InvalidParameter, stat);
39
40     stat = GdipCreateFromHDC(hdc, &graphics);
41     expect(Ok, stat);
42     stat = GdipDeleteGraphics(graphics);
43     expect(Ok, stat);
44
45     stat = GdipCreateFromHWND(NULL, &graphics);
46     expect(Ok, stat);
47     stat = GdipDeleteGraphics(graphics);
48     expect(Ok, stat);
49
50     stat = GdipDeleteGraphics(NULL);
51     expect(InvalidParameter, stat);
52     ReleaseDC(0, hdc);
53 }
54
55 typedef struct node{
56     GraphicsState data;
57     struct node * next;
58 } node;
59
60 /* Linked list prepend function. */
61 static void log_state(GraphicsState data, node ** log)
62 {
63     node * new_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(node));
64
65     new_entry->data = data;
66     new_entry->next = *log;
67     *log = new_entry;
68 }
69
70 /* Checks if there are duplicates in the list, and frees it. */
71 static void check_no_duplicates(node * log)
72 {
73     INT dups = 0;
74     node * temp = NULL;
75     node * temp2 = NULL;
76     node * orig = log;
77
78     if(!log)
79         goto end;
80
81     do{
82         temp = log;
83         while((temp = temp->next)){
84             if(log->data == temp->data){
85                 dups++;
86                 break;
87             }
88             if(dups > 0)
89                 break;
90         }
91     }while((log = log->next));
92
93     temp = orig;
94     do{
95         temp2 = temp->next;
96         HeapFree(GetProcessHeap(), 0, temp);
97         temp = temp2;
98     }while(temp);
99
100 end:
101     expect(0, dups);
102 }
103
104 static void test_save_restore(void)
105 {
106     GpStatus stat;
107     GraphicsState state_a, state_b, state_c;
108     InterpolationMode mode;
109     GpGraphics *graphics1, *graphics2;
110     node * state_log = NULL;
111     HDC hdc = GetDC(0);
112     state_a = state_b = state_c = 0xdeadbeef;
113
114     /* Invalid saving. */
115     GdipCreateFromHDC(hdc, &graphics1);
116     stat = GdipSaveGraphics(graphics1, NULL);
117     expect(InvalidParameter, stat);
118     stat = GdipSaveGraphics(NULL, &state_a);
119     expect(InvalidParameter, stat);
120     GdipDeleteGraphics(graphics1);
121
122     log_state(state_a, &state_log);
123
124     /* Basic save/restore. */
125     GdipCreateFromHDC(hdc, &graphics1);
126     GdipSetInterpolationMode(graphics1, InterpolationModeBilinear);
127     stat = GdipSaveGraphics(graphics1, &state_a);
128     todo_wine
129         expect(Ok, stat);
130     GdipSetInterpolationMode(graphics1, InterpolationModeBicubic);
131     stat = GdipRestoreGraphics(graphics1, state_a);
132     todo_wine
133         expect(Ok, stat);
134     GdipGetInterpolationMode(graphics1, &mode);
135     todo_wine
136         expect(InterpolationModeBilinear, mode);
137     GdipDeleteGraphics(graphics1);
138
139     log_state(state_a, &state_log);
140
141     /* Restoring garbage doesn't affect saves. */
142     GdipCreateFromHDC(hdc, &graphics1);
143     GdipSetInterpolationMode(graphics1, InterpolationModeBilinear);
144     GdipSaveGraphics(graphics1, &state_a);
145     GdipSetInterpolationMode(graphics1, InterpolationModeBicubic);
146     GdipSaveGraphics(graphics1, &state_b);
147     GdipSetInterpolationMode(graphics1, InterpolationModeNearestNeighbor);
148     stat = GdipRestoreGraphics(graphics1, 0xdeadbeef);
149     todo_wine
150         expect(Ok, stat);
151     GdipRestoreGraphics(graphics1, state_b);
152     GdipGetInterpolationMode(graphics1, &mode);
153     todo_wine
154         expect(InterpolationModeBicubic, mode);
155     GdipRestoreGraphics(graphics1, state_a);
156     GdipGetInterpolationMode(graphics1, &mode);
157     todo_wine
158         expect(InterpolationModeBilinear, mode);
159     GdipDeleteGraphics(graphics1);
160
161     log_state(state_a, &state_log);
162     log_state(state_b, &state_log);
163
164     /* Restoring older state invalidates newer saves (but not older saves). */
165     GdipCreateFromHDC(hdc, &graphics1);
166     GdipSetInterpolationMode(graphics1, InterpolationModeBilinear);
167     GdipSaveGraphics(graphics1, &state_a);
168     GdipSetInterpolationMode(graphics1, InterpolationModeBicubic);
169     GdipSaveGraphics(graphics1, &state_b);
170     GdipSetInterpolationMode(graphics1, InterpolationModeNearestNeighbor);
171     GdipSaveGraphics(graphics1, &state_c);
172     GdipSetInterpolationMode(graphics1, InterpolationModeHighQualityBilinear);
173     GdipRestoreGraphics(graphics1, state_b);
174     GdipGetInterpolationMode(graphics1, &mode);
175     todo_wine
176         expect(InterpolationModeBicubic, mode);
177     GdipRestoreGraphics(graphics1, state_c);
178     GdipGetInterpolationMode(graphics1, &mode);
179     todo_wine
180         expect(InterpolationModeBicubic, mode);
181     GdipRestoreGraphics(graphics1, state_a);
182     GdipGetInterpolationMode(graphics1, &mode);
183     todo_wine
184         expect(InterpolationModeBilinear, mode);
185     GdipDeleteGraphics(graphics1);
186
187     log_state(state_a, &state_log);
188     log_state(state_b, &state_log);
189     log_state(state_c, &state_log);
190
191     /* Restoring older save from one graphics object does not invalidate
192      * newer save from other graphics object. */
193     GdipCreateFromHDC(hdc, &graphics1);
194     GdipCreateFromHDC(hdc, &graphics2);
195     GdipSetInterpolationMode(graphics1, InterpolationModeBilinear);
196     GdipSaveGraphics(graphics1, &state_a);
197     GdipSetInterpolationMode(graphics2, InterpolationModeBicubic);
198     GdipSaveGraphics(graphics2, &state_b);
199     GdipSetInterpolationMode(graphics1, InterpolationModeNearestNeighbor);
200     GdipSetInterpolationMode(graphics2, InterpolationModeNearestNeighbor);
201     GdipRestoreGraphics(graphics1, state_a);
202     GdipGetInterpolationMode(graphics1, &mode);
203     todo_wine
204         expect(InterpolationModeBilinear, mode);
205     GdipRestoreGraphics(graphics2, state_b);
206     GdipGetInterpolationMode(graphics2, &mode);
207     todo_wine
208         expect(InterpolationModeBicubic, mode);
209     GdipDeleteGraphics(graphics1);
210     GdipDeleteGraphics(graphics2);
211
212     /* You can't restore a state to a graphics object that didn't save it. */
213     GdipCreateFromHDC(hdc, &graphics1);
214     GdipCreateFromHDC(hdc, &graphics2);
215     GdipSetInterpolationMode(graphics1, InterpolationModeBilinear);
216     GdipSaveGraphics(graphics1, &state_a);
217     GdipSetInterpolationMode(graphics1, InterpolationModeNearestNeighbor);
218     GdipSetInterpolationMode(graphics2, InterpolationModeNearestNeighbor);
219     GdipRestoreGraphics(graphics2, state_a);
220     GdipGetInterpolationMode(graphics2, &mode);
221     expect(InterpolationModeNearestNeighbor, mode);
222     GdipDeleteGraphics(graphics1);
223     GdipDeleteGraphics(graphics2);
224
225     log_state(state_a, &state_log);
226
227     /* The same state value should never be returned twice. */
228     todo_wine
229         check_no_duplicates(state_log);
230
231     ReleaseDC(0, hdc);
232 }
233
234 static void test_GdipDrawArc(void)
235 {
236     GpStatus status;
237     GpGraphics *graphics = NULL;
238     GpPen *pen = NULL;
239     HDC hdc = GetDC(0);
240
241     /* make a graphics object and pen object */
242     status = GdipCreateFromHDC(hdc, &graphics);
243     expect(Ok, status);
244     ok(hdc != NULL, "Expected HDC to be initialized\n");
245
246     status = GdipCreateFromHDC(hdc, &graphics);
247     expect(Ok, status);
248     ok(graphics != NULL, "Expected graphics to be initialized\n");
249
250     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
251     expect(Ok, status);
252     ok(pen != NULL, "Expected pen to be initialized\n");
253
254     /* InvalidParameter cases: null graphics, null pen, non-positive width, non-positive height */
255     status = GdipDrawArc(NULL, NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
256     expect(InvalidParameter, status);
257
258     status = GdipDrawArc(graphics, NULL, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0);
259     expect(InvalidParameter, status);
260
261     status = GdipDrawArc(NULL, pen, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0);
262     expect(InvalidParameter, status);
263
264     status = GdipDrawArc(graphics, pen, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
265     expect(InvalidParameter, status);
266
267     status = GdipDrawArc(graphics, pen, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
268     expect(InvalidParameter, status);
269
270     /* successful case */
271     status = GdipDrawArc(graphics, pen, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0);
272     expect(Ok, status);
273
274     GdipDeletePen(pen);
275     ReleaseDC(0, hdc);
276 }
277
278 static void test_GdipDrawArcI(void)
279 {
280     GpStatus status;
281     GpGraphics *graphics = NULL;
282     GpPen *pen = NULL;
283     HDC hdc = GetDC(0);
284
285     /* make a graphics object and pen object */
286     status = GdipCreateFromHDC(hdc, &graphics);
287     expect(Ok, status);
288     ok(hdc != NULL, "Expected HDC to be initialized\n");
289
290     status = GdipCreateFromHDC(hdc, &graphics);
291     expect(Ok, status);
292     ok(graphics != NULL, "Expected graphics to be initialized\n");
293
294     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
295     expect(Ok, status);
296     ok(pen != NULL, "Expected pen to be initialized\n");
297
298     /* InvalidParameter cases: null graphics, null pen, non-positive width, non-positive height */
299     status = GdipDrawArcI(NULL, NULL, 0, 0, 0, 0, 0, 0);
300     expect(InvalidParameter, status);
301
302     status = GdipDrawArcI(graphics, NULL, 0, 0, 1, 1, 0, 0);
303     expect(InvalidParameter, status);
304
305     status = GdipDrawArcI(NULL, pen, 0, 0, 1, 1, 0, 0);
306     expect(InvalidParameter, status);
307
308     status = GdipDrawArcI(graphics, pen, 0, 0, 1, 0, 0, 0);
309     expect(InvalidParameter, status);
310
311     status = GdipDrawArcI(graphics, pen, 0, 0, 0, 1, 0, 0);
312     expect(InvalidParameter, status);
313
314     /* successful case */
315     status = GdipDrawArcI(graphics, pen, 0, 0, 1, 1, 0, 0);
316     expect(Ok, status);
317
318     GdipDeletePen(pen);
319     ReleaseDC(0, hdc);
320 }
321
322 static void test_GdipDrawBezierI(void)
323 {
324     GpStatus status;
325     GpGraphics *graphics = NULL;
326     GpPen *pen = NULL;
327     HDC hdc = GetDC(0);
328
329     /* make a graphics object and pen object */
330     status = GdipCreateFromHDC(hdc, &graphics);
331     expect(Ok, status);
332     ok(hdc != NULL, "Expected HDC to be initialized\n");
333
334     status = GdipCreateFromHDC(hdc, &graphics);
335     expect(Ok, status);
336     ok(graphics != NULL, "Expected graphics to be initialized\n");
337
338     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
339     expect(Ok, status);
340     ok(pen != NULL, "Expected pen to be initialized\n");
341
342     /* InvalidParameter cases: null graphics, null pen */
343     status = GdipDrawBezierI(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0);
344     expect(InvalidParameter, status);
345
346     status = GdipDrawBezierI(graphics, NULL, 0, 0, 0, 0, 0, 0, 0, 0);
347     expect(InvalidParameter, status);
348
349     status = GdipDrawBezierI(NULL, pen, 0, 0, 0, 0, 0, 0, 0, 0);
350     expect(InvalidParameter, status);
351
352     /* successful case */
353     status = GdipDrawBezierI(graphics, pen, 0, 0, 0, 0, 0, 0, 0, 0);
354     expect(Ok, status);
355
356     GdipDeletePen(pen);
357     ReleaseDC(0, hdc);
358 }
359
360 static void test_GdipDrawLineI(void)
361 {
362     GpStatus status;
363     GpGraphics *graphics = NULL;
364     GpPen *pen = NULL;
365     HDC hdc = GetDC(0);
366
367     /* make a graphics object and pen object */
368     status = GdipCreateFromHDC(hdc, &graphics);
369     expect(Ok, status);
370     ok(hdc != NULL, "Expected HDC to be initialized\n");
371
372     status = GdipCreateFromHDC(hdc, &graphics);
373     expect(Ok, status);
374     ok(graphics != NULL, "Expected graphics to be initialized\n");
375
376     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
377     expect(Ok, status);
378     ok(pen != NULL, "Expected pen to be initialized\n");
379
380     /* InvalidParameter cases: null graphics, null pen */
381     status = GdipDrawLineI(NULL, NULL, 0, 0, 0, 0);
382     expect(InvalidParameter, status);
383
384     status = GdipDrawLineI(graphics, NULL, 0, 0, 0, 0);
385     expect(InvalidParameter, status);
386
387     status = GdipDrawLineI(NULL, pen, 0, 0, 0, 0);
388     expect(InvalidParameter, status);
389
390     /* successful case */
391     status = GdipDrawLineI(graphics, pen, 0, 0, 0, 0);
392     expect(Ok, status);
393
394     GdipDeletePen(pen);
395     ReleaseDC(0, hdc);
396 }
397
398 static void test_GdipDrawLinesI(void)
399 {
400     GpStatus status;
401     GpGraphics *graphics = NULL;
402     GpPen *pen = NULL;
403     GpPoint *ptf = NULL;
404     HDC hdc = GetDC(0);
405
406     /* make a graphics object and pen object */
407     status = GdipCreateFromHDC(hdc, &graphics);
408     expect(Ok, status);
409     ok(hdc != NULL, "Expected HDC to be initialized\n");
410
411     status = GdipCreateFromHDC(hdc, &graphics);
412     expect(Ok, status);
413     ok(graphics != NULL, "Expected graphics to be initialized\n");
414
415     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
416     expect(Ok, status);
417     ok(pen != NULL, "Expected pen to be initialized\n");
418
419     /* make some arbitrary valid points*/
420     ptf = GdipAlloc(2 * sizeof(GpPointF));
421
422     ptf[0].X = 1;
423     ptf[0].Y = 1;
424
425     ptf[1].X = 2;
426     ptf[1].Y = 2;
427
428     /* InvalidParameter cases: null graphics, null pen, null points, count < 2*/
429     status = GdipDrawLinesI(NULL, NULL, NULL, 0);
430     expect(InvalidParameter, status);
431
432     status = GdipDrawLinesI(graphics, pen, ptf, 0);
433     expect(InvalidParameter, status);
434
435     status = GdipDrawLinesI(graphics, NULL, ptf, 2);
436     expect(InvalidParameter, status);
437
438     status = GdipDrawLinesI(NULL, pen, ptf, 2);
439     expect(InvalidParameter, status);
440
441     /* successful case */
442     status = GdipDrawLinesI(graphics, pen, ptf, 2);
443     expect(Ok, status);
444
445     GdipFree(ptf);
446     GdipDeletePen(pen);
447     ReleaseDC(0, hdc);
448 }
449
450 START_TEST(graphics)
451 {
452     struct GdiplusStartupInput gdiplusStartupInput;
453     ULONG_PTR gdiplusToken;
454
455     gdiplusStartupInput.GdiplusVersion              = 1;
456     gdiplusStartupInput.DebugEventCallback          = NULL;
457     gdiplusStartupInput.SuppressBackgroundThread    = 0;
458     gdiplusStartupInput.SuppressExternalCodecs      = 0;
459
460     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
461
462     test_constructor_destructor();
463     test_save_restore();
464     test_GdipDrawBezierI();
465     test_GdipDrawArc();
466     test_GdipDrawArcI();
467     test_GdipDrawLineI();
468     test_GdipDrawLinesI();
469
470     GdiplusShutdown(gdiplusToken);
471 }