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