* graphics.c (DrawBezier, DrawBezierI): Well, it's pretty obvious
[mono.git] / mcs / class / System.Drawing / gdiplus / graphics.c
1 /*
2  * graphics.c
3  *
4  * Copyright (c) 2003 Alexandre Pigolkine, Novell Inc.
5  * 
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:
11  * 
12  * The above copyright notice and this permission notice shall be included in all copies or substantial
13  * portions of the Software.
14  * 
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.
20  * 
21  * Authors:
22  *   Alexandre Pigolkine(pigolkine@gmx.de)
23  *   Duncan Mak (duncan@ximian.com)
24  *
25  */
26
27 #include "gdip.h"
28 #include "gdip_win32.h"
29 #include <math.h>
30
31 void
32 gdip_graphics_init (GpGraphics *graphics)
33 {
34         graphics->ct = cairo_create ();
35         graphics->copy_of_ctm = cairo_matrix_create ();
36         cairo_matrix_set_identity (graphics->copy_of_ctm);
37         graphics->hdc = 0;
38         graphics->hdc_busy_count = 0;
39         graphics->image = 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);
43 }
44
45 GpGraphics *
46 gdip_graphics_new ()
47 {
48         GpGraphics *result = (GpGraphics *) GdipAlloc (sizeof (GpGraphics));
49         gdip_graphics_init (result);
50         return result;
51 }
52
53 void
54 gdip_graphics_attach_bitmap (GpGraphics *graphics, GpBitmap *image)
55 {
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;
60 }
61
62 void 
63 gdip_graphics_detach_bitmap (GpGraphics *graphics, GpBitmap *image)
64 {
65         printf ("Implement graphics_detach_bitmap");
66         /* FIXME: implement me */
67 }
68
69 #define C1 0.552285
70 static void 
71 make_ellipse (GpGraphics *graphics, float x, float y, float width, float height)
72 {
73         double rx = width / 2;
74         double ry = height / 2;
75         double cx = x + rx;
76         double cy = y + ry;
77
78         cairo_move_to (graphics->ct, cx + rx, cy);
79
80         /* an approximate of the ellipse by drawing a curve in each
81          * quartrant */
82         cairo_curve_to (graphics->ct,
83                         cx + rx, cy - C1 * ry,
84                         cx + C1 * rx, cy - ry,
85                         cx, cy - ry);
86         
87         cairo_curve_to (graphics->ct,
88                         cx - C1 * rx, cy - ry,
89                         cx - rx, cy - C1 * ry,
90                         cx - rx, cy);
91
92         cairo_curve_to (graphics->ct,
93                         cx - rx, cy + C1 * ry,
94                         cx - C1 * rx, cy + ry,
95                         cx, cy + ry);
96                 
97         cairo_curve_to (graphics->ct,
98                         cx + C1 * rx, cy + ry,
99                         cx + rx, cy + C1 * ry,
100                         cx + rx, cy);
101
102         cairo_close_path (graphics->ct);
103 }
104
105 static void
106 make_polygon (GpGraphics *graphics, GpPointF *points, int count)
107 {
108         int i;
109         cairo_move_to (graphics->ct, points [0].X, points [0].Y);
110
111         for (i = 0; i < count; i++)
112                 cairo_line_to (graphics->ct, points [i].X, points [i].Y);
113
114         /*
115          * Draw a line from the last point back to the first point if
116          * they're not the same
117          */
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);
120
121         cairo_close_path (graphics->ct);
122 }
123
124 static void
125 make_polygon_from_integers (
126         GpGraphics *graphics, GpPoint *points, int count)
127 {
128         int i;
129         cairo_move_to (graphics->ct, points [0].X, points [0].Y);
130
131         for (i = 0; i < count; i++)
132                 cairo_line_to (graphics->ct, points [i].X, points [i].Y);
133
134         /*
135          * Draw a line from the last point back to the first point if
136          * they're not the same
137          */
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);
140
141         cairo_close_path (graphics->ct);
142 }
143
144 /*
145  * Based on the algorithm described in
146  *      http://www.stillhq.com/ctpfaq/2002/03/c1088.html#AEN1212
147  */
148 static void
149 make_pie (GpGraphics *graphics, float x, float y, 
150           float width, float height, float startAngle, float sweepAngle)
151 {
152         float rx = width / 2;
153         float ry = height / 2;
154         int cx = x + rx;
155         int cy = y + ry;
156
157         /* angles in radians */        
158         float alpha = startAngle * PI / 180;
159         float beta = sweepAngle * PI / 180;
160
161         float delta = beta - alpha;
162         float bcp = 4.0 / 3 * (1 - cos (delta / 2)) / sin (delta /2);
163
164         float sin_alpha = sin (alpha);
165         float sin_beta = sin (beta);
166         float cos_alpha = cos (alpha);
167         float cos_beta = cos (beta);
168
169         /* move to center */
170         cairo_move_to (graphics->ct, cx, cy);
171
172         /* draw pie edge */
173         cairo_line_to (graphics->ct,
174                        cx + rx * cos_alpha, 
175                        cy + ry * sin_alpha);
176         
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),
182                         cx + rx *  cos_beta,
183                         cy + ry *  sin_beta);
184
185         /* draws line back to center */
186         cairo_close_path (graphics->ct);
187 }
188
189 static void
190 make_arc (GpGraphics *graphics, float x, float y, float width,
191                 float height, float startAngle, float sweepAngle)
192 {        
193         float rx = width / 2;
194         float ry = height / 2;
195         
196         /* center */
197         int cx = x + rx;
198         int cy = y + ry;
199
200         /* angles in radians */        
201         float alpha = startAngle * PI / 180;
202         float beta = sweepAngle * PI / 180;
203
204         float delta = beta - alpha;
205         float bcp = 4.0 / 3 * (1 - cos (delta / 2)) / sin (delta /2);
206
207         float sin_alpha = sin (alpha);
208         float sin_beta = sin (beta);
209         float cos_alpha = cos (alpha);
210         float cos_beta = cos (beta);
211
212         /* move to pie edge */
213         cairo_move_to (graphics->ct,
214                        cx + rx * cos_alpha, 
215                        cy + ry * sin_alpha);
216
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),
222                         cx + rx *  cos_beta,
223                         cy + ry *  sin_beta);
224 }
225
226 static cairo_fill_rule_t
227 convert_fill_mode (GpFillMode fill_mode)
228 {
229         if (fill_mode == FillModeAlternate) 
230                 return CAIRO_FILL_RULE_EVEN_ODD;
231         else
232                 return CAIRO_FILL_RULE_WINDING;
233 }
234
235
236 GpStatus 
237 GdipCreateFromHDC (int hDC, GpGraphics **graphics)
238 {
239         DC* dc = _get_DC_by_HDC (hDC);
240         
241         /* printf ("GdipCreateFromHDC. in %d, DC %p\n", hDC, dc); */
242         if (dc == 0) return NotImplemented;
243         
244         *graphics = gdip_graphics_new ();
245         cairo_set_target_drawable ((*graphics)->ct, GDIP_display, dc->physDev->drawable);
246         _release_hdc (hDC);
247         (*graphics)->hdc = (void*)hDC;
248         (*graphics)->type = gtX11Drawable;
249         /* printf ("GdipCreateFromHDC. graphics %p, ct %p\n", (*graphics), (*graphics)->ct); */
250         return Ok;
251 }
252
253 GpStatus 
254 GdipDeleteGraphics (GpGraphics *graphics)
255 {
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);
260         GdipFree (graphics);
261         return Ok;
262 }
263
264 GpStatus 
265 GdipGetDC (GpGraphics *graphics, int *hDC)
266 {
267         if (graphics->hdc == 0) {
268                 if (graphics->image != 0) {
269                         /* Create DC */
270                         graphics->hdc = gdip_image_create_Win32_HDC (graphics->image);
271                         if (graphics->hdc != 0) {
272                                 ++graphics->hdc_busy_count;
273                         }
274                 }
275         }
276         *hDC = (int)graphics->hdc;
277         return Ok;
278 }
279
280 GpStatus 
281 GdipReleaseDC (GpGraphics *graphics, int hDC)
282 {
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) {
287                         /* Destroy DC */
288                         gdip_image_destroy_Win32_HDC (graphics->image, (void*)hDC);
289                         graphics->hdc = 0;
290                 }
291         }
292         return Ok;
293 }
294
295 #define MAX_GRAPHICS_STATE_STACK 100
296
297 GpState saved_stack [MAX_GRAPHICS_STATE_STACK];
298 int current_stack_pos = 0;
299
300 GpStatus 
301 GdipRestoreGraphics (GpGraphics *graphics, unsigned int graphicsState)
302 {
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);
306         }
307         else {
308                 return InvalidParameter;
309         }
310         return Ok;
311 }
312
313 GpStatus 
314 GdipSaveGraphics(GpGraphics *graphics, unsigned int *state)
315 {
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;
320                 ++current_stack_pos;
321         }
322         else {
323                 return OutOfMemory;
324         }
325         return Ok;
326 }
327 GpStatus
328 GdipResetWorldTransform (GpGraphics *graphics)
329 {
330         GpStatus s = cairo_matrix_set_identity (graphics->copy_of_ctm);
331
332         if (s != Ok)
333                 return s;
334         else {
335                 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
336                 return Ok;
337         }
338 }
339
340 GpStatus
341 GdipSetWorldTransform (GpGraphics *graphics, GpMatrix *matrix)
342 {
343         graphics->copy_of_ctm = matrix;
344         cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
345         return Ok;
346 }
347
348 GpStatus 
349 GdipGetWorldTransform (GpGraphics *graphics, GpMatrix *matrix)
350 {
351         cairo_current_matrix (graphics->ct, matrix);
352         return Ok;
353 }
354
355 GpStatus
356 GdipMultiplyWorldTransform (GpGraphics *graphics, GpMatrix *matrix, GpMatrixOrder order)
357 {
358         Status s = GdipMultiplyMatrix (graphics->copy_of_ctm, matrix, order);
359         
360         if (s != Ok)
361                 return s;
362
363         else {
364                 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
365                 return Ok;
366         }
367 }
368
369 GpStatus 
370 GdipRotateWorldTransform (GpGraphics *graphics, float angle, GpMatrixOrder order)
371 {
372         GpStatus s = GdipRotateMatrix (graphics->copy_of_ctm, angle, order);
373
374         if (s != Ok)
375                 return s;
376         else {
377                 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
378                 return Ok;
379         }
380 }
381
382 GpStatus 
383 GdipTranslateWorldTransform (GpGraphics *graphics, float dx, float dy, GpMatrixOrder order)
384 {
385         GpStatus s = GdipTranslateMatrix (graphics->copy_of_ctm, dx, dy, order);
386
387         if (s != Ok) 
388                 return s;
389         else {
390                 cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
391                 return Ok;
392         }
393 }
394
395 GpStatus
396 GdipDrawArc (GpGraphics *graphics, GpPen *pen, 
397                 float x, float y, float width, float height, 
398                 float startAngle, float sweepAngle)
399 {
400         gdip_pen_setup (graphics, pen);
401
402         float delta = sweepAngle - startAngle;
403
404         if (delta < 180)
405                 make_arc (graphics, x, y, width, height, startAngle, sweepAngle);
406
407         else {
408                 make_arc (graphics, x, y, width, height, startAngle, startAngle + 180);
409                 make_arc (graphics, x, y, width, height, startAngle + 180, sweepAngle);
410         }
411
412         cairo_stroke (graphics->ct);
413
414         return gdip_get_status (cairo_status (graphics->ct));
415 }
416
417 GpStatus
418 GdipDrawArcI (GpGraphics *graphics, GpPen *pen, 
419                 int x, int y, int width, int height, 
420                 float startAngle, float sweepAngle)
421 {
422         gdip_pen_setup (graphics, pen);
423
424         float delta = sweepAngle - startAngle;
425
426         if (delta < 180)
427                 make_arc (graphics, x, y, width, height, startAngle, sweepAngle);
428
429         else {
430                 make_arc (graphics, x, y, width, height, startAngle, startAngle + 180);
431                 make_arc (graphics, x, y, width, height, startAngle + 180, sweepAngle);
432         }
433
434         cairo_stroke (graphics->ct);
435
436         return gdip_get_status (cairo_status (graphics->ct));
437 }
438
439 GpStatus 
440 GdipDrawBezier (GpGraphics *graphics, GpPen *pen, 
441                 float x1, float y1, float x2, float y2,
442                 float x3, float y3, float x4, float y4)
443 {
444         gdip_pen_setup (graphics, pen);        
445         
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);
449
450         return gdip_get_status (cairo_status (graphics->ct));
451 }
452
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)
456 {
457         return GdipDrawBezier (graphics, pen,
458                         x1, y1, x2, y2, x3, y3, x4, y4);
459 }
460
461 GpStatus 
462 GdipDrawBeziers (GpGraphics *graphics, GpPen *pen,
463                 GpPointF *points, int count)
464 {
465         int i, j, k;
466         
467         if (count == 0)
468                 return Ok;
469
470         gdip_pen_setup (graphics, pen);
471         
472         cairo_move_to (graphics->ct, points [0].X, points [0].Y);
473
474         for (i = 0; i < count - 3; i += 3) {
475                 j = i + 1;
476                 k = i + 2;
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);
481         }
482
483         cairo_stroke (graphics->ct);
484
485         return gdip_get_status (cairo_status (graphics->ct));
486 }
487
488 GpStatus
489 GdipDrawBeziersI (GpGraphics *graphics, GpPen *pen,
490                 GpPoint *points, int count)
491 {
492         int i, j, k;
493         
494         if (count == 0)
495                 return Ok;
496
497         gdip_pen_setup (graphics, pen);
498
499         cairo_move_to (graphics->ct, points [0].X, points [0].Y);
500
501         for (i = 0; i < count - 3; i += 3) {
502                 j = i + 1;
503                 k = i + 2;
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);
508         }
509
510         cairo_stroke (graphics->ct);
511
512         return gdip_get_status (cairo_status (graphics->ct));
513 }
514
515 GpStatus 
516 GdipDrawEllipse (GpGraphics *graphics, GpPen *pen, 
517                 float x, float y, float width, float height)
518 {
519         gdip_pen_setup (graphics, pen);
520         
521         make_ellipse (graphics, x, y, width, height);
522         cairo_stroke (graphics->ct);
523
524         return gdip_get_status (cairo_status (graphics->ct));
525 }
526
527 GpStatus
528 GdipDrawEllipseI (GpGraphics *graphics, GpPen *pen,
529                 int x, int y, int width, int height)
530 {
531         return GdipDrawEllipse (graphics, pen, x, y, width, height);
532 }
533
534 GpStatus
535 GdipDrawLine (GpGraphics *graphics, GpPen *pen,
536                 float x1, float y1, float x2, float y2)
537 {
538         gdip_pen_setup (graphics, pen);
539
540         cairo_move_to (graphics->ct, x1, y1);
541         cairo_line_to (graphics->ct, x2, y2);
542         cairo_stroke (graphics->ct);
543
544         return gdip_get_status (cairo_status (graphics->ct));
545 }
546
547 GpStatus 
548 GdipDrawLineI (GpGraphics *graphics, GpPen *pen, 
549                 int x1, int y1, int x2, int y2)
550 {
551         return GdipDrawLine (graphics, pen, x1, y1, x2, y2);
552 }
553
554 GpStatus 
555 GdipDrawLines (GpGraphics *graphics, GpPen *pen, GpPointF *points, int count)
556 {
557         GpStatus s;
558         int i, j;
559
560         for (i = 0; i < count - 1; i++) {
561                 j = i + 1;
562                 s = GdipDrawLine (graphics, pen, 
563                                 points [i].X, points [i].Y,
564                                 points [j].X, points [j].Y);
565
566                 if (s != Ok) return s;
567         }
568
569         return gdip_get_status (cairo_status (graphics->ct));
570 }
571
572 GpStatus 
573 GdipDrawLinesI (GpGraphics *graphics, GpPen *pen,
574                 GpPoint *points, int count)
575 {
576         GpStatus s;
577         int i, j;
578
579         for (i = 0; i < count - 1; i++) {
580                 j = i + 1;
581                 s = GdipDrawLineI (graphics, pen, 
582                                 points [i].X, points [i].Y,
583                                 points [j].X, points [j].Y);
584
585                 if (s != Ok) return s;
586         }
587
588         return Ok;
589 }
590
591 GpStatus
592 GdipDrawPie (GpGraphics *graphics, GpPen *pen, float x, float y, 
593                 float width, float height, float startAngle, float sweepAngle)
594 {
595         gdip_pen_setup (graphics, pen);
596
597         float delta = sweepAngle - startAngle;
598
599         if (delta < 180)
600                 make_pie (graphics, x, y, width, height, startAngle, sweepAngle);
601         else {
602                 make_pie (graphics, x, y, width, height, startAngle, startAngle + 180);
603                 make_pie (graphics, x, y, width, height, startAngle + 180, sweepAngle);
604         }
605
606         cairo_stroke (graphics->ct);
607
608         cairo_close_path (graphics->ct);
609
610         return gdip_get_status (cairo_status (graphics->ct));
611 }
612
613 GpStatus
614 GdipDrawPieI (GpGraphics *graphics, GpPen *pen, int x, int y, 
615                 int width, int height, float startAngle, float sweepAngle)
616 {
617         gdip_pen_setup (graphics, pen);
618         
619         float delta = sweepAngle - startAngle;
620         
621         if (delta < 180)
622                 make_pie (graphics, x, y, width, height, startAngle, sweepAngle);
623         else {
624                 make_pie (graphics, x, y, width, height, startAngle, startAngle + 180);
625                 make_pie (graphics, x, y, width, height, startAngle + 180, sweepAngle);
626         }
627
628         cairo_stroke (graphics->ct);
629
630         cairo_close_path (graphics->ct);
631
632         return gdip_get_status (cairo_status (graphics->ct));
633 }
634
635 GpStatus
636 GdipDrawPolygon (GpGraphics *graphics, GpPen *pen, GpPointF *points, int count)
637 {
638         gdip_pen_setup (graphics, pen);
639         
640         make_polygon (graphics, points, count);
641         cairo_stroke (graphics->ct);
642
643         return gdip_get_status (cairo_status (graphics->ct));
644 }
645
646 GpStatus
647 GdipDrawPolygonI (GpGraphics *graphics, GpPen *pen, GpPoint *points, int count)
648 {
649         gdip_pen_setup (graphics, pen);
650         
651         make_polygon_from_integers (graphics, points, count);
652         cairo_stroke (graphics->ct);
653
654         return gdip_get_status (cairo_status (graphics->ct));
655 }
656
657 GpStatus
658 GdipDrawRectangle (GpGraphics *graphics, GpPen *pen,
659                 float x, float y, float width, float height)
660 {
661         gdip_pen_setup (graphics, pen);
662
663         cairo_rectangle (graphics->ct, x, y, width, height);
664         cairo_stroke (graphics->ct);
665
666         return gdip_get_status (cairo_status (graphics->ct));
667 }
668
669 GpStatus
670 GdipDrawRectangleI (GpGraphics *graphics, GpPen *pen,
671                 int x, int y, int width, int height)
672 {
673         return GdipDrawRectangle (graphics, pen, x, y, width, height);
674 }
675
676 GpStatus
677 GdipFillEllipse (GpGraphics *graphics, GpBrush *brush,
678                 float x, float y, float width, float height)
679 {
680         gdip_brush_setup (graphics, brush);
681         make_ellipse (graphics, x, y, width, height);
682         cairo_fill (graphics->ct);
683
684         return gdip_get_status (cairo_status (graphics->ct));
685 }
686
687 GpStatus
688 GdipFillEllipseI (GpGraphics *graphics, GpBrush *brush,
689                 int x, int y, int width, int height)
690 {
691         return GdipFillEllipse (graphics, brush, x, y, width, height);
692 }
693
694 GpStatus 
695 GdipFillRectangle (GpGraphics *graphics, GpBrush *brush, 
696                 float x, float y, float width, float height)
697 {
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));
702 }
703
704 GpStatus
705 GdipFillPolygon (GpGraphics *graphics, GpBrush *brush, 
706                 GpPointF *points, int count, GpFillMode fillMode)
707 {
708         gdip_brush_setup (graphics, brush);
709         make_polygon (graphics, points, count);
710
711         cairo_set_fill_rule (
712                 graphics->ct,
713                 convert_fill_mode (fillMode));
714
715         cairo_fill (graphics->ct);
716
717         return gdip_get_status (cairo_status (graphics->ct));
718 }
719
720 GpStatus
721 GdipFillPolygonI (GpGraphics *graphics, GpBrush *brush, 
722                 GpPoint *points, int count, GpFillMode fillMode)
723 {
724         gdip_brush_setup (graphics, brush);
725         make_polygon_from_integers (graphics, points, count);
726
727         cairo_set_fill_rule (
728                 graphics->ct,
729                 convert_fill_mode (fillMode));
730         
731         cairo_fill (graphics->ct);
732
733         return gdip_get_status (cairo_status (graphics->ct));
734 }
735
736 GpStatus
737 GdipFillPolygon2 (GpGraphics *graphics, GpBrush *brush, GpPointF *points, int count)
738 {
739         return GdipFillPolygon (graphics, brush, points, count, FillModeAlternate);
740 }
741
742 GpStatus
743 GdipFillPolygon2I (GpGraphics *graphics, GpBrush *brush, GpPoint *points, int count)
744 {
745         return GdipFillPolygonI (graphics, brush, points, count, FillModeAlternate);
746 }
747
748 GpStatus 
749 GdipDrawString (GpGraphics *graphics, const char *string,
750                 int len, void *font, RectF *rc, void *format, GpBrush *brush)
751 {
752         cairo_save (graphics->ct);
753         if (brush)
754                 gdip_brush_setup (graphics, brush);
755
756         else
757                 cairo_set_rgb_color (graphics->ct, 0., 0., 0.);
758
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);
762
763         cairo_restore (graphics->ct);        
764         return gdip_get_status (cairo_status (graphics->ct));
765 }
766
767 GpStatus 
768 GdipSetRenderingOrigin (GpGraphics *graphics, int x, int y)
769 {
770         cairo_move_to (graphics->ct, x, y);
771         cairo_close_path (graphics->ct);
772
773         return gdip_get_status (cairo_status (graphics->ct));
774 }
775
776 GpStatus 
777 GdipGetRenderingOrigin (GpGraphics *graphics, int *x, int *y)
778 {
779         double cx, cy;
780         cairo_current_point (graphics->ct, &cx, &cy);
781
782         *x = (int) cx;
783         *y = (int) cy;
784
785         return gdip_get_status (cairo_status (graphics->ct));
786 }
787