4 * Copyright (c) 2003 Alexandre Pigolkine, Novell Inc.
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)
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 */
71 make_ellipse (GpGraphics *graphics, float x, float y, float width, float height)
73 double rx = width / 2;
74 double ry = height / 2;
78 cairo_move_to (graphics->ct, cx + rx, cy);
80 /* an approximate of the ellipse by drawing a curve in each
82 cairo_curve_to (graphics->ct,
83 cx + rx, cy - C1 * ry,
84 cx + C1 * rx, cy - ry,
87 cairo_curve_to (graphics->ct,
88 cx - C1 * rx, cy - ry,
89 cx - rx, cy - C1 * ry,
92 cairo_curve_to (graphics->ct,
93 cx - rx, cy + C1 * ry,
94 cx - C1 * rx, cy + ry,
97 cairo_curve_to (graphics->ct,
98 cx + C1 * rx, cy + ry,
99 cx + rx, cy + C1 * ry,
102 cairo_close_path (graphics->ct);
106 make_polygon (GpGraphics *graphics, GpPointF *points, int count)
109 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
111 for (i = 0; i < count; i++)
112 cairo_line_to (graphics->ct, points [i].X, points [i].Y);
115 * Draw a line from the last point back to the first point if
116 * they're not the same
118 if (points [0].X != points [count].X && points [0].Y != points [count].Y)
119 cairo_line_to (graphics->ct, points [0].X, points [0].Y);
121 cairo_close_path (graphics->ct);
125 make_polygon_from_integers (
126 GpGraphics *graphics, GpPoint *points, int count)
129 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
131 for (i = 0; i < count; i++)
132 cairo_line_to (graphics->ct, points [i].X, points [i].Y);
135 * Draw a line from the last point back to the first point if
136 * they're not the same
138 if (points [0].X != points [count].X && points [0].Y != points [count].Y)
139 cairo_line_to (graphics->ct, points [0].X, points [0].Y);
141 cairo_close_path (graphics->ct);
145 * Based on the algorithm described in
146 * http://www.stillhq.com/ctpfaq/2002/03/c1088.html#AEN1212
149 make_pie (GpGraphics *graphics, float x, float y,
150 float width, float height, float startAngle, float sweepAngle)
152 float rx = width / 2;
153 float ry = height / 2;
157 /* angles in radians */
158 float alpha = startAngle * PI / 180;
159 float beta = sweepAngle * PI / 180;
161 float delta = beta - alpha;
162 float bcp = 4.0 / 3 * (1 - cos (delta / 2)) / sin (delta /2);
164 float sin_alpha = sin (alpha);
165 float sin_beta = sin (beta);
166 float cos_alpha = cos (alpha);
167 float cos_beta = cos (beta);
170 cairo_move_to (graphics->ct, cx, cy);
173 cairo_line_to (graphics->ct,
175 cy + ry * sin_alpha);
177 cairo_curve_to (graphics->ct,
178 cx + rx * (cos_alpha - bcp * sin_alpha),
179 cy + ry * (sin_alpha + bcp * cos_alpha),
180 cx + rx * (cos_beta + bcp * sin_beta),
181 cy + ry * (sin_beta - bcp * cos_beta),
185 /* draws line back to center */
186 cairo_close_path (graphics->ct);
190 make_arc (GpGraphics *graphics, float x, float y, float width,
191 float height, float startAngle, float sweepAngle)
193 float rx = width / 2;
194 float ry = height / 2;
200 /* angles in radians */
201 float alpha = startAngle * PI / 180;
202 float beta = sweepAngle * PI / 180;
204 float delta = beta - alpha;
205 float bcp = 4.0 / 3 * (1 - cos (delta / 2)) / sin (delta /2);
207 float sin_alpha = sin (alpha);
208 float sin_beta = sin (beta);
209 float cos_alpha = cos (alpha);
210 float cos_beta = cos (beta);
212 /* move to pie edge */
213 cairo_move_to (graphics->ct,
215 cy + ry * sin_alpha);
217 cairo_curve_to (graphics->ct,
218 cx + rx * (cos_alpha - bcp * sin_alpha),
219 cy + ry * (sin_alpha + bcp * cos_alpha),
220 cx + rx * (cos_beta + bcp * sin_beta),
221 cy + ry * (sin_beta - bcp * cos_beta),
226 static cairo_fill_rule_t
227 convert_fill_mode (GpFillMode fill_mode)
229 if (fill_mode == FillModeAlternate)
230 return CAIRO_FILL_RULE_EVEN_ODD;
232 return CAIRO_FILL_RULE_WINDING;
237 GdipCreateFromHDC (int hDC, GpGraphics **graphics)
239 DC* dc = _get_DC_by_HDC (hDC);
241 /* printf ("GdipCreateFromHDC. in %d, DC %p\n", hDC, dc); */
242 if (dc == 0) return NotImplemented;
244 *graphics = gdip_graphics_new ();
245 cairo_set_target_drawable ((*graphics)->ct, GDIP_display, dc->physDev->drawable);
247 (*graphics)->hdc = (void*)hDC;
248 (*graphics)->type = gtX11Drawable;
249 /* printf ("GdipCreateFromHDC. graphics %p, ct %p\n", (*graphics), (*graphics)->ct); */
254 GdipDeleteGraphics (GpGraphics *graphics)
256 /* FIXME: attention to surface (image, etc.) */
257 /* printf ("GdipDeleteGraphics. graphics %p\n", graphics); */
258 cairo_matrix_destroy (graphics->copy_of_ctm);
259 cairo_destroy (graphics->ct);
265 GdipGetDC (GpGraphics *graphics, int *hDC)
267 if (graphics->hdc == 0) {
268 if (graphics->image != 0) {
270 graphics->hdc = gdip_image_create_Win32_HDC (graphics->image);
271 if (graphics->hdc != 0) {
272 ++graphics->hdc_busy_count;
276 *hDC = (int)graphics->hdc;
281 GdipReleaseDC (GpGraphics *graphics, int hDC)
283 if (graphics->hdc != (void *)hDC) return InvalidParameter;
284 if (graphics->hdc_busy_count > 0) {
285 --graphics->hdc_busy_count;
286 if (graphics->hdc_busy_count == 0) {
288 gdip_image_destroy_Win32_HDC (graphics->image, (void*)hDC);
295 #define MAX_GRAPHICS_STATE_STACK 100
297 GpState saved_stack [MAX_GRAPHICS_STATE_STACK];
298 int current_stack_pos = 0;
301 GdipRestoreGraphics (GpGraphics *graphics, unsigned int graphicsState)
303 if (graphicsState < MAX_GRAPHICS_STATE_STACK) {
304 cairo_matrix_copy (graphics->copy_of_ctm, saved_stack[graphicsState].matrix);
305 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
308 return InvalidParameter;
314 GdipSaveGraphics(GpGraphics *graphics, unsigned int *state)
316 if (current_stack_pos < MAX_GRAPHICS_STATE_STACK) {
317 saved_stack[current_stack_pos].matrix = cairo_matrix_create ();
318 cairo_matrix_copy (saved_stack[current_stack_pos].matrix, graphics->copy_of_ctm);
319 *state = current_stack_pos;
328 GdipResetWorldTransform (GpGraphics *graphics)
330 GpStatus s = cairo_matrix_set_identity (graphics->copy_of_ctm);
335 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
341 GdipSetWorldTransform (GpGraphics *graphics, GpMatrix *matrix)
343 graphics->copy_of_ctm = matrix;
344 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
349 GdipGetWorldTransform (GpGraphics *graphics, GpMatrix *matrix)
351 cairo_current_matrix (graphics->ct, matrix);
356 GdipMultiplyWorldTransform (GpGraphics *graphics, GpMatrix *matrix, GpMatrixOrder order)
358 Status s = GdipMultiplyMatrix (graphics->copy_of_ctm, matrix, order);
364 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
370 GdipRotateWorldTransform (GpGraphics *graphics, float angle, GpMatrixOrder order)
372 GpStatus s = GdipRotateMatrix (graphics->copy_of_ctm, angle, order);
377 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
383 GdipTranslateWorldTransform (GpGraphics *graphics, float dx, float dy, GpMatrixOrder order)
385 GpStatus s = GdipTranslateMatrix (graphics->copy_of_ctm, dx, dy, order);
390 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
396 GdipDrawArc (GpGraphics *graphics, GpPen *pen,
397 float x, float y, float width, float height,
398 float startAngle, float sweepAngle)
400 gdip_pen_setup (graphics, pen);
402 float delta = sweepAngle - startAngle;
405 make_arc (graphics, x, y, width, height, startAngle, sweepAngle);
408 make_arc (graphics, x, y, width, height, startAngle, startAngle + 180);
409 make_arc (graphics, x, y, width, height, startAngle + 180, sweepAngle);
412 cairo_stroke (graphics->ct);
414 return gdip_get_status (cairo_status (graphics->ct));
418 GdipDrawArcI (GpGraphics *graphics, GpPen *pen,
419 int x, int y, int width, int height,
420 float startAngle, float sweepAngle)
422 gdip_pen_setup (graphics, pen);
424 float delta = sweepAngle - startAngle;
427 make_arc (graphics, x, y, width, height, startAngle, sweepAngle);
430 make_arc (graphics, x, y, width, height, startAngle, startAngle + 180);
431 make_arc (graphics, x, y, width, height, startAngle + 180, sweepAngle);
434 cairo_stroke (graphics->ct);
436 return gdip_get_status (cairo_status (graphics->ct));
440 GdipDrawBezier (GpGraphics *graphics, GpPen *pen,
441 float x1, float y1, float x2, float y2,
442 float x3, float y3, float x4, float y4)
444 gdip_pen_setup (graphics, pen);
446 cairo_move_to (graphics->ct, x1, y1);
447 cairo_curve_to (graphics->ct, x2, y2, x3, y3, x4, y4);
448 cairo_stroke (graphics->ct);
450 return gdip_get_status (cairo_status (graphics->ct));
453 GpStatus GdipDrawBezierI (GpGraphics *graphics, GpPen *pen,
454 int x1, int y1, int x2, int y2,
455 int x3, int y3, int x4, int y4)
457 return GdipDrawBezier (graphics, pen,
458 x1, y1, x2, y2, x3, y3, x4, y4);
462 GdipDrawBeziers (GpGraphics *graphics, GpPen *pen,
463 GpPointF *points, int count)
470 gdip_pen_setup (graphics, pen);
472 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
474 for (i = 0; i < count - 3; i += 3) {
477 cairo_curve_to (graphics->ct,
478 points [i].X, points [i].Y,
479 points [j].X, points [j].Y,
480 points [k].X, points [k].Y);
483 cairo_stroke (graphics->ct);
485 return gdip_get_status (cairo_status (graphics->ct));
489 GdipDrawBeziersI (GpGraphics *graphics, GpPen *pen,
490 GpPoint *points, int count)
497 gdip_pen_setup (graphics, pen);
499 cairo_move_to (graphics->ct, points [0].X, points [0].Y);
501 for (i = 0; i < count - 3; i += 3) {
504 cairo_curve_to (graphics->ct,
505 points [i].X, points [i].Y,
506 points [j].X, points [j].Y,
507 points [k].X, points [k].Y);
510 cairo_stroke (graphics->ct);
512 return gdip_get_status (cairo_status (graphics->ct));
516 GdipDrawEllipse (GpGraphics *graphics, GpPen *pen,
517 float x, float y, float width, float height)
519 gdip_pen_setup (graphics, pen);
521 make_ellipse (graphics, x, y, width, height);
522 cairo_stroke (graphics->ct);
524 return gdip_get_status (cairo_status (graphics->ct));
528 GdipDrawEllipseI (GpGraphics *graphics, GpPen *pen,
529 int x, int y, int width, int height)
531 return GdipDrawEllipse (graphics, pen, x, y, width, height);
535 GdipDrawLine (GpGraphics *graphics, GpPen *pen,
536 float x1, float y1, float x2, float y2)
538 gdip_pen_setup (graphics, pen);
540 cairo_move_to (graphics->ct, x1, y1);
541 cairo_line_to (graphics->ct, x2, y2);
542 cairo_stroke (graphics->ct);
544 return gdip_get_status (cairo_status (graphics->ct));
548 GdipDrawLineI (GpGraphics *graphics, GpPen *pen,
549 int x1, int y1, int x2, int y2)
551 return GdipDrawLine (graphics, pen, x1, y1, x2, y2);
555 GdipDrawLines (GpGraphics *graphics, GpPen *pen, GpPointF *points, int count)
560 for (i = 0; i < count - 1; i++) {
562 s = GdipDrawLine (graphics, pen,
563 points [i].X, points [i].Y,
564 points [j].X, points [j].Y);
566 if (s != Ok) return s;
569 return gdip_get_status (cairo_status (graphics->ct));
573 GdipDrawLinesI (GpGraphics *graphics, GpPen *pen,
574 GpPoint *points, int count)
579 for (i = 0; i < count - 1; i++) {
581 s = GdipDrawLineI (graphics, pen,
582 points [i].X, points [i].Y,
583 points [j].X, points [j].Y);
585 if (s != Ok) return s;
592 GdipDrawPie (GpGraphics *graphics, GpPen *pen, float x, float y,
593 float width, float height, float startAngle, float sweepAngle)
595 gdip_pen_setup (graphics, pen);
597 float delta = sweepAngle - startAngle;
600 make_pie (graphics, x, y, width, height, startAngle, sweepAngle);
602 make_pie (graphics, x, y, width, height, startAngle, startAngle + 180);
603 make_pie (graphics, x, y, width, height, startAngle + 180, sweepAngle);
606 cairo_stroke (graphics->ct);
608 cairo_close_path (graphics->ct);
610 return gdip_get_status (cairo_status (graphics->ct));
614 GdipDrawPieI (GpGraphics *graphics, GpPen *pen, int x, int y,
615 int width, int height, float startAngle, float sweepAngle)
617 gdip_pen_setup (graphics, pen);
619 float delta = sweepAngle - startAngle;
622 make_pie (graphics, x, y, width, height, startAngle, sweepAngle);
624 make_pie (graphics, x, y, width, height, startAngle, startAngle + 180);
625 make_pie (graphics, x, y, width, height, startAngle + 180, sweepAngle);
628 cairo_stroke (graphics->ct);
630 cairo_close_path (graphics->ct);
632 return gdip_get_status (cairo_status (graphics->ct));
636 GdipDrawPolygon (GpGraphics *graphics, GpPen *pen, GpPointF *points, int count)
638 gdip_pen_setup (graphics, pen);
640 make_polygon (graphics, points, count);
641 cairo_stroke (graphics->ct);
643 return gdip_get_status (cairo_status (graphics->ct));
647 GdipDrawPolygonI (GpGraphics *graphics, GpPen *pen, GpPoint *points, int count)
649 gdip_pen_setup (graphics, pen);
651 make_polygon_from_integers (graphics, points, count);
652 cairo_stroke (graphics->ct);
654 return gdip_get_status (cairo_status (graphics->ct));
658 GdipDrawRectangle (GpGraphics *graphics, GpPen *pen,
659 float x, float y, float width, float height)
661 gdip_pen_setup (graphics, pen);
663 cairo_rectangle (graphics->ct, x, y, width, height);
664 cairo_stroke (graphics->ct);
666 return gdip_get_status (cairo_status (graphics->ct));
670 GdipDrawRectangleI (GpGraphics *graphics, GpPen *pen,
671 int x, int y, int width, int height)
673 return GdipDrawRectangle (graphics, pen, x, y, width, height);
677 GdipFillEllipse (GpGraphics *graphics, GpBrush *brush,
678 float x, float y, float width, float height)
680 gdip_brush_setup (graphics, brush);
681 make_ellipse (graphics, x, y, width, height);
682 cairo_fill (graphics->ct);
684 return gdip_get_status (cairo_status (graphics->ct));
688 GdipFillEllipseI (GpGraphics *graphics, GpBrush *brush,
689 int x, int y, int width, int height)
691 return GdipFillEllipse (graphics, brush, x, y, width, height);
695 GdipFillRectangle (GpGraphics *graphics, GpBrush *brush,
696 float x, float y, float width, float height)
698 gdip_brush_setup (graphics, brush);
699 cairo_rectangle (graphics->ct, x, y, width, height);
700 cairo_fill (graphics->ct);
701 return gdip_get_status (cairo_status (graphics->ct));
705 GdipFillPolygon (GpGraphics *graphics, GpBrush *brush,
706 GpPointF *points, int count, GpFillMode fillMode)
708 gdip_brush_setup (graphics, brush);
709 make_polygon (graphics, points, count);
711 cairo_set_fill_rule (
713 convert_fill_mode (fillMode));
715 cairo_fill (graphics->ct);
717 return gdip_get_status (cairo_status (graphics->ct));
721 GdipFillPolygonI (GpGraphics *graphics, GpBrush *brush,
722 GpPoint *points, int count, GpFillMode fillMode)
724 gdip_brush_setup (graphics, brush);
725 make_polygon_from_integers (graphics, points, count);
727 cairo_set_fill_rule (
729 convert_fill_mode (fillMode));
731 cairo_fill (graphics->ct);
733 return gdip_get_status (cairo_status (graphics->ct));
737 GdipFillPolygon2 (GpGraphics *graphics, GpBrush *brush, GpPointF *points, int count)
739 return GdipFillPolygon (graphics, brush, points, count, FillModeAlternate);
743 GdipFillPolygon2I (GpGraphics *graphics, GpBrush *brush, GpPoint *points, int count)
745 return GdipFillPolygonI (graphics, brush, points, count, FillModeAlternate);
749 GdipDrawString (GpGraphics *graphics, const char *string,
750 int len, void *font, RectF *rc, void *format, GpBrush *brush)
752 cairo_save (graphics->ct);
754 gdip_brush_setup (graphics, brush);
757 cairo_set_rgb_color (graphics->ct, 0., 0., 0.);
759 cairo_move_to (graphics->ct, rc->left, rc->top + 12);
760 cairo_scale_font (graphics->ct, 12);
761 cairo_show_text (graphics->ct, string);
763 cairo_restore (graphics->ct);
764 return gdip_get_status (cairo_status (graphics->ct));
768 GdipSetRenderingOrigin (GpGraphics *graphics, int x, int y)
770 cairo_move_to (graphics->ct, x, y);
771 cairo_close_path (graphics->ct);
773 return gdip_get_status (cairo_status (graphics->ct));
777 GdipGetRenderingOrigin (GpGraphics *graphics, int *x, int *y)
780 cairo_current_point (graphics->ct, &cx, &cy);
785 return gdip_get_status (cairo_status (graphics->ct));