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