4 * Copyright (c) 2003 Alexandre Pigolkine
6 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
7 * and associated documentation files (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all copies or substantial
13 * portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
16 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
19 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * Alexandre Pigolkine(pigolkine@gmx.de)
23 * Duncan Mak (duncan@ximian.com)
27 #include "gdip_main.h"
28 #include "gdip_win32.h"
32 gdip_graphics_init (GpGraphics *graphics)
34 graphics->ct = cairo_create ();
35 graphics->copy_of_ctm = cairo_matrix_create ();
36 cairo_matrix_set_identity (graphics->copy_of_ctm);
38 graphics->hdc_busy_count = 0;
40 graphics->type = gtUndefined;
41 cairo_select_font (graphics->ct, "serif:12");
42 /* cairo_select_font (graphics->ct, "serif:12", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); */
48 GpGraphics *result = (GpGraphics *) GdipAlloc (sizeof (GpGraphics));
49 gdip_graphics_init (result);
54 gdip_graphics_attach_bitmap (GpGraphics *graphics, GpBitmap *image)
56 cairo_set_target_image (graphics->ct, image->data.Scan0, image->cairo_format,
57 image->data.Width, image->data.Height, image->data.Stride);
58 graphics->image = image;
59 graphics->type = gtMemoryBitmap;
63 gdip_graphics_detach_bitmap (GpGraphics *graphics, GpBitmap *image)
65 printf ("Implement graphics_detach_bitmap");
66 /* FIXME: implement me */
72 make_ellipse (GpGraphics *graphics, float x, float y, float width, float height)
74 double rx = width / 2;
75 double ry = height / 2;
79 cairo_move_to (graphics->ct, cx + rx, cy);
81 /* an approximate of the ellipse by drawing a curve in each
83 cairo_curve_to (graphics->ct,
84 cx + rx, cy - C1 * ry,
85 cx + C1 * rx, cy - ry,
87 cairo_curve_to (graphics->ct,
88 cx - C1 * rx, cy - ry,
89 cx - rx, cy - C1 * ry,
91 cairo_curve_to (graphics->ct,
92 cx - rx, cy + C1 * ry,
93 cx - C1 * rx, cy + ry,
95 cairo_curve_to (graphics->ct,
96 cx + C1 * rx, cy + ry,
97 cx + rx, cy + C1 * ry,
100 cairo_close_path (graphics->ct);
104 make_polygon (GpGraphics *graphics, GpPointF *points, int count)
107 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
109 for (i = 0; i < count; i++)
110 cairo_line_to (graphics->ct, points [i].X, points [i].Y);
113 * Draw a line from the last point back to the first point if
114 * they're not the same
116 if (points [0].X != points [count].X && points [0].Y != points [count].Y)
117 cairo_line_to (graphics->ct, points [0].X, points [0].Y);
119 cairo_close_path (graphics->ct);
123 make_polygon_from_integers (
124 GpGraphics *graphics, GpPoint *points, int count)
127 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
129 for (i = 0; i < count; i++)
130 cairo_line_to (graphics->ct, points [i].X, points [i].Y);
133 * Draw a line from the last point back to the first point if
134 * they're not the same
136 if (points [0].X != points [count].X && points [0].Y != points [count].Y)
137 cairo_line_to (graphics->ct, points [0].X, points [0].Y);
139 cairo_close_path (graphics->ct);
143 make_pie (GpGraphics *graphics, float x, float y, float width,
144 float height, float startAngle, float sweepAngle)
146 float ax, ay; /* the first intersection */
147 float bx, by; /* the second intersection */
148 float cx, cy; /* center of the bounding rect */
149 float f1, f2; /* x coord. of foci */
150 float c; /* distance between center and focus */
153 * we'll assume that we're working on a circle
154 * and transform back into an ellipse after the calculation
156 float radius = width / 2;
157 float scale = height / width;
159 ax = radius * cos (startAngle);
160 ay = radius * sin (startAngle) * scale;
162 bx = radius * cos (startAngle + sweepAngle);
163 by = radius * sin (startAngle + sweepAngle) * scale;
165 cx = x + (width / 2);
166 cy = y + (height / 2);
168 c = sqrt (-cy * cy + cx * cx);
172 cairo_move_to (graphics->ct, cx, cy);
173 cairo_line_to (graphics->ct, ax, ay);
175 cairo_curve_to (graphics->ct,
176 cx, f1, cx, f2, bx, by);
178 cairo_line_to (graphics->ct, cx, cy);
180 cairo_close_path (graphics->ct);
183 static cairo_fill_rule_t
184 convert_fill_mode (GpFillMode fill_mode)
186 if (fill_mode == FillModeAlternate)
187 return CAIRO_FILL_RULE_EVEN_ODD;
189 return CAIRO_FILL_RULE_WINDING;
194 GdipCreateFromHDC (int hDC, GpGraphics **graphics)
196 DC* dc = _get_DC_by_HDC (hDC);
198 /* printf ("GdipCreateFromHDC. in %d, DC %p\n", hDC, dc); */
199 if (dc == 0) return NotImplemented;
201 *graphics = gdip_graphics_new ();
202 cairo_set_target_drawable ((*graphics)->ct, GDIP_display, dc->physDev->drawable);
204 (*graphics)->hdc = (void*)hDC;
205 (*graphics)->type = gtX11Drawable;
206 /* printf ("GdipCreateFromHDC. graphics %p, ct %p\n", (*graphics), (*graphics)->ct); */
211 GdipDeleteGraphics (GpGraphics *graphics)
213 /* FIXME: attention to surface (image, etc.) */
214 /* printf ("GdipDeleteGraphics. graphics %p\n", graphics); */
215 cairo_matrix_destroy (graphics->copy_of_ctm);
216 cairo_destroy (graphics->ct);
222 GdipGetDC (GpGraphics *graphics, int *hDC)
224 if (graphics->hdc == 0) {
225 if (graphics->image != 0) {
227 graphics->hdc = gdip_image_create_Win32_HDC (graphics->image);
228 if (graphics->hdc != 0) {
229 ++graphics->hdc_busy_count;
233 *hDC = (int)graphics->hdc;
238 GdipReleaseDC (GpGraphics *graphics, int hDC)
240 if (graphics->hdc != (void *)hDC) return InvalidParameter;
241 if (graphics->hdc_busy_count > 0) {
242 --graphics->hdc_busy_count;
243 if (graphics->hdc_busy_count == 0) {
245 gdip_image_destroy_Win32_HDC (graphics->image, (void*)hDC);
252 #define MAX_GRAPHICS_STATE_STACK 100
254 GpState saved_stack [MAX_GRAPHICS_STATE_STACK];
255 int current_stack_pos = 0;
258 GdipRestoreGraphics (GpGraphics *graphics, unsigned int graphicsState)
260 if (graphicsState < MAX_GRAPHICS_STATE_STACK) {
261 cairo_matrix_copy (graphics->copy_of_ctm, saved_stack[graphicsState].matrix);
262 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
265 return InvalidParameter;
271 GdipSaveGraphics(GpGraphics *graphics, unsigned int *state)
273 if (current_stack_pos < MAX_GRAPHICS_STATE_STACK) {
274 saved_stack[current_stack_pos].matrix = cairo_matrix_create ();
275 cairo_matrix_copy (saved_stack[current_stack_pos].matrix, graphics->copy_of_ctm);
276 *state = current_stack_pos;
285 #define PI 3.14159265358979323846
286 #define GRADTORAD PI / 180.0
289 GdipRotateWorldTransform (GpGraphics *graphics, float angle, int order)
291 cairo_matrix_t *mtx = cairo_matrix_create ();
292 cairo_matrix_rotate (mtx, angle * GRADTORAD);
293 cairo_matrix_multiply (graphics->copy_of_ctm, mtx, graphics->copy_of_ctm );
294 cairo_matrix_destroy ( mtx);
295 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
300 GdipTranslateWorldTransform (GpGraphics *graphics, float dx, float dy, int order)
302 /* FIXME: consider order here */
303 cairo_matrix_translate (graphics->copy_of_ctm, dx, dy);
304 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
310 GdipDrawArc (GpGraphics *graphics, GpPen *pen,
311 float x, float y, float width, float height,
312 float startAngle, float sweepAngle)
314 gdip_pen_setup (graphics, pen);
316 return NotImplemented;
320 GdipDrawArcI (GpGraphics *graphics, GpPen *pen,
321 int x, int y, int width, int height,
322 int startAngle, int sweepAngle)
324 gdip_pen_setup (graphics, pen);
326 return NotImplemented;
330 GdipDrawBezier (GpGraphics *graphics, GpPen *pen,
331 float x1, float y1, float x2, float y2,
332 float x3, float y3, float x4, float y4)
334 gdip_pen_setup (graphics, pen);
335 cairo_move_to (graphics->ct, x1, y1);
336 cairo_curve_to (graphics->ct, x2, y2, x3, y3, x4, y4);
337 cairo_stroke (graphics->ct);
339 return gdip_get_status (graphics->ct);
342 GpStatus GdipDrawBezierI (GpGraphics *graphics, GpPen *pen,
343 int x1, int y1, int x2, int y2,
344 int x3, int y3, int x4, int y4)
346 return GdipDrawBezier (graphics, pen,
347 x1, y1, x2, y2, x3, y3, x4, y4);
351 GdipDrawBeziers (GpGraphics *graphics, GpPen *pen,
352 GpPointF *points, int count)
359 gdip_pen_setup (graphics, pen);
360 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
362 for (i = 0; i < count; i += 3) {
365 cairo_curve_to (graphics->ct,
366 points [i].X, points [i].Y,
367 points [j].X, points [j].Y,
368 points [k].X, points [k].Y);
371 cairo_stroke (graphics->ct);
373 return gdip_get_status (graphics->ct);
377 GdipDrawBeziersI (GpGraphics *graphics, GpPen *pen,
378 GpPoint *points, int count)
385 gdip_pen_setup (graphics, pen);
386 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
388 for (i = 0; i < count; i += 3) {
391 cairo_curve_to (graphics->ct,
392 points [i].X, points [i].Y,
393 points [j].X, points [j].Y,
394 points [k].X, points [k].Y);
397 cairo_stroke (graphics->ct);
399 return gdip_get_status (graphics->ct);
403 GdipDrawEllipse (GpGraphics *graphics, GpPen *pen,
404 float x, float y, float width, float height)
406 gdip_pen_setup (graphics, pen);
407 make_ellipse (graphics, x, y, width, height);
408 cairo_stroke (graphics->ct);
410 return gdip_get_status (graphics->ct);
414 GdipDrawEllipseI (GpGraphics *graphics, GpPen *pen,
415 int x, int y, int width, int height)
417 return GdipDrawEllipse (graphics, pen, x, y, width, height);
421 GdipDrawLine (GpGraphics *graphics, GpPen *pen,
422 float x1, float y1, float x2, float y2)
424 gdip_pen_setup (graphics, pen);
426 cairo_move_to (graphics->ct, x1, y1);
427 cairo_line_to (graphics->ct, x2, y2);
429 cairo_stroke (graphics->ct);
431 return gdip_get_status (graphics->ct);
435 GdipDrawLineI (GpGraphics *graphics, GpPen *pen,
436 int x1, int y1, int x2, int y2)
438 return GdipDrawLine (graphics, pen, x1, y1, x2, y2);
442 GdipDrawLines (GpGraphics *graphics, GpPen *pen, GpPointF *points, int count)
447 for (i = 0; i < count - 1; i++) {
449 s = GdipDrawLine (graphics, pen,
450 points [i].X, points [i].Y,
451 points [j].X, points [j].Y);
453 if (s != Ok) return s;
460 GdipDrawLinesI (GpGraphics *graphics, GpPen *pen,
461 GpPoint *points, int count)
466 for (i = 0; i < count - 1; i++) {
468 s = GdipDrawLineI (graphics, pen,
469 points [i].X, points [i].Y,
470 points [j].X, points [j].Y);
472 if (s != Ok) return s;
479 GdipDrawPie (GpGraphics *graphics, GpPen *pen, float x, float y,
480 float width, float height, float startAngle, float sweepAngle)
482 gdip_pen_setup (graphics, pen);
483 make_pie (graphics, x, y, width, height, startAngle, sweepAngle);
484 cairo_stroke (graphics->ct);
485 cairo_close_path (graphics->ct);
487 return gdip_get_status (graphics->ct);
491 GdipDrawPieI (GpGraphics *graphics, GpPen *pen, int x, int y,
492 int width, int height, float startAngle, float sweepAngle)
494 gdip_pen_setup (graphics, pen);
495 make_pie (graphics, x, y, width, height, startAngle, sweepAngle);
496 cairo_stroke (graphics->ct);
497 cairo_close_path (graphics->ct);
499 return gdip_get_status (graphics->ct);
503 GdipDrawPolygon (GpGraphics *graphics, GpPen *pen, GpPointF *points, int count)
505 gdip_pen_setup (graphics, pen);
506 make_polygon (graphics, points, count);
507 cairo_stroke (graphics->ct);
509 return gdip_get_status (graphics->ct);
513 GdipDrawPolygonI (GpGraphics *graphics, GpPen *pen, GpPoint *points, int count)
515 gdip_pen_setup (graphics, pen);
516 make_polygon_from_integers (graphics, points, count);
517 cairo_stroke (graphics->ct);
519 return gdip_get_status (graphics->ct);
523 GdipDrawRectangle (GpGraphics *graphics, GpPen *pen,
524 float x, float y, float width, float height)
526 gdip_pen_setup (graphics, pen);
527 cairo_rectangle (graphics->ct, x, y, width, height);
528 cairo_stroke (graphics->ct);
530 return gdip_get_status (graphics->ct);
534 GdipDrawRectangleI (GpGraphics *graphics, GpPen *pen,
535 int x, int y, int width, int height)
537 return GdipDrawRectangle (graphics, pen, x, y, width, height);
541 GdipFillEllipse (GpGraphics *graphics, GpBrush *brush,
542 float x, float y, float width, float height)
544 gdip_brush_setup (graphics, brush);
545 make_ellipse (graphics, x, y, width, height);
546 cairo_fill (graphics->ct);
548 return gdip_get_status (graphics->ct);
552 GdipFillEllipseI (GpGraphics *graphics, GpBrush *brush,
553 int x, int y, int width, int height)
555 return GdipFillEllipse (graphics, brush, x, y, width, height);
559 GdipFillRectangle (GpGraphics *graphics, GpBrush *brush,
560 float x, float y, float width, float height)
562 gdip_brush_setup (graphics, brush);
563 cairo_rectangle (graphics->ct, x, y, width, height);
564 cairo_fill (graphics->ct);
565 return gdip_get_status (graphics->ct);
569 GdipFillPolygon (GpGraphics *graphics, GpBrush *brush,
570 GpPointF *points, int count, GpFillMode fillMode)
572 gdip_brush_setup (graphics, brush);
573 make_polygon (graphics, points, count);
575 cairo_set_fill_rule (
577 convert_fill_mode (fillMode));
579 cairo_fill (graphics->ct);
581 return gdip_get_status (graphics->ct);
585 GdipFillPolygonI (GpGraphics *graphics, GpBrush *brush,
586 GpPoint *points, int count, GpFillMode fillMode)
588 gdip_brush_setup (graphics, brush);
589 make_polygon_from_integers (graphics, points, count);
591 cairo_set_fill_rule (
593 convert_fill_mode (fillMode));
595 cairo_fill (graphics->ct);
597 return gdip_get_status (graphics->ct);
601 GdipFillPolygon2 (GpGraphics *graphics, GpBrush *brush, GpPointF *points, int count)
603 return GdipFillPolygon (graphics, brush, points, count, FillModeAlternate);
607 GdipFillPolygon2I (GpGraphics *graphics, GpBrush *brush, GpPoint *points, int count)
609 return GdipFillPolygonI (graphics, brush, points, count, FillModeAlternate);
613 GdipDrawString (GpGraphics *graphics, const char *string,
614 int len, void *font, RectF *rc, void *format, GpBrush *brush)
616 cairo_save (graphics->ct);
618 gdip_brush_setup (graphics, brush);
620 cairo_set_rgb_color (graphics->ct, 0., 0., 0.);
622 cairo_move_to (graphics->ct, rc->left, rc->top + 12);
623 cairo_scale_font (graphics->ct, 12);
624 cairo_show_text (graphics->ct, string);
625 cairo_restore(graphics->ct);
627 return gdip_get_status (graphics->ct);
631 GdipSetRenderingOrigin (GpGraphics *graphics, int x, int y)
633 cairo_move_to (graphics->ct, x, y);
634 cairo_close_path (graphics->ct);
636 return gdip_get_status (graphics->ct);
640 * FIXME: cairo_current_point does not reflect changes made from
644 GdipGetRenderingOrigin (GpGraphics *graphics, int *x, int *y)
647 cairo_current_point (graphics->ct, &cx, &cy);
652 return gdip_get_status (graphics->ct);