context: //
  // System.Drawing.Pen.cs
  //
  // Authors:
  //   Miguel de Icaza (miguel@ximian.com)
  //   Alexandre Pigolkine (pigolkine@gmx.de)
  //   Duncan Mak (duncan@ximian.com)
  //   Ravindra (rkumar@novell.com)
  //
  // Copyright (C) Ximian, Inc.  http://www.ximian.com
  // Copyright (C) 2004,2006 Novell, Inc (http://www.novell.com)
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  using System.ComponentModel;
  using System.Drawing.Drawing2D;
  using System.Runtime.InteropServices;
  
  namespace System.Drawing
  {
  	public sealed class Pen : MarshalByRefObject, ICloneable, IDisposable
  	{
  		internal IntPtr nativeObject;
  		internal bool isModifiable = true;
  		private Color color;
  		private CustomLineCap startCap;
  		private CustomLineCap endCap;
  
                  internal Pen (IntPtr p)
                  {
                          nativeObject = p;
                  }
  
  		public Pen (Brush brush) : this (brush, 1.0F)
  		{
  		}
  
  		public Pen (Color color) : this (color, 1.0F)
  		{
  		}
  
  		public Pen (Brush brush, float width)
  		{
  			if (brush == null)
  				throw new ArgumentNullException ("brush");
  
  			Status status = GDIPlus.GdipCreatePen2 (brush.nativeObject, width, GraphicsUnit.World, out nativeObject);
  			GDIPlus.CheckStatus (status);
  			color = Color.Empty;
  		}
  
  		public Pen (Color color, float width)
  		{
  			Status status = GDIPlus.GdipCreatePen1 (color.ToArgb (), width, GraphicsUnit.World, out nativeObject);
  			GDIPlus.CheckStatus (status);
  			this.color = color;
  		}
  
  		//
  		// Properties
  		//
  		[MonoLimitation ("Libgdiplus doesn't use this property for rendering")]
  		public PenAlignment Alignment {
  			get {
  				PenAlignment retval;
                                  Status status = GDIPlus.GdipGetPenMode (nativeObject, out retval);
  				GDIPlus.CheckStatus (status);
                                  return retval;
                          }
  
  			set {
  				if ((value < PenAlignment.Center) || (value > PenAlignment.Right))
  					throw new InvalidEnumArgumentException ("Alignment", (int)value, typeof (PenAlignment));
  
  				if (isModifiable) {
  					Status status = GDIPlus.GdipSetPenMode (nativeObject, value);
  					GDIPlus.CheckStatus (status);
  				} else
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
  			}
  		}
  
  		public Brush Brush {
  			get {
  				IntPtr brush;
  				Status status = GDIPlus.GdipGetPenBrushFill (nativeObject, out brush);
  				GDIPlus.CheckStatus (status);
  				return new SolidBrush (brush);
                          }
  
  			set {
  #if NET_2_0
  				if (value == null)
  					throw new ArgumentNullException ("Brush");
  #endif
  				if (!isModifiable)
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
  
  				Status status = GDIPlus.GdipSetPenBrushFill (nativeObject, value.nativeObject);
  				GDIPlus.CheckStatus (status);
  				color = Color.Empty;
  			}
  		}
  
  		public Color Color {
  			get {
  				if (color.Equals (Color.Empty)) {
  					int c;
  					Status status = GDIPlus.GdipGetPenColor (nativeObject, out c);
  					GDIPlus.CheckStatus (status);
  	                                color = Color.FromArgb (c);
  				}
  				return color;
  			}
  
  			set {
  				if (!isModifiable)
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
  
  				Status status = GDIPlus.GdipSetPenColor (nativeObject, value.ToArgb ());
  				GDIPlus.CheckStatus (status);
  				color = value;
  			}
  		}
  
  		public float [] CompoundArray {
  			get {
  				int count;
  				Status status = GDIPlus.GdipGetPenCompoundCount (nativeObject, out count);
  				GDIPlus.CheckStatus (status);
  
  				float [] compArray = new float [count];
  				status = GDIPlus.GdipGetPenCompoundArray (nativeObject, compArray, count);
  				GDIPlus.CheckStatus (status);
  
  				return compArray;
  			}
  
  			set {
  				if (isModifiable) {
                                          int length = value.Length;
                                          if (length < 2)
                                                  throw new ArgumentException ("Invalid parameter.");
                                          foreach (float val in value)
                                                  if (val < 0 || val > 1)
                                                          throw new ArgumentException ("Invalid parameter.");
  
  					Status status = GDIPlus.GdipSetPenCompoundArray (nativeObject, value, value.Length);
  					GDIPlus.CheckStatus (status);
  				} else
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
  			}
  		}
  
  		public CustomLineCap CustomEndCap {
  			get {
  				return endCap;
  			}
  
  			set {
  				if (isModifiable) {
  					Status status = GDIPlus.GdipSetPenCustomEndCap (nativeObject, value.nativeObject);
  					GDIPlus.CheckStatus (status);
  					endCap = value;
  				} else
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
  			}
  		}
  
  		public CustomLineCap CustomStartCap {
  			get {
  				return startCap;
  			}
  
  			set {
  				if (isModifiable) {
  					Status status = GDIPlus.GdipSetPenCustomStartCap (nativeObject, value.nativeObject);
  					GDIPlus.CheckStatus (status);
  					startCap = value;
  				} else
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
  			}
  		}
  
                  public DashCap DashCap {
  
                          get {
                                  DashCap retval;
                                  Status status = GDIPlus.GdipGetPenDashCap197819 (nativeObject, out retval);
  				GDIPlus.CheckStatus (status);
                                  return retval;
                          }
  
                          set {
  				if ((value < DashCap.Flat) || (value > DashCap.Triangle))
  					throw new InvalidEnumArgumentException ("DashCap", (int)value, typeof (DashCap));
  
  				if (isModifiable) {
                                  	Status status = GDIPlus.GdipSetPenDashCap197819 (nativeObject, value);
  					GDIPlus.CheckStatus (status);
  				} else
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
                          }
                  }
  
                  public float DashOffset {
  
                          get {
                                  float retval;
                                  Status status = GDIPlus.GdipGetPenDashOffset (nativeObject, out retval);
  				GDIPlus.CheckStatus (status);
                                  return retval;
                          }
  
                          set {
  				if (isModifiable) {
                                  	Status status = GDIPlus.GdipSetPenDashOffset (nativeObject, value);
  					GDIPlus.CheckStatus (status);
  				} else
  					throw new ArgumentException (Locale.GetText ("This Pen object can't be modified."));
                          }
                  }
  
                  public float [] DashPattern {
                          get {
                                  int count;
                                  Status status = GDIPlus.GdipGetPenDashCount (nativeObject, out count);
  				GDIPlus.CheckStatus (status);
  
  				float[] pattern;
  				// don't call GdipGetPenDashArray with a 0 count
  				if (count > 0) {
  					pattern = new float [count];
  	                                status = GDIPlus.GdipGetPenDashArray (nativeObject, pattern, count);
  					GDIPlus.CheckStatus (status);
  				} else if (DashStyle == DashStyle.Custom) {
  					// special case (not handled inside GDI+)
  					pattern = new float [1];
  					pattern[0] = 1.0f;
  				} else {
  					pattern = new float [0];
  				}
                                  return pattern;
                          }
  
                          set {
  				if (isModifiable) {
  					int length = value.Length;
  					if (length == 0)
  						throw new ArgumentException ("Invalid parameter.");
  					foreach (float val in value)
  						if (val <= 0)
  
gt: 							throw new ArgumentException ("Invalid parameter.");