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 (&region);
1994 		if (status != Ok)
1995 			return status;
1996 
1997 		GdipSetEmpty (region);
1998 	}
1999 	else {
2000 		status = GdipCreateRegionRect (&rect, &region);
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