2 // Mono.Cairo.Context.cs
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)
10 // (C) Ximian Inc, 2003.
11 // (C) Novell Inc, 2003.
13 // This is an OO wrapper API for the Cairo API.
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
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.
38 using System.Runtime.InteropServices;
44 static class CairoDebug
46 static System.Collections.Generic.Dictionary<IntPtr,string> traces;
48 public static readonly bool Enabled;
52 var dbg = Environment.GetEnvironmentVariable ("MONO_CAIRO_DEBUG_DISPOSE");
56 traces = new System.Collections.Generic.Dictionary<IntPtr,string> ();
59 public static void OnAllocated (IntPtr obj)
62 throw new InvalidOperationException ();
64 traces.Add (obj, Environment.StackTrace);
67 public static void OnDisposed<T> (IntPtr obj, bool disposing)
69 if (disposing && !Enabled)
70 throw new InvalidOperationException ();
73 Console.Error.WriteLine ("{0} is leaking, programmer is missing a call to Dispose", typeof(T).FullName);
75 Console.Error.WriteLine ("Allocated from:");
76 Console.Error.WriteLine (traces[obj]);
78 Console.Error.WriteLine ("Set MONO_CAIRO_DEBUG_DISPOSE to track allocation traces");
89 public Point (int x, int y)
109 public PointD (double x, double y)
128 public struct Distance
130 public Distance (double dx, double dy)
150 public Color(double r, double g, double b) : this (r, g, b, 1.0)
154 public Color(double r, double g, double b, double a)
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) {}
192 public class Context : IDisposable
194 IntPtr handle = IntPtr.Zero;
196 static int native_glyph_size, c_compiler_long_size;
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.
206 // We assume that sizeof(long) == sizeof(void*)
207 // except in the case of Win64 where sizeof(long)
210 int ptr_size = Marshal.SizeOf (typeof (IntPtr));
212 PlatformID platform = Environment.OSVersion.Platform;
213 if (platform == PlatformID.Win32NT ||
214 platform == PlatformID.Win32S ||
215 platform == PlatformID.Win32Windows ||
216 platform == PlatformID.WinCE ||
218 c_compiler_long_size = 4;
219 native_glyph_size = Marshal.SizeOf (typeof (NativeGlyph_4byte_longs));
221 c_compiler_long_size = 8;
222 native_glyph_size = Marshal.SizeOf (typeof (Glyph));
226 public Context (Surface surface) : this (NativeMethods.cairo_create (surface.Handle), true)
231 public Context (IntPtr handle, bool owner)
233 this.handle = handle;
235 NativeMethods.cairo_reference (handle);
236 if (CairoDebug.Enabled)
237 CairoDebug.OnAllocated (handle);
241 public Context (IntPtr state) : this (state, true)
250 public void Dispose ()
253 GC.SuppressFinalize (this);
256 protected virtual void Dispose (bool disposing)
258 if (!disposing || CairoDebug.Enabled)
259 CairoDebug.OnDisposed<Context> (handle, disposing);
261 if (!disposing|| handle == IntPtr.Zero)
264 NativeMethods.cairo_destroy (handle);
265 handle = IntPtr.Zero;
271 NativeMethods.cairo_save (handle);
274 public void Restore ()
276 NativeMethods.cairo_restore (handle);
279 public Antialias Antialias {
280 get { return NativeMethods.cairo_get_antialias (handle); }
281 set { NativeMethods.cairo_set_antialias (handle, value); }
284 public Cairo.Status Status {
286 return NativeMethods.cairo_status (handle);
290 public IntPtr Handle {
296 public Operator Operator {
298 NativeMethods.cairo_set_operator (handle, value);
302 return NativeMethods.cairo_get_operator (handle);
306 [Obsolete ("Use SetSourceRGBA method")]
309 NativeMethods.cairo_set_source_rgba (handle, value.R, value.G, value.B, value.A);
313 [Obsolete ("Use SetSourceRGBA method")]
314 public Cairo.Color ColorRgb {
316 Color = new Color (value.R, value.G, value.B);
320 public double Tolerance {
322 return NativeMethods.cairo_get_tolerance (handle);
326 NativeMethods.cairo_set_tolerance (handle, value);
330 public Cairo.FillRule FillRule {
332 NativeMethods.cairo_set_fill_rule (handle, value);
336 return NativeMethods.cairo_get_fill_rule (handle);
340 public double LineWidth {
342 NativeMethods.cairo_set_line_width (handle, value);
346 return NativeMethods.cairo_get_line_width (handle);
350 public Cairo.LineCap LineCap {
352 NativeMethods.cairo_set_line_cap (handle, value);
356 return NativeMethods.cairo_get_line_cap (handle);
360 public Cairo.LineJoin LineJoin {
362 NativeMethods.cairo_set_line_join (handle, value);
366 return NativeMethods.cairo_get_line_join (handle);
370 public void SetDash (double [] dashes, double offset)
372 NativeMethods.cairo_set_dash (handle, dashes, dashes.Length, offset);
375 [Obsolete("Use Source")]
376 public Pattern Pattern {
386 public Pattern Source {
388 NativeMethods.cairo_set_source (handle, value.Handle);
392 var ptr = NativeMethods.cairo_get_source (handle);
393 return Cairo.Pattern.Lookup (ptr, false);
397 public double MiterLimit {
399 NativeMethods.cairo_set_miter_limit (handle, value);
403 return NativeMethods.cairo_get_miter_limit (handle);
407 public PointD CurrentPoint {
410 NativeMethods.cairo_get_current_point (handle, out x, out y);
411 return new PointD (x, y);
415 public Cairo.Surface Target {
417 if (handle != IntPtr.Zero)
418 NativeMethods.cairo_destroy (handle);
420 handle = NativeMethods.cairo_create (value.Handle);
424 return Surface.Lookup (NativeMethods.cairo_get_target (handle), false);
428 public ScaledFont ScaledFont {
430 NativeMethods.cairo_set_scaled_font (handle, value.Handle);
434 return new ScaledFont (NativeMethods.cairo_get_scaled_font (handle), false);
438 public uint ReferenceCount {
439 get { return NativeMethods.cairo_get_reference_count (handle); }
442 public void SetSourceRGB (double r, double g, double b)
444 NativeMethods.cairo_set_source_rgb (handle, r, g, b);
447 public void SetSourceRGBA (double r, double g, double b, double a)
449 NativeMethods.cairo_set_source_rgba (handle, r, g, b, a);
452 //[Obsolete ("Use SetSource method (with double parameters)")]
453 public void SetSourceSurface (Surface source, int x, int y)
455 NativeMethods.cairo_set_source_surface (handle, source.Handle, x, y);
458 public void SetSource (Surface source, double x, double y)
460 NativeMethods.cairo_set_source_surface (handle, source.Handle, x, y);
463 public void SetSource (Surface source)
465 NativeMethods.cairo_set_source_surface (handle, source.Handle, 0, 0);
470 public void NewPath ()
472 NativeMethods.cairo_new_path (handle);
475 public void NewSubPath ()
477 NativeMethods.cairo_new_sub_path (handle);
480 public void MoveTo (PointD p)
485 public void MoveTo (double x, double y)
487 NativeMethods.cairo_move_to (handle, x, y);
490 public void LineTo (PointD p)
495 public void LineTo (double x, double y)
497 NativeMethods.cairo_line_to (handle, x, y);
500 public void CurveTo (PointD p1, PointD p2, PointD p3)
502 CurveTo (p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y);
505 public void CurveTo (double x1, double y1, double x2, double y2, double x3, double y3)
507 NativeMethods.cairo_curve_to (handle, x1, y1, x2, y2, x3, y3);
510 public void RelMoveTo (Distance d)
512 RelMoveTo (d.Dx, d.Dy);
515 public void RelMoveTo (double dx, double dy)
517 NativeMethods.cairo_rel_move_to (handle, dx, dy);
520 public void RelLineTo (Distance d)
522 RelLineTo (d.Dx, d.Dy);
525 public void RelLineTo (double dx, double dy)
527 NativeMethods.cairo_rel_line_to (handle, dx, dy);
530 public void RelCurveTo (Distance d1, Distance d2, Distance d3)
532 RelCurveTo (d1.Dx, d1.Dy, d2.Dx, d2.Dy, d3.Dx, d3.Dy);
535 public void RelCurveTo (double dx1, double dy1, double dx2, double dy2, double dx3, double dy3)
537 NativeMethods.cairo_rel_curve_to (handle, dx1, dy1, dx2, dy2, dx3, dy3);
540 public void Arc (double xc, double yc, double radius, double angle1, double angle2)
542 NativeMethods.cairo_arc (handle, xc, yc, radius, angle1, angle2);
545 public void ArcNegative (double xc, double yc, double radius, double angle1, double angle2)
547 NativeMethods.cairo_arc_negative (handle, xc, yc, radius, angle1, angle2);
550 public void Rectangle (Rectangle rectangle)
552 Rectangle (rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
555 public void Rectangle (PointD p, double width, double height)
557 Rectangle (p.X, p.Y, width, height);
560 public void Rectangle (double x, double y, double width, double height)
562 NativeMethods.cairo_rectangle (handle, x, y, width, height);
565 public void ClosePath ()
567 NativeMethods.cairo_close_path (handle);
570 public Path CopyPath ()
572 return new Path (NativeMethods.cairo_copy_path (handle));
575 public Path CopyPathFlat ()
577 return new Path (NativeMethods.cairo_copy_path_flat (handle));
580 public void AppendPath (Path path)
582 NativeMethods.cairo_append_path (handle, path.Handle);
587 #region Painting Methods
590 NativeMethods.cairo_paint (handle);
593 public void PaintWithAlpha (double alpha)
595 NativeMethods.cairo_paint_with_alpha (handle, alpha);
598 public void Mask (Pattern pattern)
600 NativeMethods.cairo_mask (handle, pattern.Handle);
603 public void MaskSurface (Surface surface, double surface_x, double surface_y)
605 NativeMethods.cairo_mask_surface (handle, surface.Handle, surface_x, surface_y);
608 public void Stroke ()
610 NativeMethods.cairo_stroke (handle);
613 public void StrokePreserve ()
615 NativeMethods.cairo_stroke_preserve (handle);
618 public Rectangle StrokeExtents ()
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);
627 NativeMethods.cairo_fill (handle);
630 public Rectangle FillExtents ()
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);
637 public void FillPreserve ()
639 NativeMethods.cairo_fill_preserve (handle);
646 NativeMethods.cairo_clip (handle);
649 public void ClipPreserve ()
651 NativeMethods.cairo_clip_preserve (handle);
654 public void ResetClip ()
656 NativeMethods.cairo_reset_clip (handle);
659 public bool InStroke (double x, double y)
661 return NativeMethods.cairo_in_stroke (handle, x, y);
664 public bool InFill (double x, double y)
666 return NativeMethods.cairo_in_fill (handle, x, y);
669 public Pattern PopGroup ()
671 return Pattern.Lookup (NativeMethods.cairo_pop_group (handle), true);
674 public void PopGroupToSource ()
676 NativeMethods.cairo_pop_group_to_source (handle);
679 public void PushGroup ()
681 NativeMethods.cairo_push_group (handle);
684 public void PushGroup (Content content)
686 NativeMethods.cairo_push_group_with_content (handle, content);
689 public Surface GroupTarget {
691 IntPtr surface = NativeMethods.cairo_get_group_target (handle);
692 return Surface.Lookup (surface, false);
696 public void Rotate (double angle)
698 NativeMethods.cairo_rotate (handle, angle);
701 public void Scale (double sx, double sy)
703 NativeMethods.cairo_scale (handle, sx, sy);
706 public void Translate (double tx, double ty)
708 NativeMethods.cairo_translate (handle, tx, ty);
711 public void Transform (Matrix m)
713 NativeMethods.cairo_transform (handle, m);
716 [Obsolete("Use UserToDevice instead")]
717 public void TransformPoint (ref double x, ref double y)
719 NativeMethods.cairo_user_to_device (handle, ref x, ref y);
722 [Obsolete("Use UserToDeviceDistance instead")]
723 public void TransformDistance (ref double dx, ref double dy)
725 NativeMethods.cairo_user_to_device_distance (handle, ref dx, ref dy);
728 [Obsolete("Use InverseTransformPoint instead")]
729 public void InverseTransformPoint (ref double x, ref double y)
731 NativeMethods.cairo_device_to_user (handle, ref x, ref y);
734 [Obsolete("Use DeviceToUserDistance instead")]
735 public void InverseTransformDistance (ref double dx, ref double dy)
737 NativeMethods.cairo_device_to_user_distance (handle, ref dx, ref dy);
740 public void UserToDevice (ref double x, ref double y)
742 NativeMethods.cairo_user_to_device (handle, ref x, ref y);
745 public void UserToDeviceDistance (ref double dx, ref double dy)
747 NativeMethods.cairo_user_to_device_distance (handle, ref dx, ref dy);
750 public void DeviceToUser (ref double x, ref double y)
752 NativeMethods.cairo_device_to_user (handle, ref x, ref y);
755 public void DeviceToUserDistance (ref double dx, ref double dy)
757 NativeMethods.cairo_device_to_user_distance (handle, ref dx, ref dy);
760 public Matrix Matrix {
762 NativeMethods.cairo_set_matrix (handle, value);
766 Matrix m = new Matrix();
767 NativeMethods.cairo_get_matrix (handle, m);
772 public void SetFontSize (double scale)
774 NativeMethods.cairo_set_font_size (handle, scale);
777 public void IdentityMatrix ()
779 NativeMethods.cairo_identity_matrix (handle);
782 [Obsolete ("Use SetFontSize() instead.")]
783 public void FontSetSize (double scale)
788 [Obsolete ("Use SetFontSize() instead.")]
789 public double FontSize {
790 set { SetFontSize (value); }
793 public Matrix FontMatrix {
796 NativeMethods.cairo_get_font_matrix (handle, out m);
799 set { NativeMethods.cairo_set_font_matrix (handle, value); }
802 public FontOptions FontOptions {
804 FontOptions options = new FontOptions ();
805 NativeMethods.cairo_get_font_options (handle, options.Handle);
808 set { NativeMethods.cairo_set_font_options (handle, value.Handle); }
811 [StructLayout(LayoutKind.Sequential)]
812 internal struct NativeGlyph_4byte_longs {
817 public NativeGlyph_4byte_longs (Glyph source)
819 index = (int) source.index;
825 static internal IntPtr FromGlyphToUnManagedMemory(Glyph [] glyphs)
827 IntPtr dest = Marshal.AllocHGlobal (native_glyph_size * glyphs.Length);
828 long pos = dest.ToInt64();
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;
836 foreach (Glyph g in glyphs){
837 NativeGlyph_4byte_longs n = new NativeGlyph_4byte_longs (g);
839 Marshal.StructureToPtr (n, (IntPtr)pos, false);
840 pos += native_glyph_size;
847 public void ShowGlyphs (Glyph[] glyphs)
851 ptr = FromGlyphToUnManagedMemory (glyphs);
853 NativeMethods.cairo_show_glyphs (handle, ptr, glyphs.Length);
855 Marshal.FreeHGlobal (ptr);
858 [Obsolete("The matrix argument was never used, use ShowGlyphs(Glyphs []) instead")]
859 public void ShowGlyphs (Matrix matrix, Glyph[] glyphs)
864 [Obsolete("The matrix argument was never used, use GlyphPath(Glyphs []) instead")]
865 public void GlyphPath (Matrix matrix, Glyph[] glyphs)
870 public void GlyphPath (Glyph[] glyphs)
874 ptr = FromGlyphToUnManagedMemory (glyphs);
876 NativeMethods.cairo_glyph_path (handle, ptr, glyphs.Length);
878 Marshal.FreeHGlobal (ptr);
882 public FontExtents FontExtents {
884 FontExtents f_extents;
885 NativeMethods.cairo_font_extents (handle, out f_extents);
890 public void CopyPage ()
892 NativeMethods.cairo_copy_page (handle);
895 [Obsolete ("Use SelectFontFace() instead.")]
896 public void FontFace (string family, FontSlant slant, FontWeight weight)
898 SelectFontFace (family, slant, weight);
901 public FontFace ContextFontFace {
903 return Cairo.FontFace.Lookup (NativeMethods.cairo_get_font_face (handle), false);
907 NativeMethods.cairo_set_font_face (handle, value == null ? IntPtr.Zero : value.Handle);
911 public void SelectFontFace (string family, FontSlant slant, FontWeight weight)
913 NativeMethods.cairo_select_font_face (handle, family, slant, weight);
916 public void ShowPage ()
918 NativeMethods.cairo_show_page (handle);
921 private static byte[] TerminateUtf8(byte[] utf8)
923 if (utf8.Length > 0 && utf8[utf8.Length - 1] == 0)
925 var termedArray = new byte[utf8.Length + 1];
926 Array.Copy(utf8, termedArray, utf8.Length);
927 termedArray[utf8.Length] = 0;
931 private static byte[] TerminateUtf8(string s)
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);
940 public void ShowText(string str)
942 NativeMethods.cairo_show_text (handle, TerminateUtf8(str));
945 public void ShowText(byte[] utf8)
947 NativeMethods.cairo_show_text (handle, TerminateUtf8(utf8));
950 public void TextPath(string str)
952 NativeMethods.cairo_text_path (handle, TerminateUtf8(str));
955 public void TextPath(byte[] utf8)
957 NativeMethods.cairo_text_path (handle, TerminateUtf8(utf8));
960 public TextExtents TextExtents(string s)
963 NativeMethods.cairo_text_extents (handle, TerminateUtf8(s), out extents);
967 public TextExtents TextExtents(byte[] utf8)
970 NativeMethods.cairo_text_extents (handle, TerminateUtf8(utf8), out extents);
974 public TextExtents GlyphExtents (Glyph[] glyphs)
976 IntPtr ptr = FromGlyphToUnManagedMemory (glyphs);
980 NativeMethods.cairo_glyph_extents (handle, ptr, glyphs.Length, out extents);
982 Marshal.FreeHGlobal (ptr);