1 /*
2 * graphics.c
3 *
4 * Copyright (c) 2003 Alexandre Pigolkine, Novell Inc.
5 * Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
8 * and associated documentation files (the "Software"), to deal in the Software without restriction,
9 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
17 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors:
23 * Alexandre Pigolkine (pigolkine@gmx.de)
24 * Duncan Mak (duncan@ximian.com)
25 * Sebastien Pouliot <sebastien@ximian.com>
26 * Frederik Carlier <frederik.carlier@quamotion.mobi>
27 */
28
29 #include "graphics-private.h"
30 #include "general-private.h"
31 #include "graphics-cairo-private.h"
32 #include "graphics-metafile-private.h"
33 #include "region-private.h"
34 #include "graphics-path-private.h"
35 #include "brush-private.h"
36 #include "matrix-private.h"
37 #include "bitmap-private.h"
38 #include "metafile-private.h"
39
40 #include <cairo-features.h>
41
42 #define NO_CAIRO_AA
43
44 #define MAX_GRAPHICS_STATE_STACK 512
45
46 float
gdip_unit_conversion(Unit from,Unit to,float dpi,GraphicsType type,float nSrc)47 gdip_unit_conversion (Unit from, Unit to, float dpi, GraphicsType type, float nSrc)
48 {
49 float inchs = 0;
50
51 switch (from) {
52 case UnitDocument:
53 inchs = nSrc / 300.0f;
54 break;
55 case UnitInch:
56 inchs = nSrc;
57 break;
58 case UnitMillimeter:
59 inchs = nSrc / 25.4f;
60 break;
61 case UnitDisplay:
62 if (type == gtPostScript) { /* Uses 1/100th on printers */
63 inchs = nSrc / 100;
64 } else { /* Pixel for video display */
65 inchs = nSrc / dpi;
66 }
67 break;
68 case UnitPixel:
69 case UnitWorld:
70 inchs = nSrc / dpi;
71 break;
72 case UnitPoint:
73 inchs = nSrc / 72.0f;
74 break;
75 case UnitCairoPoint:
76 if (type == gtPostScript) { /* Uses 1/100th on printers */
77 inchs = nSrc / 72.0f;
78 } else { /* Pixel for video display */
79 inchs = nSrc / dpi;
80 }
81 break;
82 default:
83 return nSrc;
84 }
85
86 switch (to) {
87 case UnitDocument:
88 return inchs * 300.0f;
89 case UnitInch:
90 return inchs;
91 case UnitMillimeter:
92 return inchs * 25.4f;
93 case UnitDisplay:
94 if (type == gtPostScript) { /* Uses 1/100th on printers */
95 return inchs * 100;
96 } else { /* Pixel for video display */
97 return inchs * dpi;
98 }
99 case UnitPixel:
100 case UnitWorld:
101 return inchs * dpi;
102 case UnitPoint:
103 return inchs * 72.0f;
104 case UnitCairoPoint:
105 if (type == gtPostScript) { /* Uses 1/100th on printers */
106 return inchs * 72.0f;
107 } else { /* Pixel for video display */
108 return inchs * dpi;
109 }
110 default:
111 return nSrc;
112 }
113 }
114
115 static void
gdip_graphics_reset(GpGraphics * graphics)116 gdip_graphics_reset (GpGraphics *graphics)
117 {
118 /* if required, previous_matrix will be assigned later (e.g. containers) */
119 cairo_matrix_init_identity (&graphics->previous_matrix);
120 GdipResetClip (graphics);
121 cairo_matrix_init_identity (graphics->clip_matrix);
122 graphics->page_unit = UnitDisplay;
123 graphics->scale = 1.0f;
124 graphics->interpolation = InterpolationModeBilinear;
125 graphics->composite_quality = CompositingQualityDefault;
126 graphics->composite_mode = CompositingModeSourceOver;
127 graphics->text_mode = TextRenderingHintSystemDefault;
128 graphics->pixel_mode = PixelOffsetModeDefault;
129 graphics->text_contrast = DEFAULT_TEXT_CONTRAST;
130
131 GdipSetSmoothingMode(graphics, SmoothingModeNone);
132 }
133
134 static void
gdip_graphics_common_init(GpGraphics * graphics)135 gdip_graphics_common_init (GpGraphics *graphics)
136 {
137 graphics->image = NULL;
138 graphics->type = gtUndefined;
139
140 cairo_identity_matrix (graphics->ct);
141
142 GdipCreateMatrix (&graphics->copy_of_ctm);
143 cairo_matrix_init_identity (graphics->copy_of_ctm);
144
145 GdipCreateRegion (&graphics->clip);
146 GdipCreateMatrix (&graphics->clip_matrix);
147 graphics->bounds.X = graphics->bounds.Y = graphics->bounds.Width = graphics->bounds.Height = 0;
148 graphics->orig_bounds.X = graphics->orig_bounds.Y = graphics->orig_bounds.Width = graphics->orig_bounds.Height = 0;
149 graphics->last_pen = NULL;
150 graphics->last_brush = NULL;
151 graphics->saved_status = NULL;
152 graphics->saved_status_pos = 0;
153 graphics->render_origin_x = 0;
154 graphics->render_origin_y = 0;
155 graphics->dpi_x = graphics->dpi_y = 0;
156 graphics->state = GraphicsStateValid;
157
158 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
159 graphics->display = (Display*)NULL;
160 graphics->drawable = (Drawable)NULL;
161 #endif
162
163 gdip_graphics_reset (graphics);
164 }
165
166 static void
gdip_graphics_cairo_init(GpGraphics * graphics,cairo_surface_t * surface)167 gdip_graphics_cairo_init (GpGraphics *graphics, cairo_surface_t *surface)
168 {
169 graphics->backend = GraphicsBackEndCairo;
170
171 graphics->metafile = NULL;
172 graphics->ct = cairo_create (surface);
173
174 #ifndef NO_CAIRO_AA
175 cairo_set_shape_format (graphics->ct, CAIRO_FORMAT_A1);
176 #endif
177 /* cairo_select_font_face (graphics->ct, "serif:12"); */
178 cairo_select_font_face (graphics->ct, "serif:12", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
179
180 gdip_graphics_common_init (graphics);
181 }
182
183 GpGraphics *
gdip_graphics_new(cairo_surface_t * surface)184 gdip_graphics_new (cairo_surface_t *surface)
185 {
186 GpGraphics *result = (GpGraphics *) GdipAlloc (sizeof (GpGraphics));
187
188 if (result)
189 gdip_graphics_cairo_init (result, surface);
190
191 return result;
192 }
193
194 static void
gdip_graphics_metafile_init(GpGraphics * graphics,GpMetafile * metafile)195 gdip_graphics_metafile_init (GpGraphics *graphics, GpMetafile *metafile)
196 {
197 graphics->backend = GraphicsBackEndMetafile;
198 /* some API requires a valid cairo context (even on a metafile-based graphics) */
199 graphics->metasurface = cairo_image_surface_create (CAIRO_FORMAT_A1, 1, 1);
200 graphics->ct = cairo_create (graphics->metasurface);
201 graphics->metafile = metafile;
202
203 gdip_graphics_common_init (graphics);
204 }
205
206 GpGraphics*
gdip_metafile_graphics_new(GpMetafile * metafile)207 gdip_metafile_graphics_new (GpMetafile *metafile)
208 {
209 GpGraphics *result = (GpGraphics *) GdipAlloc (sizeof (GpGraphics));
210
211 if (result)
212 gdip_graphics_metafile_init (result, metafile);
213
214 return result;
215 }
216
217 // coverity[+alloc : arg-*1]
218 GpStatus WINGDIPAPI
GdipCreateFromHDC(HDC hdc,GpGraphics ** graphics)219 GdipCreateFromHDC (HDC hdc, GpGraphics **graphics)
220 {
221 GpGraphics *clone = (GpGraphics *)hdc;
222 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
223 cairo_surface_t *surface;
224 int x, y;
225 unsigned int w, h, border_w, depth;
226 #endif
227
228 if (!gdiplusInitialized)
229 return GdiplusNotInitialized;
230
231 if (!graphics)
232 return InvalidParameter;
233
234 if (!hdc)
235 return OutOfMemory;
236
237 #if defined(WIN32)
238 // HDC returns to a device context. The remainer of this function assumes that hdc really
239 // is a GpGrahpics, but that's almost guaranteed to be not the case on Windows. Just fail
240 // quickly instead of segfauling.
241 return NotImplemented;
242 #endif
243
244 #ifdef CAIRO_HAS_PS_SURFACE
245
246 if (clone->type == gtPostScript) {
247 *graphics = clone;
248 return Ok;
249 }
250 #endif
251
252 if (clone->type == gtMemoryBitmap)
253 return GdipGetImageGraphicsContext (clone->image, graphics);
254
255 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
256 Window root;
257 XGetGeometry (clone->display, clone->drawable, &root,
258 &x, &y, &w, &h, &border_w, &depth);
259
260 surface = cairo_xlib_surface_create(clone->display, clone->drawable,
261 DefaultVisual(clone->display, DefaultScreen(clone->display)),
262 w, h);
263
264 *graphics = gdip_graphics_new (surface);
265 if (!*graphics) {
266 cairo_surface_destroy (surface);
267 return OutOfMemory;
268 }
269
270 (*graphics)->dpi_x = (*graphics)->dpi_y = gdip_get_display_dpi ();
271 cairo_surface_destroy (surface);
272
273 if ((*graphics)->drawable)
274 (*graphics)->drawable = clone->drawable;
275
276 if ((*graphics)->display)
277 (*graphics)->display = clone->display;
278
279 return Ok;
280 #endif
281
282 return NotImplemented;
283 }
284
285 GpStatus WINGDIPAPI
GdipCreateFromHDC2(HDC hdc,HANDLE hDevice,GpGraphics ** graphics)286 GdipCreateFromHDC2 (HDC hdc, HANDLE hDevice, GpGraphics **graphics)
287 {
288 if (!gdiplusInitialized)
289 return GdiplusNotInitialized;
290
291 if (!graphics)
292 return InvalidParameter;
293
294 if (hDevice)
295 return NotImplemented;
296
297 return GdipCreateFromHDC (hdc, graphics);
298 }
299
300 GpStatus WINGDIPAPI
GdipCreateFromHWND(HWND hwnd,GpGraphics ** graphics)301 GdipCreateFromHWND (HWND hwnd, GpGraphics **graphics)
302 {
303 if (!gdiplusInitialized)
304 return GdiplusNotInitialized;
305
306 if (!graphics)
307 return InvalidParameter;
308
309 return NotImplemented;
310 }
311
312 GpStatus WINGDIPAPI
GdipCreateFromHWNDICM(HWND hwnd,GpGraphics ** graphics)313 GdipCreateFromHWNDICM (HWND hwnd, GpGraphics **graphics)
314 {
315 return GdipCreateFromHWND (hwnd, graphics);
316 }
317
318 #ifdef CAIRO_HAS_QUARTZ_SURFACE
319 // coverity[+alloc : arg-*3]
320 GpStatus
GdipCreateFromContext_macosx(void * ctx,int width,int height,GpGraphics ** graphics)321 GdipCreateFromContext_macosx (void *ctx, int width, int height, GpGraphics **graphics)
322 {
323 cairo_surface_t *surface;
324
325 if (!graphics)
326 return InvalidParameter;
327
328 surface = cairo_quartz_surface_create (0, width, height);
329
330 *graphics = gdip_graphics_new (surface);
331 if (!*graphics) {
332 cairo_surface_destroy (surface);
333 return OutOfMemory;
334 }
335
336 (*graphics)->dpi_x = (*graphics)->dpi_y = gdip_get_display_dpi ();
337 cairo_surface_destroy (surface);
338
339 (*graphics)->bounds.Width = width;
340 (*graphics)->bounds.Height = height;
341 (*graphics)->orig_bounds.Width = width;
342 (*graphics)->orig_bounds.Height = height;
343
344 (*graphics)->type = gtOSXDrawable;
345 (*graphics)->cg_context = ctx;
346
347 return Ok;
348 }
349
350 #endif
351
352 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
353
354 // coverity[+alloc : arg-*2]
355 GpStatus
GdipCreateFromXDrawable_linux(Drawable d,Display * dpy,GpGraphics ** graphics)356 GdipCreateFromXDrawable_linux(Drawable d, Display *dpy, GpGraphics **graphics)
357 {
358 Window root_ignore;
359 GpRect bounds;
360 int bwidth_ignore, depth_ignore;
361 cairo_surface_t *surface;
362
363 if (!graphics)
364 return InvalidParameter;
365
366 XGetGeometry (dpy, d, &root_ignore, &bounds.X, &bounds.Y,
367 (unsigned int *)&bounds.Width, (unsigned int *)&bounds.Height,
368 (unsigned int *)&bwidth_ignore, (unsigned int *)&depth_ignore);
369
370 surface = cairo_xlib_surface_create(dpy, d,
371 DefaultVisual(dpy, DefaultScreen(dpy)),
372 bounds.Width, bounds.Height);
373
374
375 *graphics = gdip_graphics_new(surface);
376 if (!*graphics) {
377 cairo_surface_destroy (surface);
378 return OutOfMemory;
379 }
380
381 (*graphics)->dpi_x = (*graphics)->dpi_y = gdip_get_display_dpi ();
382 cairo_surface_destroy (surface);
383
384 (*graphics)->type = gtX11Drawable;
385 (*graphics)->display = dpy;
386 (*graphics)->drawable = d;
387
388 GdipSetVisibleClip_linux (*graphics, &bounds);
389 return Ok;
390 }
391
392 #endif
393
394 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
395 static int
ignore_error_handler(Display * dpy,XErrorEvent * event)396 ignore_error_handler (Display *dpy, XErrorEvent *event)
397 {
398 return Success;
399 }
400 #endif
401
402 GpStatus WINGDIPAPI
GdipDeleteGraphics(GpGraphics * graphics)403 GdipDeleteGraphics (GpGraphics *graphics)
404 {
405 if (!graphics)
406 return InvalidParameter;
407
408 if (graphics->state != GraphicsStateValid)
409 return ObjectBusy;
410
411 /* We don't destroy image because we did not create one. */
412 if (graphics->copy_of_ctm) {
413 GdipDeleteMatrix (graphics->copy_of_ctm);
414 graphics->copy_of_ctm = NULL;
415 }
416
417 if (graphics->clip) {
418 GdipDeleteRegion (graphics->clip);
419 graphics->clip = NULL;
420 }
421
422 if (graphics->clip_matrix) {
423 GdipDeleteMatrix (graphics->clip_matrix);
424 graphics->clip_matrix = NULL;
425 }
426
427 if (graphics->ct) {
428 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
429 int (*old_error_handler)(Display *dpy, XErrorEvent *ev) = NULL;
430 if (graphics->type == gtX11Drawable)
431 old_error_handler = XSetErrorHandler (ignore_error_handler);
432 #endif
433
434 cairo_destroy (graphics->ct);
435 graphics->ct = NULL;
436
437 #if defined(HAVE_X11) && CAIRO_HAS_XLIB_SURFACE
438 if (graphics->type == gtX11Drawable)
439 XSetErrorHandler (old_error_handler);
440 #endif
441 }
442
443 if (graphics->backend == GraphicsBackEndMetafile) {
444 /* if recording this is where we save the metafile (stream or file) */
445 if (graphics->metafile->recording)
446 gdip_metafile_stop_recording (graphics->metafile);
447 cairo_surface_destroy (graphics->metasurface);
448 graphics->metasurface = NULL;
449 }
450
451 if (graphics->saved_status) {
452 GpState* pos_state = graphics->saved_status;
453 int i;
454
455 for (i = 0; i < MAX_GRAPHICS_STATE_STACK; i++, pos_state++) {
456 if (pos_state->clip)
457 GdipDeleteRegion (pos_state->clip);
458 }
459
460 GdipFree (graphics->saved_status);
461 graphics->saved_status = NULL;
462 }
463
464 GdipFree (graphics);
465 return Ok;
466 }
467
468 GpStatus WINGDIPAPI
GdipGetDC(GpGraphics * graphics,HDC * hdc)469 GdipGetDC (GpGraphics *graphics, HDC *hdc)
470 {
471 if (!graphics || !hdc)
472 return InvalidParameter;
473
474 if (graphics->state == GraphicsStateBusy)
475 return ObjectBusy;
476
477 *hdc = (void *)graphics;
478 graphics->state = GraphicsStateBusy;
479
480 return Ok;
481 }
482
483 GpStatus WINGDIPAPI
GdipReleaseDC(GpGraphics * graphics,HDC hdc)484 GdipReleaseDC (GpGraphics *graphics, HDC hdc)
485 {
486 if (!graphics || !hdc || graphics->state != GraphicsStateBusy)
487 return InvalidParameter;
488
489 if (hdc != (void *)graphics)
490 return InvalidParameter;
491
492 graphics->state = GraphicsStateValid;
493
494 return Ok;
495 }
496
497 GpStatus WINGDIPAPI
GdipRestoreGraphics(GpGraphics * graphics,GraphicsState state)498 GdipRestoreGraphics (GpGraphics *graphics, GraphicsState state)
499 {
500 GpStatus status;
501 GpState *pos_state;
502
503 if (!graphics)
504 return InvalidParameter;
505
506 if (state <= 0 || (state - 1) >= MAX_GRAPHICS_STATE_STACK || (state - 1) > graphics->saved_status_pos)
507 return InvalidParameter;
508
509 pos_state = graphics->saved_status;
510 pos_state += (state - 1);
511
512 /* Save from GpState to Graphics */
513 gdip_cairo_matrix_copy (graphics->copy_of_ctm, &pos_state->matrix);
514 gdip_cairo_matrix_copy (&graphics->previous_matrix, &pos_state->previous_matrix);
515
516 GdipSetRenderingOrigin (graphics, pos_state->org_x, pos_state->org_y);
517
518 if (graphics->clip)
519 GdipDeleteRegion (graphics->clip);
520 status = GdipCloneRegion (pos_state->clip, &graphics->clip);
521 if (status != Ok)
522 return status;
523
524 gdip_cairo_matrix_copy (graphics->clip_matrix, &pos_state->clip_matrix);
525
526 graphics->composite_mode = pos_state->composite_mode;
527 graphics->composite_quality = pos_state->composite_quality;
528 graphics->interpolation = pos_state->interpolation;
529 graphics->page_unit = pos_state->page_unit;
530 graphics->scale = pos_state->scale;
531 GdipSetSmoothingMode(graphics, pos_state->draw_mode);
532 graphics->text_mode = pos_state->text_mode;
533 graphics->pixel_mode = pos_state->pixel_mode;
534 graphics->text_contrast = pos_state->text_contrast;
535
536 graphics->saved_status_pos = state;
537
538 /* re-adjust clipping (region and matrix) */
539 gdip_cairo_set_matrix (graphics, graphics->copy_of_ctm);
540
541 /* GdipCloneRegion was called, but for some reason, not registred as an allocation */
542 /* coverity[freed_arg] */
543 return cairo_SetGraphicsClip (graphics);
544 }
545
546 GpStatus WINGDIPAPI
GdipSaveGraphics(GpGraphics * graphics,GraphicsState * state)547 GdipSaveGraphics (GpGraphics *graphics, GraphicsState *state)
548 {
549 GpStatus status;
550 GpState* pos_state;
551
552 if (!graphics || !state)
553 return InvalidParameter;
554
555 if (!graphics->saved_status) {
556 graphics->saved_status = gdip_calloc (MAX_GRAPHICS_STATE_STACK, sizeof (GpState));
557 if (!graphics->saved_status)
558 return OutOfMemory;
559
560 graphics->saved_status_pos = 0;
561 }
562
563 if (graphics->saved_status_pos >= MAX_GRAPHICS_STATE_STACK)
564 return OutOfMemory;
565
566 pos_state = graphics->saved_status;
567 pos_state += graphics->saved_status_pos;
568
569 /* Save from Graphics to GpState */
570 gdip_cairo_matrix_copy (&pos_state->matrix, graphics->copy_of_ctm);
571 GdipGetRenderingOrigin (graphics, &pos_state->org_x, &pos_state->org_y);
572
573 gdip_cairo_matrix_copy (&pos_state->previous_matrix, &graphics->previous_matrix);
574
575 if (pos_state->clip)
576 GdipDeleteRegion (pos_state->clip);
577 status = GdipCloneRegion (graphics->clip, &pos_state->clip);
578 if (status != Ok)
579 return status;
580
581 gdip_cairo_matrix_copy (&pos_state->clip_matrix, graphics->clip_matrix);
582
583 pos_state->composite_mode = graphics->composite_mode;
584 pos_state->composite_quality = graphics->composite_quality;
585 pos_state->interpolation = graphics->interpolation;
586 pos_state->page_unit = graphics->page_unit;
587 pos_state->scale = graphics->scale;
588 pos_state->draw_mode = graphics->draw_mode;
589 pos_state->text_mode = graphics->text_mode;
590 pos_state->pixel_mode = graphics->pixel_mode;
591 pos_state->text_contrast = graphics->text_contrast;
592
593 *state = graphics->saved_status_pos + 1; // make sure GraphicsState is non-zero for compat with GDI+
594 graphics->saved_status_pos++;
595 return Ok;
596 }
597
598 static void
apply_world_to_bounds(GpGraphics * graphics)599 apply_world_to_bounds (GpGraphics *graphics)
600 {
601 GpPointF pts[2];
602
603 pts[0].X = graphics->orig_bounds.X;
604 pts[0].Y = graphics->orig_bounds.Y;
605 pts[1].X = graphics->orig_bounds.X + graphics->orig_bounds.Width;
606 pts[1].Y = graphics->orig_bounds.Y + graphics->orig_bounds.Height;
607 GdipTransformMatrixPoints (graphics->clip_matrix, pts, 2);
608
609 if (pts[0].X > pts[1].X) {
610 graphics->bounds.X = pts[1].X;
611 graphics->bounds.Width = iround (pts[0].X - pts[1].X);
612 } else {
613 graphics->bounds.X = pts[0].X;
614 graphics->bounds.Width = iround (pts[1].X - pts[0].X);
615 }
616 if (pts[0].Y > pts[1].Y) {
617 graphics->bounds.Y = pts[1].Y;
618 graphics->bounds.Height = iround (pts[0].Y - pts[1].Y);
619 } else {
620 graphics->bounds.Y = pts[0].Y;
621 graphics->bounds.Height = iround (pts[1].Y - pts[0].Y);
622 }
623 }
624
625 GpStatus WINGDIPAPI
GdipResetWorldTransform(GpGraphics * graphics)626 GdipResetWorldTransform (GpGraphics *graphics)
627 {
628 if (!graphics)
629 return InvalidParameter;
630
631 if (!gdip_is_matrix_empty (&graphics->previous_matrix)) {
632 /* inside a container only reset to the previous transform */
633 gdip_cairo_matrix_copy (graphics->copy_of_ctm, &graphics->previous_matrix);
634 gdip_cairo_matrix_copy (graphics->clip_matrix, &graphics->previous_matrix);
635 GdipInvertMatrix (graphics->clip_matrix);
636 } else {
637 cairo_matrix_init_identity (graphics->copy_of_ctm);
638 cairo_matrix_init_identity (graphics->clip_matrix);
639 }
640
641 apply_world_to_bounds (graphics);
642
643 switch (graphics->backend) {
644 case GraphicsBackEndCairo:
645 return cairo_ResetWorldTransform (graphics);
646 case GraphicsBackEndMetafile:
647 return metafile_ResetWorldTransform (graphics);
648 default:
649 return GenericError;
650 }
651 }
652
653 GpStatus WINGDIPAPI
GdipSetWorldTransform(GpGraphics * graphics,GpMatrix * matrix)654 GdipSetWorldTransform (GpGraphics *graphics, GpMatrix *matrix)
655 {
656 BOOL invertible;
657
658 if (!graphics)
659 return InvalidParameter;
660 if (graphics->state == GraphicsStateBusy)
661 return ObjectBusy;
662 if (!matrix)
663 return InvalidParameter;
664
665 // Inverting an identity matrix result in the identity matrix.
666 if (gdip_is_matrix_empty (matrix))
667 return GdipResetWorldTransform (graphics);
668
669 // The matrix must be invertible to be used.
670 GdipIsMatrixInvertible (matrix, &invertible);
671 if (!invertible)
672 return InvalidParameter;
673
674 GpMatrix matrixCopy;
675 gdip_cairo_matrix_copy (&matrixCopy, matrix);
676
677 if (!gdip_is_matrix_empty (&graphics->previous_matrix)) {
678 /* inside a container the transform is appended to the previous transform */
679 GdipMultiplyMatrix (&matrixCopy, &graphics->previous_matrix, MatrixOrderAppend);
680 }
681
682 gdip_cairo_matrix_copy (graphics->copy_of_ctm, &matrixCopy);
683 gdip_cairo_matrix_copy (graphics->clip_matrix, &matrixCopy);
684
685 /* we already know it's invertible */
686 GdipInvertMatrix (graphics->clip_matrix);
687
688 apply_world_to_bounds (graphics);
689
690 switch (graphics->backend) {
691 case GraphicsBackEndCairo:
692 return cairo_SetWorldTransform (graphics, &matrixCopy);
693 case GraphicsBackEndMetafile:
694 return metafile_SetWorldTransform (graphics, &matrixCopy);
695 default:
696 return GenericError;
697 }
698 }
699
700 GpStatus WINGDIPAPI
GdipGetWorldTransform(GpGraphics * graphics,GpMatrix * matrix)701 GdipGetWorldTransform (GpGraphics *graphics, GpMatrix *matrix)
702 {
703 if (!graphics || !matrix)
704 return InvalidParameter;
705
706 if (graphics->state == GraphicsStateBusy)
707 return ObjectBusy;
708
709 /* get the effective matrix from cairo */
710 gdip_cairo_matrix_copy (matrix, graphics->copy_of_ctm);
711
712 /* if we're inside a container then the previous matrix are hidden */
713 if (!gdip_is_matrix_empty (&graphics->previous_matrix)) {
714 cairo_matrix_t inverted;
715 /* substract the previous matrix from the effective matrix */
716 gdip_cairo_matrix_copy (&inverted, &graphics->previous_matrix);
717 cairo_matrix_invert (&inverted);
718 return GdipMultiplyMatrix (matrix, &inverted, MatrixOrderAppend);
719 }
720 return Ok;
721 }
722
723 GpStatus WINGDIPAPI
GdipMultiplyWorldTransform(GpGraphics * graphics,GpMatrix * matrix,GpMatrixOrder order)724 GdipMultiplyWorldTransform (GpGraphics *graphics, GpMatrix *matrix, GpMatrixOrder order)
725 {
726 GpStatus s;
727 BOOL invertible;
728 GpMatrix inverted;
729
730 if (!graphics)
731 return InvalidParameter;
732
733 /* the matrix MUST be invertible to be used */
734 s = GdipIsMatrixInvertible (matrix, &invertible);
735 if (!invertible || (s != Ok))
736 return InvalidParameter;
737
738 s = GdipMultiplyMatrix (graphics->copy_of_ctm, matrix, order);
739 if (s != Ok)
740 return s;
741
742 /* Multiply the inverted matrix with the clipping matrix */
743 gdip_cairo_matrix_copy (&inverted, matrix);
744 s = GdipInvertMatrix (&inverted);
745 if (s != Ok)
746 return s;
747
748 s = GdipMultiplyMatrix (graphics->clip_matrix, &inverted, order);
749 if (s != Ok)
750 return s;
751
752 apply_world_to_bounds (graphics);
753
754 switch (graphics->backend) {
755 case GraphicsBackEndCairo:
756 /* not a typo - we apply to calculated matrix to cairo context */
757 return cairo_SetWorldTransform (graphics, graphics->copy_of_ctm);
758 case GraphicsBackEndMetafile:
759 return metafile_MultiplyWorldTransform (graphics, matrix, order);
760 default:
761 return GenericError;
762 }
763 }
764
765 GpStatus WINGDIPAPI
GdipRotateWorldTransform(GpGraphics * graphics,REAL angle,GpMatrixOrder order)766 GdipRotateWorldTransform (GpGraphics *graphics, REAL angle, GpMatrixOrder order)
767 {
768 GpStatus s;
769
770 if (!graphics)
771 return InvalidParameter;
772
773 if (graphics->state == GraphicsStateBusy)
774 return ObjectBusy;
775
776 s = GdipRotateMatrix (graphics->copy_of_ctm, angle, order);
777 if (s != Ok)
778 return s;
779
780 s = GdipRotateMatrix (graphics->clip_matrix, -angle, gdip_matrix_reverse_order (order));
781 if (s != Ok)
782 return s;
783
784 apply_world_to_bounds (graphics);
785
786 switch (graphics->backend) {
787 case GraphicsBackEndCairo:
788 /* not a typo - we apply to calculated matrix to cairo context */
789 return cairo_SetWorldTransform (graphics, graphics->copy_of_ctm);
790 case GraphicsBackEndMetafile:
791 return metafile_RotateWorldTransform (graphics, angle, order);
792 default:
793 return GenericError;
794 }
795 }
796
797 GpStatus WINGDIPAPI
GdipScaleWorldTransform(GpGraphics * graphics,REAL sx,REAL sy,GpMatrixOrder order)798 GdipScaleWorldTransform (GpGraphics *graphics, REAL sx, REAL sy, GpMatrixOrder order)
799 {
800 GpStatus s;
801
802 if (!graphics || (sx == 0.0f) || (sy == 0.0f))
803 return InvalidParameter;
804
805 s = GdipScaleMatrix (graphics->copy_of_ctm, sx, sy, order);
806 if (s != Ok)
807 return s;
808
809 s = GdipScaleMatrix (graphics->clip_matrix, (1.0f / sx), (1.0f / sy), gdip_matrix_reverse_order (order));
810 if (s != Ok)
811 return s;
812
813 apply_world_to_bounds (graphics);
814
815 switch (graphics->backend) {
816 case GraphicsBackEndCairo:
817 /* not a typo - we apply to calculated matrix to cairo context */
818 return cairo_SetWorldTransform (graphics, graphics->copy_of_ctm);
819 case GraphicsBackEndMetafile:
820 return metafile_ScaleWorldTransform (graphics, sx, sy, order);
821 default:
822 return GenericError;
823 }
824 }
825
826 GpStatus WINGDIPAPI
GdipTranslateWorldTransform(GpGraphics * graphics,REAL dx,REAL dy,GpMatrixOrder order)827 GdipTranslateWorldTransform (GpGraphics *graphics, REAL dx, REAL dy, GpMatrixOrder order)
828 {
829 GpStatus s;
830
831 if (!graphics)
832 return InvalidParameter;
833
834 s = GdipTranslateMatrix (graphics->copy_of_ctm, dx, dy, order);
835 if (s != Ok)
836 return s;
837
838 s = GdipTranslateMatrix (graphics->clip_matrix, -dx, -dy, gdip_matrix_reverse_order (order));
839 if (s != Ok)
840 return s;
841
842 apply_world_to_bounds (graphics);
843
844 switch (graphics->backend) {
845 case GraphicsBackEndCairo:
846 /* not a typo - we apply to calculated matrix to cairo context */
847 return cairo_SetWorldTransform (graphics, graphics->copy_of_ctm);
848 case GraphicsBackEndMetafile:
849 return metafile_TranslateWorldTransform (graphics, dx, dy, order);
850 default:
851 return GenericError;
852 }
853 }
854
855 /*
856 * Draw operations - validate parameters and delegate to cairo/metafile backends
857 */
858
859 GpStatus WINGDIPAPI
GdipDrawArc(GpGraphics * graphics,GpPen * pen,REAL x,REAL y,REAL width,REAL height,REAL startAngle,REAL sweepAngle)860 GdipDrawArc (GpGraphics *graphics, GpPen *pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
861 {
862 if (!graphics)
863 return InvalidParameter;
864 if (graphics->state == GraphicsStateBusy)
865 return ObjectBusy;
866 if (!pen || width <= 0 || height <= 0)
867 return InvalidParameter;
868
869 switch (graphics->backend) {
870 case GraphicsBackEndCairo:
871 return cairo_DrawArc (graphics, pen, x, y, width, height, startAngle, sweepAngle);
872 case GraphicsBackEndMetafile:
873 return metafile_DrawArc (graphics, pen, x, y, width, height, startAngle, sweepAngle);
874 default:
875 return GenericError;
876 }
877 }
878
879 GpStatus WINGDIPAPI
GdipDrawArcI(GpGraphics * graphics,GpPen * pen,INT x,INT y,INT width,INT height,REAL startAngle,REAL sweepAngle)880 GdipDrawArcI (GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
881 {
882 return GdipDrawArc (graphics, pen, x, y, width, height, startAngle, sweepAngle);
883 }
884
885 GpStatus WINGDIPAPI
GdipDrawBezier(GpGraphics * graphics,GpPen * pen,REAL x1,REAL y1,REAL x2,REAL y2,REAL x3,REAL y3,REAL x4,REAL y4)886 GdipDrawBezier (GpGraphics *graphics, GpPen *pen, REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3,
887 REAL x4, REAL y4)
888 {
889 PointF points[4] = {
890 {x1, y1},
891 {x2, y2},
892 {x3, y3},
893 {x4, y4}
894 };
895
896 return GdipDrawBeziers (graphics, pen, points, 4);
897 }
898
899 GpStatus WINGDIPAPI
GdipDrawBezierI(GpGraphics * graphics,GpPen * pen,INT x1,INT y1,INT x2,INT y2,INT x3,INT y3,INT x4,INT y4)900 GdipDrawBezierI (GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4)
901 {
902 return GdipDrawBezier (graphics, pen, x1, y1, x2, y2, x3, y3, x4, y4);
903 }
904
905 GpStatus WINGDIPAPI
GdipDrawBeziers(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count)906 GdipDrawBeziers (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *points, INT count)
907 {
908 if (!graphics || !points || count <= 0 || (count > 3 && (count % 3) != 1))
909 return InvalidParameter;
910 if (graphics->state == GraphicsStateBusy)
911 return ObjectBusy;
912 if (!pen)
913 return InvalidParameter;
914
915 // Nop if the count is too small to fit any bezier paths.
916 if (count < 3)
917 return Ok;
918
919 switch (graphics->backend) {
920 case GraphicsBackEndCairo:
921 return cairo_DrawBeziers (graphics, pen, points, count);
922 case GraphicsBackEndMetafile:
923 return metafile_DrawBeziers (graphics, pen, points, count);
924 default:
925 return GenericError;
926 }
927 }
928
929 GpStatus WINGDIPAPI
GdipDrawBeziersI(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count)930 GdipDrawBeziersI (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count)
931 {
932 GpStatus status;
933 GpPointF *pointsF;
934
935 if (!points || count < 0)
936 return InvalidParameter;
937
938 pointsF = convert_points (points, count);
939 if (!pointsF)
940 return OutOfMemory;
941
942 status = GdipDrawBeziers (graphics, pen, pointsF, count);
943
944 GdipFree (pointsF);
945 return status;
946 }
947
948 GpStatus WINGDIPAPI
GdipDrawEllipse(GpGraphics * graphics,GpPen * pen,REAL x,REAL y,REAL width,REAL height)949 GdipDrawEllipse (GpGraphics *graphics, GpPen *pen, REAL x, REAL y, REAL width, REAL height)
950 {
951 if (!graphics)
952 return InvalidParameter;
953 if (graphics->state == GraphicsStateBusy)
954 return ObjectBusy;
955 if (!pen)
956 return InvalidParameter;
957
958 switch (graphics->backend) {
959 case GraphicsBackEndCairo:
960 return cairo_DrawEllipse (graphics, pen, x, y, width, height);
961 case GraphicsBackEndMetafile:
962 return metafile_DrawEllipse (graphics, pen, x, y, width, height);
963 default:
964 return GenericError;
965 }
966 }
967
968 GpStatus WINGDIPAPI
GdipDrawEllipseI(GpGraphics * graphics,GpPen * pen,INT x,INT y,INT width,INT height)969 GdipDrawEllipseI (GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height)
970 {
971 return GdipDrawEllipse (graphics, pen, x, y, width, height);
972 }
973
974 GpStatus WINGDIPAPI
GdipDrawLine(GpGraphics * graphics,GpPen * pen,REAL x1,REAL y1,REAL x2,REAL y2)975 GdipDrawLine (GpGraphics *graphics, GpPen *pen, REAL x1, REAL y1, REAL x2, REAL y2)
976 {
977 PointF points[2] = {
978 {x1, y1},
979 {x2, y2}
980 };
981 return GdipDrawLines (graphics, pen, points, 2);
982 }
983
984 GpStatus WINGDIPAPI
GdipDrawLineI(GpGraphics * graphics,GpPen * pen,INT x1,INT y1,INT x2,INT y2)985 GdipDrawLineI (GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2)
986 {
987 return GdipDrawLine (graphics, pen, x1, y1, x2, y2);
988 }
989
990 GpStatus WINGDIPAPI
GdipDrawLines(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count)991 GdipDrawLines (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *points, INT count)
992 {
993 if (!graphics || !points || count <= 0)
994 return InvalidParameter;
995 if (graphics->state == GraphicsStateBusy)
996 return ObjectBusy;
997 if (!pen || count < 2)
998 return InvalidParameter;
999
1000 switch (graphics->backend) {
1001 case GraphicsBackEndCairo:
1002 return cairo_DrawLines (graphics, pen, points, count);
1003 case GraphicsBackEndMetafile:
1004 return metafile_DrawLines (graphics, pen, points, count);
1005 default:
1006 return GenericError;
1007 }
1008 }
1009
1010 GpStatus WINGDIPAPI
GdipDrawLinesI(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count)1011 GdipDrawLinesI (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count)
1012 {
1013 GpStatus status;
1014 GpPointF *pointsF;
1015
1016 if (count < 0)
1017 return OutOfMemory;
1018 if (!points)
1019 return InvalidParameter;
1020
1021 pointsF = convert_points (points, count);
1022 if (!pointsF)
1023 return OutOfMemory;
1024
1025 status = GdipDrawLines (graphics, pen, pointsF, count);
1026
1027 GdipFree (pointsF);
1028 return status;
1029 }
1030
1031 GpStatus WINGDIPAPI
GdipDrawPath(GpGraphics * graphics,GpPen * pen,GpPath * path)1032 GdipDrawPath (GpGraphics *graphics, GpPen *pen, GpPath *path)
1033 {
1034 if (!graphics)
1035 return InvalidParameter;
1036 if (graphics->state == GraphicsStateBusy)
1037 return ObjectBusy;
1038 if (!pen || !path)
1039 return InvalidParameter;
1040
1041 switch (graphics->backend) {
1042 case GraphicsBackEndCairo:
1043 return cairo_DrawPath (graphics, pen, path);
1044 case GraphicsBackEndMetafile:
1045 return metafile_DrawPath (graphics, pen, path);
1046 default:
1047 return GenericError;
1048 }
1049 }
1050
1051 GpStatus WINGDIPAPI
GdipDrawPie(GpGraphics * graphics,GpPen * pen,REAL x,REAL y,REAL width,REAL height,REAL startAngle,REAL sweepAngle)1052 GdipDrawPie (GpGraphics *graphics, GpPen *pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
1053 {
1054 if (!graphics)
1055 return InvalidParameter;
1056 if (graphics->state == GraphicsStateBusy)
1057 return ObjectBusy;
1058 if (!pen || width <= 0 || height <= 0)
1059 return InvalidParameter;
1060
1061 /* We don't do anything, if sweep angle is zero. */
1062 if (sweepAngle == 0)
1063 return Ok;
1064
1065 switch (graphics->backend) {
1066 case GraphicsBackEndCairo:
1067 return cairo_DrawPie (graphics, pen, x, y, width, height, startAngle, sweepAngle);
1068 case GraphicsBackEndMetafile:
1069 return metafile_DrawPie (graphics, pen, x, y, width, height, startAngle, sweepAngle);
1070 default:
1071 return GenericError;
1072 }
1073 }
1074
1075 GpStatus WINGDIPAPI
GdipDrawPieI(GpGraphics * graphics,GpPen * pen,INT x,INT y,INT width,INT height,REAL startAngle,REAL sweepAngle)1076 GdipDrawPieI (GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
1077 {
1078 return GdipDrawPie (graphics, pen, x, y, width, height, startAngle, sweepAngle);
1079 }
1080
1081 GpStatus WINGDIPAPI
GdipDrawPolygon(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count)1082 GdipDrawPolygon (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *points, INT count)
1083 {
1084 if (!graphics || !points || count <= 0)
1085 return InvalidParameter;
1086 if (graphics->state == GraphicsStateBusy)
1087 return ObjectBusy;
1088 if (!pen || count < 2)
1089 return InvalidParameter;
1090
1091 switch (graphics->backend) {
1092 case GraphicsBackEndCairo:
1093 return cairo_DrawPolygon (graphics, pen, points, count);
1094 case GraphicsBackEndMetafile:
1095 return metafile_DrawPolygon (graphics, pen, points, count);
1096 default:
1097 return GenericError;
1098 }
1099 }
1100
1101 GpStatus WINGDIPAPI
GdipDrawPolygonI(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count)1102 GdipDrawPolygonI (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count)
1103 {
1104 GpStatus status;
1105 GpPointF *pointsF;
1106
1107 if (count < 0)
1108 return OutOfMemory;
1109 if (!points)
1110 return InvalidParameter;
1111
1112 pointsF = convert_points (points, count);
1113 if (!pointsF)
1114 return OutOfMemory;
1115
1116 status = GdipDrawPolygon (graphics, pen, pointsF, count);
1117
1118 GdipFree (pointsF);
1119 return status;
1120 }
1121
1122 GpStatus WINGDIPAPI
GdipDrawRectangle(GpGraphics * graphics,GpPen * pen,REAL x,REAL y,REAL width,REAL height)1123 GdipDrawRectangle (GpGraphics *graphics, GpPen *pen, REAL x, REAL y, REAL width, REAL height)
1124 {
1125 RectF rect = {x, y, width, height};
1126 return GdipDrawRectangles (graphics, pen, &rect, 1);
1127 }
1128
1129 GpStatus WINGDIPAPI
GdipDrawRectangleI(GpGraphics * graphics,GpPen * pen,INT x,INT y,INT width,INT height)1130 GdipDrawRectangleI (GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height)
1131 {
1132 return GdipDrawRectangle (graphics, pen, x, y, width, height);
1133 }
1134
1135 GpStatus WINGDIPAPI
GdipDrawRectangles(GpGraphics * graphics,GpPen * pen,GDIPCONST GpRectF * rects,INT count)1136 GdipDrawRectangles (GpGraphics *graphics, GpPen *pen, GDIPCONST GpRectF *rects, INT count)
1137 {
1138 if (!graphics || !rects || count <= 0)
1139 return InvalidParameter;
1140 if (graphics->state == GraphicsStateBusy)
1141 return ObjectBusy;
1142 if (!pen)
1143 return InvalidParameter;
1144
1145 switch (graphics->backend) {
1146 case GraphicsBackEndCairo:
1147 return cairo_DrawRectangles (graphics, pen, rects, count);
1148 case GraphicsBackEndMetafile:
1149 return metafile_DrawRectangles (graphics, pen, rects, count);
1150 default:
1151 return GenericError;
1152 }
1153 }
1154
1155 GpStatus WINGDIPAPI
GdipDrawRectanglesI(GpGraphics * graphics,GpPen * pen,GDIPCONST GpRect * rects,INT count)1156 GdipDrawRectanglesI (GpGraphics *graphics, GpPen *pen, GDIPCONST GpRect *rects, INT count)
1157 {
1158 GpStatus status;
1159 GpRectF *rectsF;
1160
1161 if (!rects || count < 0)
1162 return InvalidParameter;
1163
1164 rectsF = convert_rects (rects, count);
1165 if (!rectsF)
1166 return OutOfMemory;
1167
1168 status = GdipDrawRectangles (graphics, pen, rectsF, count);
1169
1170 GdipFree (rectsF);
1171 return status;
1172 }
1173
1174 GpStatus WINGDIPAPI
GdipDrawClosedCurve(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count)1175 GdipDrawClosedCurve (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *points, INT count)
1176 {
1177 return GdipDrawClosedCurve2 (graphics, pen, points, count, 0.5f);
1178 }
1179
1180 GpStatus WINGDIPAPI
GdipDrawClosedCurveI(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count)1181 GdipDrawClosedCurveI (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count)
1182 {
1183 return GdipDrawClosedCurve2I (graphics, pen, points, count, 0.5f);
1184 }
1185
1186 GpStatus WINGDIPAPI
GdipDrawClosedCurve2(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count,REAL tension)1187 GdipDrawClosedCurve2 (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *points, INT count, REAL tension)
1188 {
1189 if (!graphics || !points || count <= 0)
1190 return InvalidParameter;
1191 if (graphics->state == GraphicsStateBusy)
1192 return ObjectBusy;
1193 if (!pen || count < 3)
1194 return InvalidParameter;
1195
1196 /* when tension is 0, draw straight lines */
1197 if (tension == 0)
1198 return GdipDrawPolygon (graphics, pen, points, count);
1199
1200 switch (graphics->backend) {
1201 case GraphicsBackEndCairo:
1202 return cairo_DrawClosedCurve2 (graphics, pen, points, count, tension);
1203 case GraphicsBackEndMetafile:
1204 return metafile_DrawClosedCurve2 (graphics, pen, points, count, tension);
1205 default:
1206 return GenericError;
1207 }
1208 }
1209
1210 GpStatus WINGDIPAPI
GdipDrawClosedCurve2I(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count,REAL tension)1211 GdipDrawClosedCurve2I (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count, REAL tension)
1212 {
1213 GpStatus status;
1214 GpPointF *pointsF;
1215
1216 if (count < 0)
1217 return OutOfMemory;
1218 if (!points)
1219 return InvalidParameter;
1220
1221 pointsF = convert_points (points, count);
1222 if (!pointsF)
1223 return OutOfMemory;
1224
1225 status = GdipDrawClosedCurve2 (graphics, pen, pointsF, count, tension);
1226
1227 GdipFree (pointsF);
1228 return status;
1229 }
1230
1231 GpStatus WINGDIPAPI
GdipDrawCurve(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count)1232 GdipDrawCurve (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF *points, INT count)
1233 {
1234 return GdipDrawCurve2 (graphics, pen, points, count, 0.5f);
1235 }
1236
1237 GpStatus WINGDIPAPI
GdipDrawCurveI(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count)1238 GdipDrawCurveI (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count)
1239 {
1240 return GdipDrawCurve2I (graphics, pen, points, count, 0.5f);
1241 }
1242
1243 GpStatus WINGDIPAPI
GdipDrawCurve2(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count,REAL tension)1244 GdipDrawCurve2 (GpGraphics *graphics, GpPen* pen, GDIPCONST GpPointF *points, INT count, REAL tension)
1245 {
1246 if (count == 2)
1247 return GdipDrawLines (graphics, pen, points, count);
1248
1249 return GdipDrawCurve3 (graphics, pen, points, count, 0, count - 1, tension);
1250 }
1251
1252 GpStatus WINGDIPAPI
GdipDrawCurve2I(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count,REAL tension)1253 GdipDrawCurve2I (GpGraphics *graphics, GpPen* pen, GDIPCONST GpPoint *points, INT count, REAL tension)
1254 {
1255 GpStatus status;
1256 GpPointF *pointsF;
1257
1258 if (count < 0)
1259 return OutOfMemory;
1260 if (!points)
1261 return InvalidParameter;
1262
1263 pointsF = convert_points (points, count);
1264 if (!pointsF)
1265 return OutOfMemory;
1266
1267 status = GdipDrawCurve2 (graphics, pen, pointsF, count, tension);
1268
1269 GdipFree (pointsF);
1270 return status;
1271 }
1272
1273 GpStatus WINGDIPAPI
GdipDrawCurve3(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPointF * points,INT count,INT offset,INT numOfSegments,REAL tension)1274 GdipDrawCurve3 (GpGraphics *graphics, GpPen* pen, GDIPCONST GpPointF *points, INT count, INT offset, INT numOfSegments, REAL tension)
1275 {
1276 if (!graphics || !points || count <= 0)
1277 return InvalidParameter;
1278 if (graphics->state == GraphicsStateBusy)
1279 return ObjectBusy;
1280 if (!pen || count < 2 || offset < 0 || offset >= count)
1281 return InvalidParameter;
1282 if (numOfSegments < 1 || numOfSegments >= count - offset)
1283 return InvalidParameter;
1284
1285 /* draw lines if tension = 0 */
1286 if (tension == 0)
1287 return GdipDrawLines (graphics, pen, points, count);
1288
1289 switch (graphics->backend) {
1290 case GraphicsBackEndCairo:
1291 return cairo_DrawCurve3 (graphics, pen, points, count, offset, numOfSegments, tension);
1292 case GraphicsBackEndMetafile:
1293 return metafile_DrawCurve3 (graphics, pen, points, count, offset, numOfSegments, tension);
1294 default:
1295 return GenericError;
1296 }
1297 }
1298
1299 GpStatus WINGDIPAPI
GdipDrawCurve3I(GpGraphics * graphics,GpPen * pen,GDIPCONST GpPoint * points,INT count,INT offset,INT numOfSegments,REAL tension)1300 GdipDrawCurve3I (GpGraphics *graphics, GpPen* pen, GDIPCONST GpPoint *points, INT count, INT offset, INT numOfSegments, REAL tension)
1301 {
1302 GpStatus status;
1303 GpPointF *pointsF;
1304
1305 if (count < 0)
1306 return OutOfMemory;
1307 if (!points)
1308 return InvalidParameter;
1309
1310 pointsF = convert_points (points, count);
1311 if (!pointsF)
1312 return OutOfMemory;
1313
1314 status = GdipDrawCurve3 (graphics, pen, pointsF, count, offset, numOfSegments, tension);
1315
1316 GdipFree (pointsF);
1317 return status;
1318 }
1319
1320 /*
1321 * Fills
1322 */
1323 GpStatus WINGDIPAPI
GdipFillEllipse(GpGraphics * graphics,GpBrush * brush,REAL x,REAL y,REAL width,REAL height)1324 GdipFillEllipse (GpGraphics *graphics, GpBrush *brush, REAL x, REAL y, REAL width, REAL height)
1325 {
1326 if (!graphics)
1327 return InvalidParameter;
1328 if (graphics->state == GraphicsStateBusy)
1329 return ObjectBusy;
1330 if (!brush)
1331 return InvalidParameter;
1332
1333 switch (graphics->backend) {
1334 case GraphicsBackEndCairo:
1335 return cairo_FillEllipse (graphics, brush, x, y, width, height);
1336 case GraphicsBackEndMetafile:
1337 return metafile_FillEllipse (graphics, brush, x, y, width, height);
1338 default:
1339 return GenericError;
1340 }
1341 }
1342
1343 GpStatus WINGDIPAPI
GdipFillEllipseI(GpGraphics * graphics,GpBrush * brush,INT x,INT y,INT width,INT height)1344 GdipFillEllipseI (GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height)
1345 {
1346 return GdipFillEllipse (graphics, brush, x, y, width, height);
1347 }
1348
1349 GpStatus WINGDIPAPI
GdipFillRectangle(GpGraphics * graphics,GpBrush * brush,REAL x,REAL y,REAL width,REAL height)1350 GdipFillRectangle (GpGraphics *graphics, GpBrush *brush, REAL x, REAL y, REAL width, REAL height)
1351 {
1352 RectF rect = {x, y, width, height};
1353 return GdipFillRectangles (graphics, brush, &rect, 1);
1354 }
1355
1356 GpStatus WINGDIPAPI
GdipFillRectangleI(GpGraphics * graphics,GpBrush * brush,INT x,INT y,INT width,INT height)1357 GdipFillRectangleI (GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height)
1358 {
1359 return GdipFillRectangle (graphics, brush, x, y, width, height);
1360 }
1361
1362 GpStatus WINGDIPAPI
GdipFillRectangles(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpRectF * rects,INT count)1363 GdipFillRectangles (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects, INT count)
1364 {
1365 if (!graphics || !rects || count <= 0)
1366 return InvalidParameter;
1367 if (graphics->state == GraphicsStateBusy)
1368 return ObjectBusy;
1369 if (!brush)
1370 return InvalidParameter;
1371
1372 switch (graphics->backend) {
1373 case GraphicsBackEndCairo:
1374 return cairo_FillRectangles (graphics, brush, rects, count);
1375 case GraphicsBackEndMetafile:
1376 return metafile_FillRectangles (graphics, brush, rects, count);
1377 default:
1378 return GenericError;
1379 }
1380 }
1381
1382 GpStatus WINGDIPAPI
GdipFillRectanglesI(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpRect * rects,INT count)1383 GdipFillRectanglesI (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRect *rects, INT count)
1384 {
1385 GpStatus status;
1386 GpRectF *rectsF;
1387
1388 if (count < 0)
1389 return OutOfMemory;
1390 if (!rects)
1391 return InvalidParameter;
1392
1393 rectsF = convert_rects (rects, count);
1394 if (!rectsF)
1395 return OutOfMemory;
1396
1397 status = GdipFillRectangles (graphics, brush, rectsF, count);
1398
1399 GdipFree (rectsF);
1400 return status;
1401 }
1402
1403 GpStatus WINGDIPAPI
GdipFillPie(GpGraphics * graphics,GpBrush * brush,REAL x,REAL y,REAL width,REAL height,REAL startAngle,REAL sweepAngle)1404 GdipFillPie (GpGraphics *graphics, GpBrush *brush, REAL x, REAL y, REAL width, REAL height,
1405 REAL startAngle, REAL sweepAngle)
1406 {
1407 if (!graphics)
1408 return InvalidParameter;
1409 if (graphics->state == GraphicsStateBusy)
1410 return ObjectBusy;
1411 if (!brush || width <= 0 || height <= 0)
1412 return InvalidParameter;
1413
1414 // Don't do anything if sweep angle is zero.
1415 if (sweepAngle == 0)
1416 return Ok;
1417
1418 switch (graphics->backend) {
1419 case GraphicsBackEndCairo:
1420 return cairo_FillPie (graphics, brush, x, y, width, height, startAngle, sweepAngle);
1421 case GraphicsBackEndMetafile:
1422 return metafile_FillPie (graphics, brush, x, y, width, height, startAngle, sweepAngle);
1423 default:
1424 return GenericError;
1425 }
1426 }
1427
1428 GpStatus WINGDIPAPI
GdipFillPieI(GpGraphics * graphics,GpBrush * brush,INT x,INT y,INT width,INT height,REAL startAngle,REAL sweepAngle)1429 GdipFillPieI (GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
1430 {
1431 return GdipFillPie (graphics, brush, x, y, width, height, startAngle, sweepAngle);
1432 }
1433
1434 GpStatus WINGDIPAPI
GdipFillPath(GpGraphics * graphics,GpBrush * brush,GpPath * path)1435 GdipFillPath (GpGraphics *graphics, GpBrush *brush, GpPath *path)
1436 {
1437 if (!graphics)
1438 return InvalidParameter;
1439 if (graphics->state == GraphicsStateBusy)
1440 return ObjectBusy;
1441 if (!brush || !path)
1442 return InvalidParameter;
1443
1444 switch (graphics->backend) {
1445 case GraphicsBackEndCairo:
1446 return cairo_FillPath (graphics, brush, path);
1447 case GraphicsBackEndMetafile:
1448 return metafile_FillPath (graphics, brush, path);
1449 default:
1450 return GenericError;
1451 }
1452 }
1453
1454 GpStatus WINGDIPAPI
GdipFillPolygon(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPointF * points,INT count,GpFillMode fillMode)1455 GdipFillPolygon (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPointF *points, INT count, GpFillMode fillMode)
1456 {
1457 if (!graphics || !points || count <= 0)
1458 return InvalidParameter;
1459 if (graphics->state == GraphicsStateBusy)
1460 return ObjectBusy;
1461 if (!brush || fillMode > FillModeWinding)
1462 return InvalidParameter;
1463
1464 // Don't do anything if sweep angle is zero.
1465 if (count < 2)
1466 return Ok;
1467
1468 switch (graphics->backend) {
1469 case GraphicsBackEndCairo:
1470 return cairo_FillPolygon (graphics, brush, points, count, fillMode);
1471 case GraphicsBackEndMetafile:
1472 return metafile_FillPolygon (graphics, brush, points, count, fillMode);
1473 default:
1474 return GenericError;
1475 }
1476 }
1477
1478 GpStatus WINGDIPAPI
GdipFillPolygonI(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPoint * points,INT count,GpFillMode fillMode)1479 GdipFillPolygonI (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPoint *points, INT count, GpFillMode fillMode)
1480 {
1481 GpStatus status;
1482 GpPointF *pointsF;
1483
1484 if (count < 0)
1485 return OutOfMemory;
1486 if (!points)
1487 return InvalidParameter;
1488
1489 pointsF = convert_points (points, count);
1490 if (!pointsF)
1491 return OutOfMemory;
1492
1493 status = GdipFillPolygon (graphics, brush, pointsF, count, fillMode);
1494
1495 GdipFree (pointsF);
1496 return status;
1497 }
1498
1499 GpStatus WINGDIPAPI
GdipFillPolygon2(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPointF * points,INT count)1500 GdipFillPolygon2 (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPointF *points, INT count)
1501 {
1502 return GdipFillPolygon (graphics, brush, points, count, FillModeAlternate);
1503 }
1504
1505 GpStatus WINGDIPAPI
GdipFillPolygon2I(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPoint * points,INT count)1506 GdipFillPolygon2I (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPoint *points, INT count)
1507 {
1508 return GdipFillPolygonI (graphics, brush, points, count, FillModeAlternate);
1509 }
1510
1511 GpStatus WINGDIPAPI
GdipFillClosedCurve(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPointF * points,INT count)1512 GdipFillClosedCurve (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPointF *points, INT count)
1513 {
1514 return GdipFillClosedCurve2 (graphics, brush, points, count, 0.5f, FillModeAlternate);
1515 }
1516
1517 GpStatus WINGDIPAPI
GdipFillClosedCurveI(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPoint * points,INT count)1518 GdipFillClosedCurveI (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPoint *points, INT count)
1519 {
1520 return GdipFillClosedCurve2I (graphics, brush, points, count, 0.5f, FillModeAlternate);
1521 }
1522
1523 GpStatus WINGDIPAPI
GdipFillClosedCurve2(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPointF * points,INT count,REAL tension,GpFillMode fillMode)1524 GdipFillClosedCurve2 (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPointF *points, INT count, REAL tension, GpFillMode fillMode)
1525 {
1526 if (!graphics || !points || count <= 0)
1527 return InvalidParameter;
1528 if (graphics->state == GraphicsStateBusy)
1529 return ObjectBusy;
1530 if (!brush || fillMode > FillModeWinding)
1531 return InvalidParameter;
1532
1533 // Nop if the count is too small.
1534 if (count < 3)
1535 return Ok;
1536
1537 /* when tension is 0, the edges are straight lines */
1538 if (tension == 0)
1539 return GdipFillPolygon2 (graphics, brush, points, count);
1540
1541 if (!graphics || !brush || !points)
1542 return InvalidParameter;
1543
1544 switch (graphics->backend) {
1545 case GraphicsBackEndCairo:
1546 return cairo_FillClosedCurve2 (graphics, brush, points, count, tension, fillMode);
1547 case GraphicsBackEndMetafile:
1548 return metafile_FillClosedCurve2 (graphics, brush, points, count, tension, fillMode);
1549 default:
1550 return GenericError;
1551 }
1552 }
1553
1554 GpStatus WINGDIPAPI
GdipFillClosedCurve2I(GpGraphics * graphics,GpBrush * brush,GDIPCONST GpPoint * points,INT count,REAL tension,GpFillMode fillMode)1555 GdipFillClosedCurve2I (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPoint *points, INT count, REAL tension, GpFillMode fillMode)
1556 {
1557 GpStatus status;
1558 GpPointF *pointsF;
1559
1560 if (count < 0)
1561 return OutOfMemory;
1562 if (!points)
1563 return InvalidParameter;
1564
1565 pointsF = convert_points (points, count);
1566 if (!pointsF)
1567 return OutOfMemory;
1568
1569 status = GdipFillClosedCurve2 (graphics, brush, pointsF, count, tension, fillMode);
1570
1571 GdipFree (pointsF);
1572 return status;
1573 }
1574
1575 GpStatus WINGDIPAPI
GdipFillRegion(GpGraphics * graphics,GpBrush * brush,GpRegion * region)1576 GdipFillRegion (GpGraphics *graphics, GpBrush *brush, GpRegion *region)
1577 {
1578 if (!graphics || !brush || !region)
1579 return InvalidParameter;
1580
1581 switch (graphics->backend) {
1582 case GraphicsBackEndCairo:
1583 return cairo_FillRegion (graphics, brush, region);
1584 case GraphicsBackEndMetafile:
1585 return metafile_FillRegion (graphics, brush, region);
1586 default:
1587 return GenericError;
1588 }
1589 }
1590
1591 GpStatus WINGDIPAPI
GdipSetRenderingOrigin(GpGraphics * graphics,INT x,INT y)1592 GdipSetRenderingOrigin (GpGraphics *graphics, INT x, INT y)
1593 {
1594 if (!graphics)
1595 return InvalidParameter;
1596
1597 if (graphics->state == GraphicsStateBusy)
1598 return ObjectBusy;
1599
1600 graphics->render_origin_x = x;
1601 graphics->render_origin_y = y;
1602
1603 switch (graphics->backend) {
1604 case GraphicsBackEndCairo:
1605 return Ok;
1606 case GraphicsBackEndMetafile:
1607 return metafile_SetRenderingOrigin (graphics, x, y);
1608 default:
1609 return GenericError;
1610 }
1611 }
1612
1613 GpStatus WINGDIPAPI
GdipGetRenderingOrigin(GpGraphics * graphics,INT * x,INT * y)1614 GdipGetRenderingOrigin (GpGraphics *graphics, INT *x, INT *y)
1615 {
1616 if (!graphics || !x || !y)
1617 return InvalidParameter;
1618
1619 if (graphics->state == GraphicsStateBusy)
1620 return ObjectBusy;
1621
1622 *x = graphics->render_origin_x;
1623 *y = graphics->render_origin_y;
1624
1625 return Ok;
1626 }
1627
1628 GpStatus WINGDIPAPI
GdipGetDpiX(GpGraphics * graphics,REAL * dpi)1629 GdipGetDpiX (GpGraphics *graphics, REAL *dpi)
1630 {
1631 if (!graphics || !dpi)
1632 return InvalidParameter;
1633
1634 if (graphics->state == GraphicsStateBusy)
1635 return ObjectBusy;
1636
1637 *dpi = graphics->dpi_x;
1638 return Ok;
1639 }
1640
1641 GpStatus WINGDIPAPI
GdipGetDpiY(GpGraphics * graphics,REAL * dpi)1642 GdipGetDpiY (GpGraphics *graphics, REAL *dpi)
1643 {
1644 if (!graphics || !dpi)
1645 return InvalidParameter;
1646
1647 if (graphics->state == GraphicsStateBusy)
1648 return ObjectBusy;
1649
1650 *dpi = graphics->dpi_y;
1651 return Ok;
1652 }
1653
1654 GpStatus WINGDIPAPI
GdipGraphicsClear(GpGraphics * graphics,ARGB color)1655 GdipGraphicsClear (GpGraphics *graphics, ARGB color)
1656 {
1657 if (!graphics)
1658 return InvalidParameter;
1659
1660 switch (graphics->backend) {
1661 case GraphicsBackEndCairo:
1662 return cairo_GraphicsClear (graphics, color);
1663 case GraphicsBackEndMetafile:
1664 return metafile_GraphicsClear (graphics, color);
1665 default:
1666 return GenericError;
1667 }
1668 }
1669
1670 GpStatus WINGDIPAPI
GdipSetInterpolationMode(GpGraphics * graphics,InterpolationMode interpolationMode)1671 GdipSetInterpolationMode (GpGraphics *graphics, InterpolationMode interpolationMode)
1672 {
1673 if (!graphics)
1674 return InvalidParameter;
1675 if (graphics->state == GraphicsStateBusy)
1676 return ObjectBusy;
1677 if (interpolationMode <= InterpolationModeInvalid || interpolationMode > InterpolationModeHighQualityBicubic)
1678 return InvalidParameter;
1679
1680 switch (interpolationMode) {
1681 case InterpolationModeDefault:
1682 case InterpolationModeLowQuality:
1683 graphics->interpolation = InterpolationModeBilinear;
1684 break;
1685 case InterpolationModeHighQuality:
1686 graphics->interpolation = InterpolationModeHighQualityBicubic;
1687 break;
1688 default:
1689 graphics->interpolation = interpolationMode;
1690 break;
1691 }
1692
1693 switch (graphics->backend) {
1694 case GraphicsBackEndCairo:
1695 return Ok;
1696 case GraphicsBackEndMetafile:
1697 return metafile_SetInterpolationMode (graphics, interpolationMode);
1698 default:
1699 return GenericError;
1700 }
1701 }
1702
1703 GpStatus WINGDIPAPI
GdipGetInterpolationMode(GpGraphics * graphics,InterpolationMode * interpolationMode)1704 GdipGetInterpolationMode (GpGraphics *graphics, InterpolationMode *interpolationMode)
1705 {
1706 if (!graphics)
1707 return InvalidParameter;
1708 if (graphics->state == GraphicsStateBusy)
1709 return ObjectBusy;
1710 if (!interpolationMode)
1711 return InvalidParameter;
1712
1713 *interpolationMode = graphics->interpolation;
1714 return Ok;
1715 }
1716
1717 GpStatus WINGDIPAPI
GdipSetTextRenderingHint(GpGraphics * graphics,TextRenderingHint mode)1718 GdipSetTextRenderingHint (GpGraphics *graphics, TextRenderingHint mode)
1719 {
1720 if (!graphics)
1721 return InvalidParameter;
1722 if (graphics->state == GraphicsStateBusy)
1723 return ObjectBusy;
1724 if (mode > TextRenderingHintClearTypeGridFit)
1725 return InvalidParameter;
1726
1727 graphics->text_mode = mode;
1728
1729 switch (graphics->backend) {
1730 case GraphicsBackEndCairo:
1731 return Ok;
1732 case GraphicsBackEndMetafile:
1733 return metafile_SetTextRenderingHint (graphics, mode);
1734 default:
1735 return GenericError;
1736 }
1737 }
1738
1739 GpStatus WINGDIPAPI
GdipGetTextRenderingHint(GpGraphics * graphics,TextRenderingHint * mode)1740 GdipGetTextRenderingHint (GpGraphics *graphics, TextRenderingHint *mode)
1741 {
1742 if (!graphics || !mode)
1743 return InvalidParameter;
1744
1745 if (graphics->state == GraphicsStateBusy)
1746 return ObjectBusy;
1747
1748 *mode = graphics->text_mode;
1749 return Ok;
1750 }
1751
1752 /* MonoTODO - pixel offset mode isn't supported */
1753 GpStatus WINGDIPAPI
GdipSetPixelOffsetMode(GpGraphics * graphics,PixelOffsetMode pixelOffsetMode)1754 GdipSetPixelOffsetMode (GpGraphics *graphics, PixelOffsetMode pixelOffsetMode)
1755 {
1756 if (!graphics)
1757 return InvalidParameter;
1758 if (graphics->state == GraphicsStateBusy)
1759 return ObjectBusy;
1760 if (pixelOffsetMode <= PixelOffsetModeInvalid || pixelOffsetMode > PixelOffsetModeHalf)
1761 return InvalidParameter;
1762
1763 graphics->pixel_mode = pixelOffsetMode;
1764
1765 switch (graphics->backend) {
1766 case GraphicsBackEndCairo:
1767 /* FIXME: changing pixel mode affects other properties (e.g. the visible clip bounds) */
1768 return Ok;
1769 case GraphicsBackEndMetafile:
1770 return metafile_SetPixelOffsetMode (graphics, pixelOffsetMode);
1771 default:
1772 return GenericError;
1773 }
1774 }
1775
1776 /* MonoTODO - pixel offset mode isn't supported */
1777 GpStatus WINGDIPAPI
GdipGetPixelOffsetMode(GpGraphics * graphics,PixelOffsetMode * pixelOffsetMode)1778 GdipGetPixelOffsetMode (GpGraphics *graphics, PixelOffsetMode *pixelOffsetMode)
1779 {
1780 if (!graphics || !pixelOffsetMode)
1781 return InvalidParameter;
1782
1783 if (graphics->state == GraphicsStateBusy)
1784 return ObjectBusy;
1785
1786 *pixelOffsetMode = graphics->pixel_mode;
1787 return Ok;
1788 }
1789
1790 /* MonoTODO - text contrast isn't supported */
1791 GpStatus WINGDIPAPI
GdipSetTextContrast(GpGraphics * graphics,UINT contrast)1792 GdipSetTextContrast (GpGraphics *graphics, UINT contrast)
1793 {
1794 // The gamma correction value must be less than 12.
1795 // The default value is 4.
1796 if (!graphics)
1797 return InvalidParameter;
1798 if (graphics->state == GraphicsStateBusy)
1799 return ObjectBusy;
1800 if (contrast > 12)
1801 return InvalidParameter;
1802
1803 graphics->text_contrast = contrast;
1804
1805 switch (graphics->backend) {
1806 case GraphicsBackEndCairo:
1807 return Ok;
1808 case GraphicsBackEndMetafile:
1809 return metafile_SetTextContrast (graphics, contrast);
1810 default:
1811 return GenericError;
1812 }
1813 }
1814
1815 /* MonoTODO - text contrast isn't supported */
1816 GpStatus WINGDIPAPI
GdipGetTextContrast(GpGraphics * graphics,UINT * contrast)1817 GdipGetTextContrast (GpGraphics *graphics, UINT *contrast)
1818 {
1819 if (!graphics || !contrast)
1820 return InvalidParameter;
1821
1822 if (graphics->state == GraphicsStateBusy)
1823 return ObjectBusy;
1824
1825 *contrast = graphics->text_contrast;
1826 return Ok;
1827 }
1828
1829 GpStatus WINGDIPAPI
GdipSetSmoothingMode(GpGraphics * graphics,SmoothingMode smoothingMode)1830 GdipSetSmoothingMode (GpGraphics *graphics, SmoothingMode smoothingMode)
1831 {
1832 if (!graphics)
1833 return InvalidParameter;
1834 if (graphics->state == GraphicsStateBusy)
1835 return ObjectBusy;
1836 if (smoothingMode <= SmoothingModeInvalid || smoothingMode > SmoothingModeAntiAlias + 1)
1837 return InvalidParameter;
1838
1839 switch (smoothingMode) {
1840 case SmoothingModeDefault:
1841 case SmoothingModeHighSpeed:
1842 graphics->draw_mode = SmoothingModeNone;
1843 break;
1844 case SmoothingModeHighQuality:
1845 graphics->draw_mode = SmoothingModeAntiAlias;
1846 break;
1847 default:
1848 graphics->draw_mode = smoothingMode;
1849 break;
1850 }
1851
1852 switch (graphics->backend) {
1853 case GraphicsBackEndCairo:
1854 return cairo_SetSmoothingMode (graphics, smoothingMode);
1855 case GraphicsBackEndMetafile:
1856 return metafile_SetSmoothingMode (graphics, smoothingMode);
1857 default:
1858 return GenericError;
1859 }
1860 }
1861
1862 GpStatus WINGDIPAPI
GdipGetSmoothingMode(GpGraphics * graphics,SmoothingMode * smoothingMode)1863 GdipGetSmoothingMode (GpGraphics *graphics, SmoothingMode *smoothingMode)
1864 {
1865 if (!graphics || !smoothingMode)
1866 return InvalidParameter;
1867
1868 if (graphics->state == GraphicsStateBusy)
1869 return ObjectBusy;
1870
1871 *smoothingMode = graphics->draw_mode;
1872 return Ok;
1873 }
1874
1875 /* MonoTODO - dstrect, srcrect and unit support isn't implemented */
1876 GpStatus WINGDIPAPI
GdipBeginContainer(GpGraphics * graphics,GDIPCONST GpRectF * dstrect,GDIPCONST GpRectF * srcrect,GpUnit unit,GraphicsContainer * state)1877 GdipBeginContainer (GpGraphics *graphics, GDIPCONST GpRectF* dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state)
1878 {
1879 if (!graphics || !dstrect || !srcrect || (unit < UnitPixel) || (unit > UnitMillimeter))
1880 return InvalidParameter;
1881
1882 return GdipBeginContainer2 (graphics, state);
1883 }
1884
1885 GpStatus WINGDIPAPI
GdipBeginContainer2(GpGraphics * graphics,GraphicsContainer * state)1886 GdipBeginContainer2 (GpGraphics *graphics, GraphicsContainer* state)
1887 {
1888 GpStatus status;
1889
1890 if (!graphics || !state)
1891 return InvalidParameter;
1892
1893 status = GdipSaveGraphics (graphics, state);
1894 if (status == Ok) {
1895 /* reset most properties to defaults after saving them */
1896 gdip_graphics_reset (graphics);
1897 /* copy the current effective matrix as the preivous matrix */
1898 gdip_cairo_matrix_copy (&graphics->previous_matrix, graphics->copy_of_ctm);
1899 }
1900 return status;
1901 }
1902
1903 GpStatus WINGDIPAPI
GdipBeginContainerI(GpGraphics * graphics,GDIPCONST GpRect * dstrect,GDIPCONST GpRect * srcrect,GpUnit unit,GraphicsContainer * state)1904 GdipBeginContainerI (GpGraphics *graphics, GDIPCONST GpRect* dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state)
1905 {
1906 GpRectF dstrectF;
1907 GpRectF srcrectF;
1908
1909 if (!dstrect || !srcrect)
1910 return InvalidParameter;
1911
1912 gdip_RectF_from_Rect (dstrect, &dstrectF);
1913 gdip_RectF_from_Rect (srcrect, &srcrectF);
1914 return GdipBeginContainer (graphics, &dstrectF, &srcrectF, unit, state);
1915 }
1916
1917 GpStatus WINGDIPAPI
GdipEndContainer(GpGraphics * graphics,GraphicsContainer state)1918 GdipEndContainer (GpGraphics *graphics, GraphicsContainer state)
1919 {
1920 if (!graphics)
1921 return InvalidParameter;
1922
1923 return GdipRestoreGraphics (graphics, state);
1924 }
1925
1926 GpStatus WINGDIPAPI
GdipFlush(GpGraphics * graphics,GpFlushIntention intention)1927 GdipFlush (GpGraphics *graphics, GpFlushIntention intention)
1928 {
1929 cairo_surface_t* surface;
1930
1931 if (!graphics)
1932 return InvalidParameter;
1933
1934 if (graphics->state != GraphicsStateValid)
1935 return ObjectBusy;
1936
1937 surface = cairo_get_target (graphics->ct);
1938 cairo_surface_flush (surface);
1939
1940 #ifdef CAIRO_HAS_QUARTZ_SURFACE
1941 if (graphics->type == gtOSXDrawable) {
1942 CGRect rect;
1943
1944 rect.origin.x = 0;
1945 rect.origin.y = 0;
1946 rect.size.width = graphics->orig_bounds.Width;
1947 rect.size.height = graphics->orig_bounds.Height;
1948 void *image = CGBitmapContextCreateImage (cairo_quartz_surface_get_cg_context (surface));
1949 CGContextDrawImage (graphics->cg_context, rect, image);
1950 CGImageRelease (image);
1951 }
1952 #endif
1953 return Ok;
1954 }
1955
1956 GpStatus WINGDIPAPI
GdipSetClipGraphics(GpGraphics * graphics,GpGraphics * srcgraphics,CombineMode combineMode)1957 GdipSetClipGraphics (GpGraphics *graphics, GpGraphics *srcgraphics, CombineMode combineMode)
1958 {
1959 if (!graphics)
1960 return InvalidParameter;
1961 if (graphics->state == GraphicsStateBusy)
1962 return ObjectBusy;
1963 if (!srcgraphics)
1964 return InvalidParameter;
1965 if (srcgraphics->state == GraphicsStateBusy)
1966 return ObjectBusy;
1967
1968 return GdipSetClipRegion (graphics, srcgraphics->clip, combineMode);
1969 }
1970
1971 GpStatus WINGDIPAPI
GdipSetClipRect(GpGraphics * graphics,REAL x,REAL y,REAL width,REAL height,CombineMode combineMode)1972 GdipSetClipRect (GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, CombineMode combineMode)
1973 {
1974 GpStatus status;
1975 GpRectF rect;
1976 GpRegion *region = NULL;
1977
1978 if (!graphics)
1979 return InvalidParameter;
1980 if (graphics->state == GraphicsStateBusy)
1981 return ObjectBusy;
1982 if (combineMode > CombineModeComplement)
1983 return InvalidParameter;
1984
1985 rect.X = x;
1986 rect.Y = y;
1987 rect.Width = width;
1988 rect.Height = height;
1989 gdip_normalize_rectangle (&rect, &rect);
1990
1991 // Match GDI+ behaviour by setting empty rects to an empty region.
1992 if (gdip_is_rectF_empty (&rect, /* allowNegative */ FALSE)) {
1993 status = GdipCreateRegion (®ion);
1994 if (status != Ok)
1995 return status;
1996
1997 GdipSetEmpty (region);
1998 }
1999 else {
2000 status = GdipCreateRegionRect (&rect, ®ion);
2001 if (status != Ok)
2002 return status;
2003 }
2004
2005 return GdipSetClipRegion (graphics, region, combineMode);
2006 }
2007
2008 GpStatus WINGDIPAPI
GdipSetClipRectI(GpGraphics * graphics,INT x,INT y,INT width,INT height,CombineMode combineMode)2009 GdipSetClipRectI (GpGraphics *graphics, INT x, INT y, INT width, INT height, CombineMode combineMode)
2010 {
2011 return GdipSetClipRect (graphics, x, y, width, height, combineMode);
2012 }
2013
2014 GpStatus WINGDIPAPI
GdipSetClipPath(GpGraphics * graphics,GpPath * path,CombineMode combineMode)2015 GdipSetClipPath (GpGraphics *graphics, GpPath *path, CombineMode combineMode)
2016 {
2017 GpStatus status;
2018 GpPath *work;
2019
2020 if (!graphics)
2021 return InvalidParameter;
2022 if (graphics->state == GraphicsStateBusy)
2023 return ObjectBusy;
2024 if (!path || combineMode > CombineModeComplement)
2025 return InvalidParameter;
2026
2027 /* if the matrix is empty, avoid path cloning and transform */
2028 if (gdip_is_matrix_empty (graphics->clip_matrix)) {
2029 work = path;
2030 } else {
2031 cairo_matrix_t inverted;
2032
2033 gdip_cairo_matrix_copy (&inverted, graphics->clip_matrix);
2034 cairo_matrix_invert (&inverted);
2035
2036 status = GdipClonePath (path, &work);
2037 if (status != Ok)
2038 return status;
2039 GdipTransformPath (work, &inverted);
2040 }
2041
2042 status = GdipCombineRegionPath (graphics->clip, work, combineMode);
2043 if (status != Ok)
2044 goto cleanup;
2045
2046 switch (graphics->backend) {
2047 case GraphicsBackEndCairo:
2048 /* adjust cairo clipping according to graphics->clip */
2049 status = cairo_SetGraphicsClip (graphics);
2050 break;
2051 case GraphicsBackEndMetafile:
2052 status = metafile_SetClipPath (graphics, path, combineMode);
2053 break;
2054 default:
2055 status = GenericError;
2056 break;
2057 }
2058
2059 cleanup:
2060 if (work != path)
2061 GdipDeletePath (work);
2062 return status;
2063 }
2064
2065 GpStatus WINGDIPAPI
GdipSetClipRegion(GpGraphics * graphics,GpRegion * region,CombineMode combineMode)2066 GdipSetClipRegion (GpGraphics *graphics, GpRegion *region, CombineMode combineMode)
2067 {
2068 GpStatus status;
2069 GpRegion *work;
2070
2071 if (!graphics)
2072 return InvalidParameter;
2073 if (graphics->state == GraphicsStateBusy)
2074 return ObjectBusy;
2075 if (!region || combineMode > CombineModeComplement)
2076 return InvalidParameter;
2077
2078 /* if the matrix is empty, avoid region cloning and transform */
2079 if (gdip_is_matrix_empty (graphics->clip_matrix)) {
2080 work = region;
2081 } else {
2082 cairo_matrix_t inverted;
2083
2084 gdip_cairo_matrix_copy (&inverted, graphics->clip_matrix);
2085 cairo_matrix_invert (&inverted);
2086
2087 GdipCloneRegion (region, &work);
2088 GdipTransformRegion (work, &inverted);
2089 }
2090
2091 status = GdipCombineRegionRegion (graphics->clip, work, combineMode);
2092 if (status != Ok)
2093 goto cleanup;
2094
2095 switch (graphics->backend) {
2096 case GraphicsBackEndCairo:
2097 /* adjust cairo clipping according to graphics->clip */
2098 status = cairo_SetGraphicsClip (graphics);
2099 break;
2100 case GraphicsBackEndMetafile:
2101 status = metafile_SetClipRegion (graphics, region, combineMode);
2102 break;
2103 default:
2104 status = GenericError;
2105 break;
2106 }
2107
2108 cleanup:
2109 if (work != region)
2110 GdipDeleteRegion (work);
2111 return status;
2112 }
2113
2114 /* Note: not exposed in System.Drawing.dll */
2115 GpStatus WINGDIPAPI
GdipSetClipHrgn(GpGraphics * graphics,void * hRgn,CombineMode combineMode)2116 GdipSetClipHrgn (GpGraphics *graphics, void *hRgn, CombineMode combineMode)
2117 {
2118 if (!graphics)
2119 return InvalidParameter;
2120 if (graphics->state == GraphicsStateBusy)
2121 return ObjectBusy;
2122 if (!hRgn)
2123 return InvalidParameter;
2124
2125 return GdipSetClipRegion (graphics, (GpRegion*)hRgn, combineMode);
2126 }
2127
2128 GpStatus WINGDIPAPI
GdipResetClip(GpGraphics * graphics)2129 GdipResetClip (GpGraphics *graphics)
2130 {
2131 if (!graphics)
2132 return InvalidParameter;
2133
2134 if (graphics->state == GraphicsStateBusy)
2135 return ObjectBusy;
2136
2137 GdipSetInfinite (graphics->clip);
2138 cairo_matrix_init_identity (graphics->clip_matrix);
2139
2140 switch (graphics->backend) {
2141 case GraphicsBackEndCairo:
2142 return cairo_ResetClip (graphics);
2143 case GraphicsBackEndMetafile:
2144 return metafile_ResetClip (graphics);
2145 default:
2146 return GenericError;
2147 }
2148 }
2149
2150 GpStatus WINGDIPAPI
GdipTranslateClip(GpGraphics * graphics,REAL dx,REAL dy)2151 GdipTranslateClip (GpGraphics *graphics, REAL dx, REAL dy)
2152 {
2153 GpStatus status;
2154
2155 if (!graphics)
2156 return InvalidParameter;
2157
2158 if (graphics->state == GraphicsStateBusy)
2159 return ObjectBusy;
2160
2161 status = GdipTranslateRegion (graphics->clip, dx, dy);
2162 if (status != Ok)
2163 return status;
2164
2165 switch (graphics->backend) {
2166 case GraphicsBackEndCairo:
2167 /* adjust cairo clipping according to graphics->clip */
2168 return cairo_SetGraphicsClip (graphics);
2169 case GraphicsBackEndMetafile:
2170 return metafile_TranslateClip (graphics, dx, dy);
2171 default:
2172 return GenericError;
2173 }
2174 }
2175
2176 GpStatus WINGDIPAPI
GdipTranslateClipI(GpGraphics * graphics,INT dx,INT dy)2177 GdipTranslateClipI (GpGraphics *graphics, INT dx, INT dy)
2178 {
2179 return GdipTranslateClip (graphics, dx, dy);
2180 }
2181
2182 GpStatus WINGDIPAPI
GdipGetClip(GpGraphics * graphics,GpRegion * region)2183 GdipGetClip (GpGraphics *graphics, GpRegion *region)
2184 {
2185 if (!graphics || !region)
2186 return InvalidParameter;
2187
2188 if (graphics->state == GraphicsStateBusy)
2189 return ObjectBusy;
2190
2191 gdip_clear_region (region);
2192 gdip_copy_region (graphics->clip, region);
2193
2194 if (gdip_is_matrix_empty (graphics->clip_matrix))
2195 return Ok;
2196 return GdipTransformRegion (region, graphics->clip_matrix);
2197 }
2198
2199 GpStatus WINGDIPAPI
GdipGetClipBounds(GpGraphics * graphics,GpRectF * rect)2200 GdipGetClipBounds (GpGraphics *graphics, GpRectF *rect)
2201 {
2202 GpStatus status;
2203 BOOL empty;
2204 GpRegion *work;
2205
2206 if (!graphics || !rect)
2207 return InvalidParameter;
2208 if (graphics->state == GraphicsStateBusy)
2209 return ObjectBusy;
2210
2211 // The clip bounds for empty bounds should be translated.
2212 GdipIsEmptyRegion (graphics->clip, graphics, &empty);
2213 if (empty) {
2214 status = GdipGetRegionBounds (graphics->clip, graphics, rect);
2215 if (status != Ok)
2216 return status;
2217
2218 rect->X += graphics->clip_matrix->x0;
2219 rect->Y += graphics->clip_matrix->y0;
2220
2221 return Ok;
2222 }
2223
2224 /* if the matrix is empty, avoid region cloning and transform */
2225 if (gdip_is_matrix_empty (graphics->clip_matrix)) {
2226 work = graphics->clip;
2227 } else {
2228 GdipCloneRegion (graphics->clip, &work);
2229 GdipTransformRegion (work, graphics->clip_matrix);
2230 }
2231
2232 status = GdipGetRegionBounds (work, graphics, rect);
2233
2234 if (work != graphics->clip)
2235 GdipDeleteRegion (work);
2236
2237 return status;
2238 }
2239
2240 GpStatus WINGDIPAPI
GdipGetClipBoundsI(GpGraphics * graphics,GpRect * rect)2241 GdipGetClipBoundsI (GpGraphics *graphics, GpRect *rect)
2242 {
2243 GpRectF rectF;
2244 GpStatus status;
2245
2246 if (!rect)
2247 return InvalidParameter;
2248
2249 status = GdipGetClipBounds (graphics, &rectF);
2250 if (status != Ok)
2251 return status;
2252
2253 gdip_Rect_from_RectF (&rectF, rect);
2254 return Ok;
2255 }
2256
2257 GpStatus WINGDIPAPI
GdipIsClipEmpty(GpGraphics * graphics,BOOL * result)2258 GdipIsClipEmpty (GpGraphics *graphics, BOOL *result)
2259 {
2260 if (!graphics || !result)
2261 return InvalidParameter;
2262
2263 if (graphics->state == GraphicsStateBusy)
2264 return ObjectBusy;
2265
2266 return GdipIsEmptyRegion (graphics->clip, graphics, result);
2267 }
2268
2269 GpStatus WINGDIPAPI
GdipSetVisibleClip_linux(GpGraphics * graphics,GpRect * rect)2270 GdipSetVisibleClip_linux (GpGraphics *graphics, GpRect *rect)
2271 {
2272 if (!graphics || !rect)
2273 return InvalidParameter;
2274
2275 graphics->orig_bounds.X = rect->X;
2276 graphics->orig_bounds.Y = rect->Y;
2277 graphics->orig_bounds.Width = rect->Width;
2278 graphics->orig_bounds.Height = rect->Height;
2279 graphics->bounds.X = rect->X;
2280 graphics->bounds.Y = rect->Y;
2281 graphics->bounds.Width = rect->Width;
2282 graphics->bounds.Height = rect->Height;
2283 return Ok;
2284 }
2285
2286 GpStatus WINGDIPAPI
GdipGetVisibleClipBounds(GpGraphics * graphics,GpRectF * rect)2287 GdipGetVisibleClipBounds (GpGraphics *graphics, GpRectF *rect)
2288 {
2289 if (!graphics || !rect)
2290 return InvalidParameter;
2291
2292 if (graphics->state == GraphicsStateBusy)
2293 return ObjectBusy;
2294
2295 if (!gdip_is_InfiniteRegion (graphics->clip)) {
2296 GpRectF clipbound;
2297 GpStatus status = GdipGetClipBounds (graphics, &clipbound);
2298 if (status != Ok)
2299 return status;
2300
2301 /* intersect clipping with bounds (for clips bigger than the graphics) */
2302 rect->X = (clipbound.X > graphics->bounds.X) ? clipbound.X : graphics->bounds.X;
2303 rect->Y = (clipbound.Y > graphics->bounds.Y) ? clipbound.Y : graphics->bounds.Y;
2304 rect->Width = (((clipbound.X + clipbound.Width) < (graphics->bounds.X + graphics->bounds.Width)) ?
2305 (clipbound.X + clipbound.Width) : (graphics->bounds.X + graphics->bounds.Width)) - rect->X;
2306 rect->Height = (((clipbound.Y + clipbound.Height) < (graphics->bounds.Y + graphics->bounds.Height)) ?
2307 (clipbound.Y + clipbound.Height) : (graphics->bounds.Y + graphics->bounds.Height)) - rect->Y;
2308 } else {
2309 rect->X = graphics->bounds.X;
2310 rect->Y = graphics->bounds.Y;
2311 rect->Width = graphics->bounds.Width;
2312 rect->Height = graphics->bounds.Height;
2313 }
2314 return Ok;
2315 }
2316
2317 GpStatus WINGDIPAPI
GdipGetVisibleClipBoundsI(GpGraphics * graphics,GpRect * rect)2318 GdipGetVisibleClipBoundsI (GpGraphics *graphics, GpRect *rect)
2319 {
2320 GpStatus status;
2321 GpRectF rectF;
2322
2323 if (!graphics || !rect)
2324 return InvalidParameter;
2325
2326 status = GdipGetVisibleClipBounds (graphics, &rectF);
2327 if (status != Ok)
2328 return status;
2329
2330 gdip_Rect_from_RectF (&rectF, rect);
2331 return Ok;
2332 }
2333
2334 GpStatus WINGDIPAPI
GdipIsVisibleClipEmpty(GpGraphics * graphics,BOOL * result)2335 GdipIsVisibleClipEmpty (GpGraphics *graphics, BOOL *result)
2336 {
2337 GpRectF visibleClipBounds;
2338
2339 if (!graphics || !result)
2340 return InvalidParameter;
2341
2342 if (graphics->state == GraphicsStateBusy)
2343 return ObjectBusy;
2344
2345 GdipGetVisibleClipBounds (graphics, &visibleClipBounds);
2346
2347 *result = visibleClipBounds.Width == 0 || visibleClipBounds.Height == 0;
2348 return Ok;
2349 }
2350
2351 GpStatus WINGDIPAPI
GdipIsVisiblePoint(GpGraphics * graphics,REAL x,REAL y,BOOL * result)2352 GdipIsVisiblePoint (GpGraphics *graphics, REAL x, REAL y, BOOL *result)
2353 {
2354 GpRectF rectF;
2355
2356 if (!graphics || !result)
2357 return InvalidParameter;
2358
2359 gdip_RectF_from_Rect (&graphics->bounds, &rectF);
2360 *result = gdip_is_Point_in_RectF_inclusive (x, y, &rectF);
2361 return Ok;
2362 }
2363
2364 GpStatus WINGDIPAPI
GdipIsVisiblePointI(GpGraphics * graphics,INT x,INT y,BOOL * result)2365 GdipIsVisiblePointI (GpGraphics *graphics, INT x, INT y, BOOL *result)
2366 {
2367 return GdipIsVisiblePoint (graphics, x, y, result);
2368 }
2369
2370 GpStatus WINGDIPAPI
GdipIsVisibleRect(GpGraphics * graphics,REAL x,REAL y,REAL width,REAL height,BOOL * result)2371 GdipIsVisibleRect (GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, BOOL *result)
2372 {
2373 BOOL found = FALSE;
2374 float posy, posx;
2375 GpRectF recthit, boundsF;
2376
2377 if (!graphics || !result)
2378 return InvalidParameter;
2379
2380 if (width == 0 || height == 0) {
2381 *result = FALSE;
2382 return Ok;
2383 }
2384
2385 gdip_RectF_from_Rect (&graphics->bounds, &boundsF);
2386 recthit.X = x;
2387 recthit.Y = y;
2388 recthit.Width = width;
2389 recthit.Height = height;
2390
2391 /* Any point of intersection ?*/
2392 for (posy = 0; posy < recthit.Height+1; posy++) {
2393 for (posx = 0; posx < recthit.Width +1; posx++) {
2394 if (gdip_is_Point_in_RectF_inclusive (recthit.X + posx , recthit.Y + posy, &boundsF) == TRUE) {
2395 found = TRUE;
2396 break;
2397 }
2398 }
2399 }
2400
2401 *result = found;
2402 return Ok;
2403 }
2404
2405 GpStatus WINGDIPAPI
GdipIsVisibleRectI(GpGraphics * graphics,INT x,INT y,INT width,INT height,BOOL * result)2406 GdipIsVisibleRectI (GpGraphics *graphics, INT x, INT y, INT width, INT height, BOOL *result)
2407 {
2408 return GdipIsVisibleRect (graphics, x, y, width, height, result);
2409 }
2410
2411 GpStatus WINGDIPAPI
GdipSetCompositingMode(GpGraphics * graphics,CompositingMode compositingMode)2412 GdipSetCompositingMode (GpGraphics *graphics, CompositingMode compositingMode)
2413 {
2414 if (!graphics)
2415 return InvalidParameter;
2416
2417 if (graphics->state == GraphicsStateBusy)
2418 return ObjectBusy;
2419
2420 graphics->composite_mode = compositingMode;
2421
2422 switch (graphics->backend) {
2423 case GraphicsBackEndCairo:
2424 return cairo_SetCompositingMode (graphics, compositingMode);
2425 case GraphicsBackEndMetafile:
2426 return metafile_SetCompositingMode (graphics, compositingMode);
2427 default:
2428 return GenericError;
2429 }
2430 }
2431
2432 GpStatus WINGDIPAPI
GdipGetCompositingMode(GpGraphics * graphics,CompositingMode * compositingMode)2433 GdipGetCompositingMode (GpGraphics *graphics, CompositingMode *compositingMode)
2434 {
2435 if (!graphics || !compositingMode)
2436 return InvalidParameter;
2437
2438 if (graphics->state == GraphicsStateBusy)
2439 return ObjectBusy;
2440
2441 *compositingMode = graphics->composite_mode;
2442 return Ok;
2443 }
2444
2445 GpStatus WINGDIPAPI
GdipSetCompositingQuality(GpGraphics * graphics,CompositingQuality compositingQuality)2446 GdipSetCompositingQuality (GpGraphics *graphics, CompositingQuality compositingQuality)
2447 {
2448 if (!graphics)
2449 return InvalidParameter;
2450
2451 if (graphics->state == GraphicsStateBusy)
2452 return ObjectBusy;
2453
2454 graphics->composite_quality = compositingQuality;
2455
2456 switch (graphics->backend) {
2457 case GraphicsBackEndCairo:
2458 /* In Cairo there is no way of setting this, always use high quality */
2459 return Ok;
2460 case GraphicsBackEndMetafile:
2461 return metafile_SetCompositingQuality (graphics, compositingQuality);
2462 default:
2463 return GenericError;
2464 }
2465 }
2466
2467 GpStatus WINGDIPAPI
GdipGetCompositingQuality(GpGraphics * graphics,CompositingQuality * compositingQuality)2468 GdipGetCompositingQuality (GpGraphics *graphics, CompositingQuality *compositingQuality)
2469 {
2470 if (!graphics || !compositingQuality)
2471 return InvalidParameter;
2472
2473 if (graphics->state == GraphicsStateBusy)
2474 return ObjectBusy;
2475
2476 *compositingQuality = graphics->composite_quality;
2477 return Ok;
2478 }
2479
2480 GpStatus WINGDIPAPI
GdipGetNearestColor(GpGraphics * graphics,ARGB * argb)2481 GdipGetNearestColor (GpGraphics *graphics, ARGB *argb)
2482 {
2483 return Ok;
2484 }
2485
2486 GpStatus WINGDIPAPI
GdipResetPageTransform(GpGraphics * graphics)2487 GdipResetPageTransform (GpGraphics *graphics)
2488 {
2489 return NotImplemented;
2490 }
2491
2492 GpStatus WINGDIPAPI
GdipSetPageScale(GpGraphics * graphics,REAL scale)2493 GdipSetPageScale (GpGraphics *graphics, REAL scale)
2494 {
2495 if (!graphics)
2496 return InvalidParameter;
2497 if (graphics->state == GraphicsStateBusy)
2498 return ObjectBusy;
2499 if (scale <= 0.0 || scale > 1000000032)
2500 return InvalidParameter;
2501
2502 graphics->scale = scale;
2503
2504 switch (graphics->backend) {
2505 case GraphicsBackEndCairo:
2506 return Ok;
2507 case GraphicsBackEndMetafile:
2508 /* page unit and scale are in the same EMF+ record */
2509 return metafile_SetPageTransform (graphics, graphics->page_unit, scale);
2510 default:
2511 return GenericError;
2512 }
2513 }
2514
2515 GpStatus WINGDIPAPI
GdipGetPageScale(GpGraphics * graphics,REAL * scale)2516 GdipGetPageScale (GpGraphics *graphics, REAL *scale)
2517 {
2518 if (!graphics | !scale)
2519 return InvalidParameter;
2520
2521 if (graphics->state == GraphicsStateBusy)
2522 return ObjectBusy;
2523
2524 *scale = graphics->scale;
2525 return Ok;
2526 }
2527
2528 GpStatus WINGDIPAPI
GdipSetPageUnit(GpGraphics * graphics,GpUnit unit)2529 GdipSetPageUnit (GpGraphics *graphics, GpUnit unit)
2530 {
2531 if (!graphics)
2532 return InvalidParameter;
2533 if (graphics->state == GraphicsStateBusy)
2534 return ObjectBusy;
2535 if (unit <= UnitWorld || unit > UnitCairoPoint)
2536 return InvalidParameter;
2537
2538 graphics->page_unit = unit;
2539
2540 switch (graphics->backend) {
2541 case GraphicsBackEndCairo:
2542 return Ok;
2543 case GraphicsBackEndMetafile:
2544 /* page unit and scale are in the same EMF+ record */
2545 return metafile_SetPageTransform (graphics, unit, graphics->scale);
2546 default:
2547 return GenericError;
2548 }
2549 }
2550
2551 GpStatus WINGDIPAPI
GdipGetPageUnit(GpGraphics * graphics,GpUnit * unit)2552 GdipGetPageUnit (GpGraphics *graphics, GpUnit *unit)
2553 {
2554 if (!graphics || !unit)
2555 return InvalidParameter;
2556
2557 if (graphics->state == GraphicsStateBusy)
2558 return ObjectBusy;
2559
2560 *unit = graphics->page_unit;
2561 return Ok;
2562 }
2563
2564 GpStatus WINGDIPAPI
GdipTransformPoints(GpGraphics * graphics,GpCoordinateSpace destSpace,GpCoordinateSpace srcSpace,GpPointF * points,INT count)2565 GdipTransformPoints (GpGraphics *graphics, GpCoordinateSpace destSpace, GpCoordinateSpace srcSpace, GpPointF *points, INT count)
2566 {
2567 static int called = 0;
2568
2569 if (!called) {
2570 printf("NOT IMPLEMENTED YET:GdipTransformPoints (GpGraphics *graphics, GpCoordinateSpace destSpace %d, GpCoordinateSpace srcSpace %d, GpPointF *points, int count %d)\n", destSpace, srcSpace, count);
2571 }
2572 /* return NotImplemented; */
2573 return Ok;
2574 }
2575
2576 GpStatus WINGDIPAPI
GdipTransformPointsI(GpGraphics * graphics,GpCoordinateSpace destSpace,GpCoordinateSpace srcSpace,GpPoint * points,INT count)2577 GdipTransformPointsI (GpGraphics *graphics, GpCoordinateSpace destSpace, GpCoordinateSpace srcSpace, GpPoint *points, INT count)
2578 {
2579 static int called = 0;
2580
2581 if (!called) {
2582 printf("NOT IMPLEMENTED YET:GdipTransformPointsI (GpGraphics *graphics, GpCoordinateSpace destSpace, GpCoordinateSpace srcSpace, GpPoint *points, int count)\n");
2583 }
2584 /* return NotImplemented; */
2585 return Ok;
2586 }
2587
2588 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST PointF * destPoint,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2589 GdipEnumerateMetafileDestPoint (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST PointF *destPoint,
2590 EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2591 {
2592 return NotImplemented;
2593 }
2594
2595 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST Point * destPoint,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2596 GdipEnumerateMetafileDestPointI (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST Point *destPoint,
2597 EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2598 {
2599 return NotImplemented;
2600 }
2601
2602 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST RectF * destRect,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2603 GdipEnumerateMetafileDestRect (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST RectF *destRect,
2604 EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2605 {
2606 return NotImplemented;
2607 }
2608
2609 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST Rect * destRect,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2610 GdipEnumerateMetafileDestRectI (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST Rect *destRect,
2611 EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes )
2612 {
2613 return NotImplemented;
2614 }
2615
2616 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoints(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST PointF * destPoints,INT count,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2617 GdipEnumerateMetafileDestPoints (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST PointF *destPoints, INT count,
2618 EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2619 {
2620 return NotImplemented;
2621 }
2622
2623 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointsI(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST Point * destPoints,INT count,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2624 GdipEnumerateMetafileDestPointsI (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST Point *destPoints, INT count,
2625 EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes )
2626 {
2627 return NotImplemented;
2628 }
2629
2630 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoint(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST PointF * destPoint,GDIPCONST RectF * srcRect,Unit srcUnit,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2631 GdipEnumerateMetafileSrcRectDestPoint (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST PointF *destPoint, GDIPCONST RectF *srcRect,
2632 Unit srcUnit, EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes * imageAttributes)
2633 {
2634 return NotImplemented;
2635 }
2636
2637 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPointI(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST Point * destPoint,GDIPCONST Rect * srcRect,Unit srcUnit,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2638 GdipEnumerateMetafileSrcRectDestPointI (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST Point *destPoint, GDIPCONST Rect *srcRect,
2639 Unit srcUnit, EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2640 {
2641 return NotImplemented;
2642 }
2643
2644 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRect(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST RectF * destRect,GDIPCONST RectF * srcRect,Unit srcUnit,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2645 GdipEnumerateMetafileSrcRectDestRect (GpGraphics * graphics, GDIPCONST GpMetafile *metafile, GDIPCONST RectF *destRect, GDIPCONST RectF *srcRect,
2646 Unit srcUnit, EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2647 {
2648 return NotImplemented;
2649 }
2650
2651 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRectI(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST Rect * destRect,GDIPCONST Rect * srcRect,Unit srcUnit,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2652 GdipEnumerateMetafileSrcRectDestRectI (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST Rect *destRect, GDIPCONST Rect *srcRect,
2653 Unit srcUnit, EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2654 {
2655 return NotImplemented;
2656 }
2657
2658 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST PointF * destPoints,INT count,GDIPCONST RectF * srcRect,Unit srcUnit,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2659 GdipEnumerateMetafileSrcRectDestPoints (GpGraphics *graphics, GDIPCONST GpMetafile * metafile, GDIPCONST PointF *destPoints, INT count, GDIPCONST RectF *srcRect,
2660 Unit srcUnit, EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2661 {
2662 return NotImplemented;
2663 }
2664
2665 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPointsI(GpGraphics * graphics,GDIPCONST GpMetafile * metafile,GDIPCONST Point * destPoints,INT count,GDIPCONST Rect * srcRect,Unit srcUnit,EnumerateMetafileProc callback,VOID * callbackData,GDIPCONST GpImageAttributes * imageAttributes)2666 GdipEnumerateMetafileSrcRectDestPointsI (GpGraphics *graphics, GDIPCONST GpMetafile *metafile, GDIPCONST Point *destPoints, INT count, GDIPCONST Rect *srcRect,
2667 Unit srcUnit, EnumerateMetafileProc callback, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2668 {
2669 return NotImplemented;
2670 }
2671
2672 HPALETTE WINGDIPAPI
GdipCreateHalftonePalette()2673 GdipCreateHalftonePalette()
2674 {
2675 return NULL;
2676 }
2677