Changed link from GUID to URL
[mono.git] / mcs / class / Mono.Cairo / Mono.Cairo / Context.cs
1 //
2 // Mono.Cairo.Context.cs
3 //
4 // Author:
5 //   Duncan Mak (duncan@ximian.com)
6 //   Miguel de Icaza (miguel@novell.com)
7 //   Hisham Mardam Bey (hisham.mardambey@gmail.com)
8 //   Alp Toker (alp@atoker.com)
9 //
10 // (C) Ximian Inc, 2003.
11 // (C) Novell Inc, 2003.
12 //
13 // This is an OO wrapper API for the Cairo API.
14 //
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 //
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 //
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Runtime.InteropServices;
39 using System.Text;
40 using Cairo;
41
42 namespace Cairo {
43
44         [Obsolete ("Renamed Cairo.Context per suggestion from cairo binding guidelines.")]
45         public class Graphics : Context {
46                 public Graphics (IntPtr state) : base (state) {}
47                 public Graphics (Surface surface) : base (surface) {}
48         }
49
50         public class Context : IDisposable
51         {
52                 IntPtr handle = IntPtr.Zero;
53
54                 static int native_glyph_size, c_compiler_long_size;
55
56                 static Context ()
57                 {
58                         //
59                         // This is used to determine what kind of structure
60                         // we should use to marshal Glyphs, as the public
61                         // definition in Cairo uses `long', which can be
62                         // 32 bits or 64 bits depending on the platform.
63                         //
64                         // We assume that sizeof(long) == sizeof(void*)
65                         // except in the case of Win64 where sizeof(long)
66                         // is 32 bits
67                         //
68                         int ptr_size = Marshal.SizeOf (typeof (IntPtr));
69
70                         PlatformID platform = Environment.OSVersion.Platform;
71                         if (platform == PlatformID.Win32NT ||
72                             platform == PlatformID.Win32S ||
73                             platform == PlatformID.Win32Windows ||
74                             platform == PlatformID.WinCE ||
75                             ptr_size == 4){
76                                 c_compiler_long_size = 4;
77                                 native_glyph_size = Marshal.SizeOf (typeof (NativeGlyph_4byte_longs));
78                         } else {
79                                 c_compiler_long_size = 8;
80                                 native_glyph_size = Marshal.SizeOf (typeof (Glyph));
81                         }
82                 }
83
84                 public Context (Surface surface) : this (NativeMethods.cairo_create (surface.Handle), true)
85                 {
86                 }
87
88
89                 public Context (IntPtr handle, bool owner)
90                 {
91                         this.handle = handle;
92                         if (!owner)
93                                 NativeMethods.cairo_reference (handle);
94                         if (CairoDebug.Enabled)
95                                 CairoDebug.OnAllocated (handle);
96                 }
97
98                 [Obsolete]
99                 public Context (IntPtr state) : this (state, true)
100                 {
101                 }
102
103                 ~Context ()
104                 {
105                         Dispose (false);
106                 }
107
108                 public void Dispose ()
109                 {
110                         Dispose (true);
111                         GC.SuppressFinalize (this);
112                 }
113
114                 protected virtual void Dispose (bool disposing)
115                 {
116                         if (!disposing || CairoDebug.Enabled)
117                                 CairoDebug.OnDisposed<Context> (handle, disposing);
118
119                         if (!disposing|| handle == IntPtr.Zero)
120                                 return;
121
122                         NativeMethods.cairo_destroy (handle);
123                         handle = IntPtr.Zero;
124
125                 }
126
127                 public void Save ()
128                 {
129                         NativeMethods.cairo_save (handle);
130                 }
131
132                 public void Restore ()
133                 {
134                         NativeMethods.cairo_restore (handle);
135                 }
136
137                 public Antialias Antialias {
138                         get { return NativeMethods.cairo_get_antialias (handle); }
139                         set { NativeMethods.cairo_set_antialias (handle, value); }
140                 }
141
142                 public Cairo.Status Status {
143                         get {
144                                 return NativeMethods.cairo_status (handle);
145                         }
146                 }
147
148                 public IntPtr Handle {
149                         get {
150                                 return handle;
151                         }
152                 }
153
154                 public Operator Operator {
155                         set {
156                                 NativeMethods.cairo_set_operator (handle, value);
157                         }
158
159                         get {
160                                 return NativeMethods.cairo_get_operator (handle);
161                         }
162                 }
163
164                 [Obsolete ("Use SetSourceColor method")]
165                 public Color Color {
166                         set {
167                                 SetSourceColor (value);
168                         }
169                 }
170
171                 [Obsolete ("Use SetSourceRGBA method")]
172                 public Cairo.Color ColorRgb {
173                         set {
174                                 Color = new Color (value.R, value.G, value.B);
175                         }
176                 }
177
178                 public double Tolerance {
179                         get {
180                                 return NativeMethods.cairo_get_tolerance (handle);
181                         }
182
183                         set {
184                                 NativeMethods.cairo_set_tolerance (handle, value);
185                         }
186                 }
187
188                 public Cairo.FillRule FillRule {
189                         set {
190                                 NativeMethods.cairo_set_fill_rule (handle, value);
191                         }
192
193                         get {
194                                 return NativeMethods.cairo_get_fill_rule (handle);
195                         }
196                 }
197
198                 public double LineWidth {
199                         set {
200                                 NativeMethods.cairo_set_line_width (handle, value);
201                         }
202
203                         get {
204                                 return NativeMethods.cairo_get_line_width (handle);
205                         }
206                 }
207
208                 public Cairo.LineCap LineCap {
209                         set {
210                                 NativeMethods.cairo_set_line_cap (handle, value);
211                         }
212
213                         get {
214                                 return NativeMethods.cairo_get_line_cap (handle);
215                         }
216                 }
217
218                 public Cairo.LineJoin LineJoin {
219                         set {
220                                 NativeMethods.cairo_set_line_join (handle, value);
221                         }
222
223                         get {
224                                 return NativeMethods.cairo_get_line_join (handle);
225                         }
226                 }
227
228                 public void SetDash (double [] dashes, double offset)
229                 {
230                         NativeMethods.cairo_set_dash (handle, dashes, dashes.Length, offset);
231                 }
232
233                 [Obsolete("Use GetSource/GetSource")]
234                 public Pattern Pattern {
235                         set {
236                                 SetSource (value);
237                         }
238                         get {
239                                 return GetSource ();
240                         }
241                 }
242
243                 //This is obsolete because it wasn't obvious it needed to be disposed
244                 [Obsolete("Use GetSource/GetSource")]
245                 public Pattern Source {
246                         set {
247                                 SetSource (value);
248                         }
249                         get {
250                                 return GetSource ();
251                         }
252                 }
253
254                 public void SetSource (Pattern source)
255                 {
256                         NativeMethods.cairo_set_source (handle, source.Handle);
257                 }
258
259                 public Pattern GetSource ()
260                 {
261                         var ptr = NativeMethods.cairo_get_source (handle);
262                         return Cairo.Pattern.Lookup (ptr, false);
263                 }
264
265                 public double MiterLimit {
266                         set {
267                                 NativeMethods.cairo_set_miter_limit (handle, value);
268                         }
269
270                         get {
271                                 return NativeMethods.cairo_get_miter_limit (handle);
272                         }
273                 }
274
275                 public PointD CurrentPoint {
276                         get {
277                                 double x, y;
278                                 NativeMethods.cairo_get_current_point (handle, out x, out y);
279                                 return new PointD (x, y);
280                         }
281                 }
282
283                 public bool HasCurrentPoint {
284                         get {
285                                 return NativeMethods.cairo_has_current_point (handle);
286                         }
287                 }
288
289                 [Obsolete ("Use GetTarget/SetTarget")]
290                 public Cairo.Surface Target {
291                         set {
292                                 if (handle != IntPtr.Zero)
293                                         NativeMethods.cairo_destroy (handle);
294
295                                 handle = NativeMethods.cairo_create (value.Handle);
296                         }
297
298                         get {
299                                 return GetTarget ();
300                         }
301                 }
302
303                 public Surface GetTarget ()
304                 {
305                         return Surface.Lookup (NativeMethods.cairo_get_target (handle), false);
306                 }
307
308                 public void SetTarget (Surface target)
309                 {
310                         if (handle != IntPtr.Zero)
311                                 NativeMethods.cairo_destroy (handle);
312                         handle = NativeMethods.cairo_create (target.Handle);
313                 }
314
315                 [Obsolete("Use GetScaledFont/SetScaledFont")]
316                 public ScaledFont ScaledFont {
317                         set {
318                                 SetScaledFont (value);
319                         }
320
321                         get {
322                                 return GetScaledFont ();
323                         }
324                 }
325
326                 public ScaledFont GetScaledFont ()
327                 {
328                         return new ScaledFont (NativeMethods.cairo_get_scaled_font (handle), false);
329                 }
330
331                 public void SetScaledFont (ScaledFont font)
332                 {
333                         NativeMethods.cairo_set_scaled_font (handle, font.Handle);
334                 }
335
336                 public uint ReferenceCount {
337                         get { return NativeMethods.cairo_get_reference_count (handle); }
338                 }
339
340                 public void SetSourceColor (Color color)
341                 {
342                         NativeMethods.cairo_set_source_rgba (handle, color.R, color.G, color.B, color.A);
343                 }
344
345                 public void SetSourceRGB (double r, double g, double b)
346                 {
347                         NativeMethods.cairo_set_source_rgb (handle, r, g, b);
348                 }
349
350                 public void SetSourceRGBA (double r, double g, double b, double a)
351                 {
352                         NativeMethods.cairo_set_source_rgba (handle, r, g, b, a);
353                 }
354
355                 //[Obsolete ("Use SetSource method (with double parameters)")]
356                 public void SetSourceSurface (Surface source, int x, int y)
357                 {
358                         NativeMethods.cairo_set_source_surface (handle, source.Handle, x, y);
359                 }
360
361                 public void SetSource (Surface source, double x, double y)
362                 {
363                         NativeMethods.cairo_set_source_surface (handle, source.Handle, x, y);
364                 }
365
366                 public void SetSource (Surface source)
367                 {
368                         NativeMethods.cairo_set_source_surface (handle, source.Handle, 0, 0);
369                 }
370
371 #region Path methods
372
373                 public void NewPath ()
374                 {
375                         NativeMethods.cairo_new_path (handle);
376                 }
377
378                 public void NewSubPath ()
379                 {
380                         NativeMethods.cairo_new_sub_path (handle);
381                 }
382
383                 public void MoveTo (PointD p)
384                 {
385                         MoveTo (p.X, p.Y);
386                 }
387
388                 public void MoveTo (double x, double y)
389                 {
390                         NativeMethods.cairo_move_to (handle, x, y);
391                 }
392
393                 public void LineTo (PointD p)
394                 {
395                         LineTo (p.X, p.Y);
396                 }
397
398                 public void LineTo (double x, double y)
399                 {
400                         NativeMethods.cairo_line_to (handle, x, y);
401                 }
402
403                 public void CurveTo (PointD p1, PointD p2, PointD p3)
404                 {
405                         CurveTo (p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y);
406                 }
407
408                 public void CurveTo (double x1, double y1, double x2, double y2, double x3, double y3)
409                 {
410                         NativeMethods.cairo_curve_to (handle, x1, y1, x2, y2, x3, y3);
411                 }
412
413                 public void RelMoveTo (Distance d)
414                 {
415                         RelMoveTo (d.Dx, d.Dy);
416                 }
417
418                 public void RelMoveTo (double dx, double dy)
419                 {
420                         NativeMethods.cairo_rel_move_to (handle, dx, dy);
421                 }
422
423                 public void RelLineTo (Distance d)
424                 {
425                         RelLineTo (d.Dx, d.Dy);
426                 }
427
428                 public void RelLineTo (double dx, double dy)
429                 {
430                         NativeMethods.cairo_rel_line_to (handle, dx, dy);
431                 }
432
433                 public void RelCurveTo (Distance d1, Distance d2, Distance d3)
434                 {
435                         RelCurveTo (d1.Dx, d1.Dy, d2.Dx, d2.Dy, d3.Dx, d3.Dy);
436                 }
437
438                 public void RelCurveTo (double dx1, double dy1, double dx2, double dy2, double dx3, double dy3)
439                 {
440                         NativeMethods.cairo_rel_curve_to (handle, dx1, dy1, dx2, dy2, dx3, dy3);
441                 }
442
443                 public void Arc (double xc, double yc, double radius, double angle1, double angle2)
444                 {
445                         NativeMethods.cairo_arc (handle, xc, yc, radius, angle1, angle2);
446                 }
447
448                 public void ArcNegative (double xc, double yc, double radius, double angle1, double angle2)
449                 {
450                         NativeMethods.cairo_arc_negative (handle, xc, yc, radius, angle1, angle2);
451                 }
452
453                 public void Rectangle (Rectangle rectangle)
454                 {
455                         Rectangle (rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
456                 }
457
458                 public void Rectangle (PointD p, double width, double height)
459                 {
460                         Rectangle (p.X, p.Y, width, height);
461                 }
462
463                 public void Rectangle (double x, double y, double width, double height)
464                 {
465                         NativeMethods.cairo_rectangle (handle, x, y, width, height);
466                 }
467
468                 public void ClosePath ()
469                 {
470                         NativeMethods.cairo_close_path (handle);
471                 }
472
473                 public Path CopyPath ()
474                 {
475                         return new Path (NativeMethods.cairo_copy_path (handle));
476                 }
477
478                 public Path CopyPathFlat ()
479                 {
480                         return new Path (NativeMethods.cairo_copy_path_flat (handle));
481                 }
482
483                 public void AppendPath (Path path)
484                 {
485                         NativeMethods.cairo_append_path (handle, path.Handle);
486                 }
487
488 #endregion
489
490 #region Painting Methods
491                 public void Paint ()
492                 {
493                         NativeMethods.cairo_paint (handle);
494                 }
495
496                 public void PaintWithAlpha (double alpha)
497                 {
498                         NativeMethods.cairo_paint_with_alpha (handle, alpha);
499                 }
500
501                 public void Mask (Pattern pattern)
502                 {
503                         NativeMethods.cairo_mask (handle, pattern.Handle);
504                 }
505
506                 public void MaskSurface (Surface surface, double surface_x, double surface_y)
507                 {
508                         NativeMethods.cairo_mask_surface (handle, surface.Handle, surface_x, surface_y);
509                 }
510
511                 public void Stroke ()
512                 {
513                         NativeMethods.cairo_stroke (handle);
514                 }
515
516                 public void StrokePreserve ()
517                 {
518                         NativeMethods.cairo_stroke_preserve (handle);
519                 }
520
521                 public Rectangle StrokeExtents ()
522                 {
523                         double x1, y1, x2, y2;
524                         NativeMethods.cairo_stroke_extents (handle, out x1, out y1, out x2, out y2);
525                         return new Rectangle (x1, y1, x2 - x1, y2 - y1);
526                 }
527
528                 public void Fill ()
529                 {
530                         NativeMethods.cairo_fill (handle);
531                 }
532
533                 public Rectangle FillExtents ()
534                 {
535                         double x1, y1, x2, y2;
536                         NativeMethods.cairo_fill_extents (handle, out x1, out y1, out x2, out y2);
537                         return new Rectangle (x1, y1, x2 - x1, y2 - y1);
538                 }
539
540                 public void FillPreserve ()
541                 {
542                         NativeMethods.cairo_fill_preserve (handle);
543                 }
544
545 #endregion
546
547                 public void Clip ()
548                 {
549                         NativeMethods.cairo_clip (handle);
550                 }
551
552                 public void ClipPreserve ()
553                 {
554                         NativeMethods.cairo_clip_preserve (handle);
555                 }
556
557                 public void ResetClip ()
558                 {
559                         NativeMethods.cairo_reset_clip (handle);
560                 }
561
562                 public bool InClip (double x, double y)
563                 {
564                         return NativeMethods.cairo_in_clip (handle, x, y);
565                 }
566
567                 public bool InStroke (double x, double y)
568                 {
569                         return NativeMethods.cairo_in_stroke (handle, x, y);
570                 }
571
572                 public bool InFill (double x, double y)
573                 {
574                         return NativeMethods.cairo_in_fill (handle, x, y);
575                 }
576
577                 public Pattern PopGroup ()
578                 {
579                         return Pattern.Lookup (NativeMethods.cairo_pop_group (handle), true);
580                 }
581
582                 public void PopGroupToSource ()
583                 {
584                         NativeMethods.cairo_pop_group_to_source (handle);
585                 }
586
587                 public void PushGroup ()
588                 {
589                         NativeMethods.cairo_push_group (handle);
590                 }
591
592                 public void PushGroup (Content content)
593                 {
594                         NativeMethods.cairo_push_group_with_content (handle, content);
595                 }
596
597                 [Obsolete ("Use GetGroupTarget()")]
598                 public Surface GroupTarget {
599                         get {
600                                 return GetGroupTarget ();
601                         }
602                 }
603
604                 public Surface GetGroupTarget ()
605                 {
606                         IntPtr surface = NativeMethods.cairo_get_group_target (handle);
607                         return Surface.Lookup (surface, false);
608                 }
609
610                 public void Rotate (double angle)
611                 {
612                         NativeMethods.cairo_rotate (handle, angle);
613                 }
614
615                 public void Scale (double sx, double sy)
616                 {
617                         NativeMethods.cairo_scale (handle, sx, sy);
618                 }
619
620                 public void Translate (double tx, double ty)
621                 {
622                         NativeMethods.cairo_translate (handle, tx, ty);
623                 }
624
625                 public void Transform (Matrix m)
626                 {
627                         NativeMethods.cairo_transform (handle, m);
628                 }
629
630                 [Obsolete("Use UserToDevice instead")]
631                 public void TransformPoint (ref double x, ref double y)
632                 {
633                         NativeMethods.cairo_user_to_device (handle, ref x, ref y);
634                 }
635
636                 [Obsolete("Use UserToDeviceDistance instead")]
637                 public void TransformDistance (ref double dx, ref double dy)
638                 {
639                         NativeMethods.cairo_user_to_device_distance (handle, ref dx, ref dy);
640                 }
641
642                 [Obsolete("Use InverseTransformPoint instead")]
643                 public void InverseTransformPoint (ref double x, ref double y)
644                 {
645                         NativeMethods.cairo_device_to_user (handle, ref x, ref y);
646                 }
647
648                 [Obsolete("Use DeviceToUserDistance instead")]
649                 public void InverseTransformDistance (ref double dx, ref double dy)
650                 {
651                         NativeMethods.cairo_device_to_user_distance (handle, ref dx, ref dy);
652                 }
653
654                 public void UserToDevice (ref double x, ref double y)
655                 {
656                         NativeMethods.cairo_user_to_device (handle, ref x, ref y);
657                 }
658
659                 public void UserToDeviceDistance (ref double dx, ref double dy)
660                 {
661                         NativeMethods.cairo_user_to_device_distance (handle, ref dx, ref dy);
662                 }
663
664                 public void DeviceToUser (ref double x, ref double y)
665                 {
666                         NativeMethods.cairo_device_to_user (handle, ref x, ref y);
667                 }
668
669                 public void DeviceToUserDistance (ref double dx, ref double dy)
670                 {
671                         NativeMethods.cairo_device_to_user_distance (handle, ref dx, ref dy);
672                 }
673
674                 public Matrix Matrix {
675                         set {
676                                 NativeMethods.cairo_set_matrix (handle, value);
677                         }
678
679                         get {
680                                 Matrix m = new Matrix();
681                                 NativeMethods.cairo_get_matrix (handle, m);
682                                 return m;
683                         }
684                 }
685
686                 public void SetFontSize (double scale)
687                 {
688                         NativeMethods.cairo_set_font_size (handle, scale);
689                 }
690
691                 public void IdentityMatrix ()
692                 {
693                         NativeMethods.cairo_identity_matrix (handle);
694                 }
695
696                 [Obsolete ("Use SetFontSize() instead.")]
697                 public void FontSetSize (double scale)
698                 {
699                         SetFontSize (scale);
700                 }
701
702                 [Obsolete ("Use SetFontSize() instead.")]
703                 public double FontSize {
704                         set { SetFontSize (value); }
705                 }
706
707                 public Matrix FontMatrix {
708                         get {
709                                 Matrix m;
710                                 NativeMethods.cairo_get_font_matrix (handle, out m);
711                                 return m;
712                         }
713                         set { NativeMethods.cairo_set_font_matrix (handle, value); }
714                 }
715
716                 public FontOptions FontOptions {
717                         get {
718                                 FontOptions options = new FontOptions ();
719                                 NativeMethods.cairo_get_font_options (handle, options.Handle);
720                                 return options;
721                         }
722                         set { NativeMethods.cairo_set_font_options (handle, value.Handle); }
723                 }
724
725                 [StructLayout(LayoutKind.Sequential)]
726                 internal struct NativeGlyph_4byte_longs {
727                         public int index;
728                         public double x;
729                         public double y;
730
731                         public NativeGlyph_4byte_longs (Glyph source)
732                         {
733                                 index = (int) source.index;
734                                 x = source.x;
735                                 y = source.y;
736                         }
737                 }
738
739                 static internal IntPtr FromGlyphToUnManagedMemory(Glyph [] glyphs)
740                 {
741                         IntPtr dest = Marshal.AllocHGlobal (native_glyph_size * glyphs.Length);
742                         long pos = dest.ToInt64();
743
744                         if (c_compiler_long_size == 8){
745                                 foreach (Glyph g in glyphs){
746                                         Marshal.StructureToPtr (g, (IntPtr)pos, false);
747                                         pos += native_glyph_size;
748                                 }
749                         } else {
750                                 foreach (Glyph g in glyphs){
751                                         NativeGlyph_4byte_longs n = new NativeGlyph_4byte_longs (g);
752
753                                         Marshal.StructureToPtr (n, (IntPtr)pos, false);
754                                         pos += native_glyph_size;
755                                 }
756                         }
757
758                         return dest;
759                 }
760
761                 public void ShowGlyphs (Glyph[] glyphs)
762                 {
763                         IntPtr ptr;
764
765                         ptr = FromGlyphToUnManagedMemory (glyphs);
766
767                         NativeMethods.cairo_show_glyphs (handle, ptr, glyphs.Length);
768
769                         Marshal.FreeHGlobal (ptr);
770                 }
771
772                 [Obsolete("The matrix argument was never used, use ShowGlyphs(Glyphs []) instead")]
773                 public void ShowGlyphs (Matrix matrix, Glyph[] glyphs)
774                 {
775                         ShowGlyphs (glyphs);
776                 }
777
778                 [Obsolete("The matrix argument was never used, use GlyphPath(Glyphs []) instead")]
779                 public void GlyphPath (Matrix matrix, Glyph[] glyphs)
780                 {
781                         GlyphPath (glyphs);
782                 }
783
784                 public void GlyphPath (Glyph[] glyphs)
785                 {
786                         IntPtr ptr;
787
788                         ptr = FromGlyphToUnManagedMemory (glyphs);
789
790                         NativeMethods.cairo_glyph_path (handle, ptr, glyphs.Length);
791
792                         Marshal.FreeHGlobal (ptr);
793
794                 }
795
796                 public FontExtents FontExtents {
797                         get {
798                                 FontExtents f_extents;
799                                 NativeMethods.cairo_font_extents (handle, out f_extents);
800                                 return f_extents;
801                         }
802                 }
803
804                 public void CopyPage ()
805                 {
806                         NativeMethods.cairo_copy_page (handle);
807                 }
808
809                 [Obsolete ("Use SelectFontFace() instead.")]
810                 public void FontFace (string family, FontSlant slant, FontWeight weight)
811                 {
812                         SelectFontFace (family, slant, weight);
813                 }
814
815                 [Obsolete("Use GetFontFace/SetFontFace")]
816                 public FontFace ContextFontFace {
817                         get {
818                                 return GetContextFontFace ();
819                         }
820                         set {
821                                 SetContextFontFace (value);
822                         }
823                 }
824
825                 public FontFace GetContextFontFace ()
826                 {
827                         return Cairo.FontFace.Lookup (NativeMethods.cairo_get_font_face (handle), false);
828                 }
829
830                 public void SetContextFontFace (FontFace value)
831                 {
832                         NativeMethods.cairo_set_font_face (handle, value == null ? IntPtr.Zero : value.Handle);
833                 }
834
835                 public void SelectFontFace (string family, FontSlant slant, FontWeight weight)
836                 {
837                         NativeMethods.cairo_select_font_face (handle, family, slant, weight);
838                 }
839
840                 public void ShowPage ()
841                 {
842                         NativeMethods.cairo_show_page (handle);
843                 }
844
845                 private static byte[] TerminateUtf8(byte[] utf8)
846                 {
847                         if (utf8.Length > 0 && utf8[utf8.Length - 1] == 0)
848                                 return utf8;
849                         var termedArray = new byte[utf8.Length + 1];
850                         Array.Copy(utf8, termedArray, utf8.Length);
851                         termedArray[utf8.Length] = 0;
852                         return termedArray;
853                 }
854
855                 private static byte[] TerminateUtf8(string s)
856                 {
857                         // compute the byte count including the trailing \0
858                         var byteCount = Encoding.UTF8.GetMaxByteCount(s.Length + 1);
859                         var bytes = new byte[byteCount];
860                         Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0);
861                         return bytes;
862                 }
863
864                 public void ShowText(string str)
865                 {
866                         NativeMethods.cairo_show_text (handle, TerminateUtf8(str));
867                 }
868
869                 public void ShowText(byte[] utf8)
870                 {
871                         NativeMethods.cairo_show_text (handle, TerminateUtf8(utf8));
872                 }
873
874                 public void TextPath(string str)
875                 {
876                         NativeMethods.cairo_text_path (handle, TerminateUtf8(str));
877                 }
878
879                 public void TextPath(byte[] utf8)
880                 {
881                         NativeMethods.cairo_text_path (handle, TerminateUtf8(utf8));
882                 }
883
884                 public TextExtents TextExtents(string s)
885                 {
886                         TextExtents extents;
887                         NativeMethods.cairo_text_extents (handle, TerminateUtf8(s), out extents);
888                         return extents;
889                 }
890
891                 public TextExtents TextExtents(byte[] utf8)
892                 {
893                         TextExtents extents;
894                         NativeMethods.cairo_text_extents (handle, TerminateUtf8(utf8), out extents);
895                         return extents;
896                 }
897
898                 public TextExtents GlyphExtents (Glyph[] glyphs)
899                 {
900                         IntPtr ptr = FromGlyphToUnManagedMemory (glyphs);
901
902                         TextExtents extents;
903
904                         NativeMethods.cairo_glyph_extents (handle, ptr, glyphs.Length, out extents);
905
906                         Marshal.FreeHGlobal (ptr);
907
908                         return extents;
909                 }
910         }
911 }