context: //
  // Graphics class testing unit
  //
  // Authors:
  //   Jordi Mas, jordi@ximian.com
  //   Sebastien Pouliot  <sebastien@ximian.com>
  //
  // Copyright (C) 2005-2008 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 NUnit.Framework;
  using System;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Drawing.Imaging;
  using System.Drawing.Text;
  using System.IO;
  using System.Reflection;
  using System.Security.Permissions;
  
  namespace MonoTests.System.Drawing {
  
  	[TestFixture]
  	[SecurityPermission (SecurityAction.Deny, UnmanagedCode = true)]
  	public class GraphicsTest {
  
  		private RectangleF[] rects;
  		private Font font;
  
  		[TestFixtureSetUp]
  		public void FixtureSetUp ()
  		{
  			try {
  				font = new Font ("Arial", 12);
  			}
  			catch {
  			}
  		}
  
  		[TestFixtureTearDown]
  		public void FixtureTearDown ()
  		{
  			if (font != null)
  				font.Dispose ();
  		}
  
  
  		private bool IsEmptyBitmap (Bitmap bitmap, out int x, out int y)
  		{
  			bool result = true;
  			int empty = Color.Empty.ToArgb ();
  #if false
  			for (y = 0; y < bitmap.Height; y++) {
  				for (x = 0; x < bitmap.Width; x++) {
  					if (bitmap.GetPixel (x, y).ToArgb () != empty) {
  						Console.Write ("X");
  						result = false;
  					} else
  						Console.Write (" ");
  				}
  				Console.WriteLine ();
  			}
  #else
  			for (y = 0; y < bitmap.Height; y++) {
  				for (x = 0; x < bitmap.Width; x++) {
  					if (bitmap.GetPixel (x, y).ToArgb () != empty)
  						return false;
  				}
  			}
  #endif
  			x = -1;
  			y = -1;
  			return result;
  		}
  
  		private void CheckForEmptyBitmap (Bitmap bitmap)
  		{
  			int x, y;
  			if (!IsEmptyBitmap (bitmap, out x, out y))
  				Assert.Fail (String.Format ("Position {0},{1}", x, y));
  		}
  
  		private void CheckForNonEmptyBitmap (Bitmap bitmap)
  		{
  			int x, y;
  			if (IsEmptyBitmap (bitmap, out x, out y))
  				Assert.Fail ("Bitmap was empty");
  		}
  
  		private void AssertEquals (string msg, object expected, object actual)
  		{
  			Assert.AreEqual (expected, actual, msg);
  		}
  
  		private void AssertEquals (string msg, double expected, double actual, double delta)
  		{
  			Assert.AreEqual (expected, actual, delta, msg);
  		}
  
  		[Test]
  		public void DefaultProperties ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  			Region r = new Region ();
  
  			Assert.AreEqual (r.GetBounds (g), g.ClipBounds, "DefaultProperties1");
  			Assert.AreEqual (CompositingMode.SourceOver, g.CompositingMode, "DefaultProperties2");
  			Assert.AreEqual (CompositingQuality.Default, g.CompositingQuality, "DefaultProperties3");
  			Assert.AreEqual (InterpolationMode.Bilinear, g.InterpolationMode, "DefaultProperties4");
  			Assert.AreEqual (1, g.PageScale, "DefaultProperties5");
  			Assert.AreEqual (GraphicsUnit.Display, g.PageUnit, "DefaultProperties6");
  			Assert.AreEqual (PixelOffsetMode.Default, g.PixelOffsetMode, "DefaultProperties7");
  			Assert.AreEqual (new Point (0, 0), g.RenderingOrigin, "DefaultProperties8");
  			Assert.AreEqual (SmoothingMode.None, g.SmoothingMode, "DefaultProperties9");
  			Assert.AreEqual (TextRenderingHint.SystemDefault, g.TextRenderingHint, "DefaultProperties10");
  
  			r.Dispose ();
  		}
  
  		[Test]
  		public void SetGetProperties ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  
  			g.CompositingMode = CompositingMode.SourceCopy;
  			g.CompositingQuality = CompositingQuality.GammaCorrected;
  			g.InterpolationMode = InterpolationMode.HighQualityBilinear;
  			g.PageScale = 2;
  			g.PageUnit = GraphicsUnit.Inch;
  			g.PixelOffsetMode = PixelOffsetMode.Half;
  			g.RenderingOrigin = new Point (10, 20);
  			g.SmoothingMode = SmoothingMode.AntiAlias;
  			g.TextRenderingHint = TextRenderingHint.SystemDefault;
  
  			//Clipping set/get tested in clipping functions			
  			Assert.AreEqual (CompositingMode.SourceCopy, g.CompositingMode, "SetGetProperties2");
  			Assert.AreEqual (CompositingQuality.GammaCorrected, g.CompositingQuality, "SetGetProperties3");
  			Assert.AreEqual (InterpolationMode.HighQualityBilinear, g.InterpolationMode, "SetGetProperties4");
  			Assert.AreEqual (2, g.PageScale, "SetGetProperties5");
  			Assert.AreEqual (GraphicsUnit.Inch, g.PageUnit, "SetGetProperties6");
  			Assert.AreEqual (PixelOffsetMode.Half, g.PixelOffsetMode, "SetGetProperties7");
  			Assert.AreEqual (new Point (10, 20), g.RenderingOrigin, "SetGetProperties8");
  			Assert.AreEqual (SmoothingMode.AntiAlias, g.SmoothingMode, "SetGetProperties9");
  			Assert.AreEqual (TextRenderingHint.SystemDefault, g.TextRenderingHint, "SetGetProperties10");
  		}
  
  		// Properties
  		[Test]
  		public void Clip ()
  		{
  			RectangleF[] rects;
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  			g.Clip = new Region (new Rectangle (50, 40, 210, 220));
  			rects = g.Clip.GetRegionScans (new Matrix ());
  
  			Assert.AreEqual (1, rects.Length, "Clip1");
  			Assert.AreEqual (50, rects[0].X, "Clip2");
  			Assert.AreEqual (40, rects[0].Y, "Clip3");
  			Assert.AreEqual (210, rects[0].Width, "Clip4");
  			Assert.AreEqual (220, rects[0].Height, "Clip5");
  		}
  
  		[Test]
  		public void Clip_NotAReference ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  			Assert.IsTrue (g.Clip.IsInfinite (g), "IsInfinite");
  			g.Clip.IsEmpty (g);
  			Assert.IsFalse (g.Clip.IsEmpty (g), "!IsEmpty");
  			Assert.IsTrue (g.Clip.IsInfinite (g), "IsInfinite-2");
  		}
  
  		[Test]
  		public void ExcludeClip ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  
  			g.Clip = new Region (new RectangleF (10, 10, 100, 100));
  			g.ExcludeClip (new Rectangle (40, 60, 100, 20));
  			rects = g.Clip.GetRegionScans (new Matrix ());
  
  			Assert.AreEqual (3, rects.Length, "ExcludeClip1");
  
  			Assert.AreEqual (10, rects[0].X, "ExcludeClip2");
  			Assert.AreEqual (10, rects[0].Y, "ExcludeClip3");
  			Assert.AreEqual (100, rects[0].Width, "ExcludeClip4");
  			Assert.AreEqual (50, rects[0].Height, "ExcludeClip5");
  
  			Assert.AreEqual (10, rects[1].X, "ExcludeClip6");
  			Assert.AreEqual (60, rects[1].Y, "ExcludeClip7");
  			Assert.AreEqual (30, rects[1].Width, "ExcludeClip8");
  			Assert.AreEqual (20, rects[1].Height, "ExcludeClip9");
  
  			Assert.AreEqual (10, rects[2].X, "ExcludeClip10");
  			Assert.AreEqual (80, rects[2].Y, "ExcludeClip11");
  			Assert.AreEqual (100, rects[2].Width, "ExcludeClip12");
  			Assert.AreEqual (30, rects[2].Height, "ExcludeClip13");
  		}
  
  		[Test]
  		public void IntersectClip ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  
  			g.Clip = new Region (new RectangleF (260, 30, 60, 80));
  			g.IntersectClip (new Rectangle (290, 40, 60, 80));
  			rects = g.Clip.GetRegionScans (new Matrix ());
  
  			Assert.AreEqual (1, rects.Length, "IntersectClip");
  
  			Assert.AreEqual (290, rects[0].X, "IntersectClip");
  			Assert.AreEqual (40, rects[0].Y, "IntersectClip");
  			Assert.AreEqual (30, rects[0].Width, "IntersectClip");
  			Assert.AreEqual (70, rects[0].Height, "IntersectClip");
  		}
  
  		[Test]
  		public void ResetClip ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  
  			g.Clip = new Region (new RectangleF (260, 30, 60, 80));
  			g.IntersectClip (new Rectangle (290, 40, 60, 80));
  			g.ResetClip ();
  			rects = g.Clip.GetRegionScans (new Matrix ());
  
  			Assert.AreEqual (1, rects.Length, "ResetClip");
  
  			Assert.AreEqual (-4194304, rects[0].X, "ResetClip");
  			Assert.AreEqual (-4194304, rects[0].Y, "ResetClip");
  			Assert.AreEqual (8388608, rects[0].Width, "ResetClip");
  			Assert.AreEqual (8388608, rects[0].Height, "ResetClip");
  		}
  
  		[Test]
  		public void SetClip ()
  		{
  			RectangleF[] rects;
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  
  			// Region
  			g.SetClip (new Region (new Rectangle (50, 40, 210, 220)), CombineMode.Replace);
  			rects = g.Clip.GetRegionScans (new Matrix ());
  			Assert.AreEqual (1, rects.Length, "SetClip1");
  			Assert.AreEqual (50, rects[0].X, "SetClip2");
  			Assert.AreEqual (40, rects[0].Y, "SetClip3");
  			Assert.AreEqual (210, rects[0].Width, "SetClip4");
  			Assert.AreEqual (220, rects[0].Height, "SetClip5");
  
  			// RectangleF
  			g = Graphics.FromImage (bmp);
  			g.SetClip (new RectangleF (50, 40, 210, 220));
  			rects = g.Clip.GetRegionScans (new Matrix ());
  			Assert.AreEqual (1, rects.Length, "SetClip6");
  			Assert.AreEqual (50, rects[0].X, "SetClip7");
  			Assert.AreEqual (40, rects[0].Y, "SetClip8");
  			Assert.AreEqual (210, rects[0].Width, "SetClip9");
  			Assert.AreEqual (220, rects[0].Height, "SetClip10");
  
  			// Rectangle
  			g = Graphics.FromImage (bmp);
  			g.SetClip (new Rectangle (50, 40, 210, 220));
  			rects = g.Clip.GetRegionScans (new Matrix ());
  			Assert.AreEqual (1, rects.Length, "SetClip10");
  			Assert.AreEqual (50, rects[0].X, "SetClip11");
  			Assert.AreEqual (40, rects[0].Y, "SetClip12");
  			Assert.AreEqual (210, rects[0].Width, "SetClip13");
  			Assert.AreEqual (220, rects[0].Height, "SetClip14");
  		}
  
  		[Test]
  		public void SetSaveReset ()
  		{
  			Bitmap bmp = new Bitmap (200, 200);
  			Graphics g = Graphics.FromImage (bmp);
  			GraphicsState state_default, state_modified;
  
  			state_default = g.Save (); // Default
  
  			g.CompositingMode = CompositingMode.SourceCopy;
  			g.CompositingQuality = CompositingQuality.GammaCorrected;
  			g.InterpolationMode = InterpolationMode.HighQualityBilinear;
  			g.PageScale = 2;
  			g.PageUnit = GraphicsUnit.Inch;
  			g.PixelOffsetMode = PixelOffsetMode.Half;
  			g.Clip = new Region (new Rectangle (0, 0, 100, 100));
  			g.RenderingOrigin = new Point (10, 20);
  			g.SmoothingMode = SmoothingMode.AntiAlias;
  			g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
  
  
  			state_modified = g.Save (); // Modified
  
  			g.CompositingMode = CompositingMode.SourceOver;
  			g.CompositingQuality = CompositingQuality.Default;
  			g.InterpolationMode = InterpolationMode.Bilinear;
  			g.PageScale = 5;
  			g.PageUnit = GraphicsUnit.Display;
  			g.PixelOffsetMode = PixelOffsetMode.Default;
  			g.Clip = new Region (new Rectangle (1, 2, 20, 25));
  			g.RenderingOrigin = new Point (5, 6);
  			g.SmoothingMode = SmoothingMode.None;
  			g.TextRenderingHint = TextRenderingHint.SystemDefault;
  
  			g.Restore (state_modified);
  
  			Assert.AreEqual (CompositingMode.SourceCopy, g.CompositingMode, "SetSaveReset1");
  			Assert.AreEqual (CompositingQuality.GammaCorrected, g.CompositingQuality, "SetSaveReset2");
  			Assert.AreEqual (InterpolationMode.HighQualityBilinear, g.InterpolationMode, "SetSaveReset3");
  			Assert.AreEqual (2, g.PageScale, "SetSaveReset4");
  			Assert.AreEqual (GraphicsUnit.Inch, g.PageUnit, "SetSaveReset5");
  			Assert.AreEqual (PixelOffsetMode.Half, g.PixelOffsetMode, "SetSaveReset6");
  			Assert.AreEqual (new Point (10, 20), g.RenderingOrigin, "SetSaveReset7");
  			Assert.AreEqual (SmoothingMode.AntiAlias, g.SmoothingMode, "SetSaveReset8");
  			Assert.AreEqual (TextRenderingHint.ClearTypeGridFit, g.TextRenderingHint, "SetSaveReset9");
  			Assert.AreEqual (0, (int) g.ClipBounds.X, "SetSaveReset10");
  			Assert.AreEqual (0, (int) g.ClipBounds.Y, "SetSaveReset10");
  
  			g.Restore (state_default);
  
  			Assert.AreEqual (CompositingMode.SourceOver, g.CompositingMode, "SetSaveReset11");
  			Assert.AreEqual (CompositingQuality.Default, g.CompositingQuality, "SetSaveReset12");
  			Assert.AreEqual (InterpolationMode.Bilinear, g.InterpolationMode, "SetSaveReset13");
  			Assert.AreEqual (1, g.PageScale, "SetSaveReset14");
  			Assert.AreEqual (GraphicsUnit.Display, g.PageUnit, "SetSaveReset15");
  			Assert.AreEqual (PixelOffsetMode.Default, g.PixelOffsetMode, "SetSaveReset16");
  			Assert.AreEqual (new Point (0, 0), g.RenderingOrigin, "SetSaveReset17");
  			Assert.AreEqual (SmoothingMode.None, g.SmoothingMode, "SetSaveReset18");
  			Assert.AreEqual (TextRenderingHint.SystemDefault, g.TextRenderingHint, "SetSaveReset19");
  
  			Region r = new Region ();
  			Assert.AreEqual (r.GetBounds (g), g.ClipBounds, "SetSaveReset20");
  
  			g.Dispose ();
  		}
  
  		[Test]
  		[Category ("NotWorking")] // looks like MS PNG codec promote indexed format to 32bpp ARGB
  		public void LoadIndexed_PngStream ()
  		{
  			// Tests that we can load an indexed file
  			using (Stream s = Assembly.GetExecutingAssembly ().GetManifestResourceStream ("indexed.png")) {
  				using (Image img = Image.FromStream (s)) {
  					// however it's no more indexed once loaded
  					Assert.AreEqual (PixelFormat.Format32bppArgb, img.PixelFormat, "PixelFormat");
  					using (Graphics g = Graphics.FromImage (img)) {
  						Assert.AreEqual (img.Height, g.VisibleClipBounds.Height, "Height");
  						Assert.AreEqual (img.Width, g.VisibleClipBounds.Width, "Width");
  					}
  				}
  			}
  		}
  
  		[Test]
  		[ExpectedException (typeof (Exception))]
  		public void LoadIndexed_BmpFile ()
  		{
  			// Tests that we can load an indexed file, but...
  			string sInFile = TestBitmap.getInFile ("bitmaps/almogaver1bit.bmp");
  			// note: file is misnamed (it's a 4bpp bitmap)
  			using (Image img = Image.FromFile (sInFile)) {
  				Assert.AreEqual (PixelFormat.Format4bppIndexed, img.PixelFormat, "PixelFormat");
  				Graphics.FromImage (img);
  			}
  		}
  
  		[Test]
  		[ExpectedException (typeof (ArgumentNullException))]
  		public void FromImage ()
  		{
  			Graphics g = Graphics.FromImage (null);
  		}
  
  		private Graphics Get (int w, int h)
  		{
  			Bitmap bitmap = new Bitmap (w, h);
  			Graphics g = Graphics.FromImage (bitmap);
  			g.Clip = new Region (new Rectangle (0, 0, w, h));
  			return g;
  		}
  
  		private void Compare (string msg, RectangleF b1, RectangleF b2)
  		{
  			AssertEquals (msg + ".compare.X", b1.X, b2.X);
  			AssertEquals (msg + ".compare.Y", b1.Y, b2.Y);
  			AssertEquals (msg + ".compare.Width", b1.Width, b2.Width);
  			AssertEquals (msg + ".compare.Height", b1.Height, b2.Height);
  		}
  
  		[Test]
  		public void Clip_GetBounds ()
  		{
  			Graphics g = Get (16, 16);
  			RectangleF bounds = g.Clip.GetBounds (g);
  			Assert.AreEqual (0, bounds.X, "X");
  			Assert.AreEqual (0, bounds.Y, "Y");
  			Assert.AreEqual (16, bounds.Width, "Width");
  			Assert.AreEqual (16, bounds.Height, "Height");
  			Assert.IsTrue (g.Transform.IsIdentity, "Identity");
  			g.Dispose ();
  		}
  
  		[Test]
  		public void Clip_TranslateTransform ()
  		{
  			Graphics g = Get (16, 16);
  			g.TranslateTransform (12.22f, 10.10f);
  			RectangleF bounds = g.Clip.GetBounds (g);
  			Compare ("translate", bounds, g.ClipBounds);
  			Assert.AreEqual (-12.2200003f, bounds.X, "translate.X");
  			Assert.AreEqual (-10.1000004f, bounds.Y, "translate.Y");
  			Assert.AreEqual (16, bounds.Width, "translate.Width");
  			Assert.AreEqual (16, bounds.Height, "translate.Height");
  			float[] elements = g.Transform.Elements;
  			Assert.AreEqual (1, elements[0], "translate.0");
  			Assert.AreEqual (0, elements[1], "translate.1");
  			Assert.AreEqual (0, elements[2], "translate.2");
  			Assert.AreEqual (1, elements[3], "translate.3");
  			Assert.AreEqual (12.2200003f, elements[4], "translate.4");
  			Assert.AreEqual (10.1000004f, elements[5], "translate.5");
  
  			g.ResetTransform ();
  			bounds = g.Clip.GetBounds (g);
  			Compare ("reset", bounds, g.ClipBounds);
  			Assert.AreEqual (0, bounds.X, "reset.X");
  			Assert.AreEqual (0, bounds.Y, "reset.Y");
  			Assert.AreEqual (16, bounds.Width, "reset.Width");
  			Assert.AreEqual (16, bounds.Height, "reset.Height");
  			Assert.IsTrue (g.Transform.IsIdentity, "Identity");
  			g.Dispose ();
  		}
  
  		[Test]
  		[ExpectedException (typeof (ArgumentException))]
  		public void Transform_NonInvertibleMatrix ()
  		{
  			Matrix matrix = new Matrix (123, 24, 82, 16, 47, 30);
  			Assert.IsFalse (matrix.IsInvertible, "IsInvertible");
  			Graphics g = Get (16, 16);
  			g.Transform = matrix;
  		}
  
  
  		[Test]
  		[ExpectedException (typeof (ArgumentException))]
  		public void Multiply_NonInvertibleMatrix ()
  		{
  			Matrix matrix = new Matrix (123, 24, 82, 16, 47, 30);
  			Assert.IsFalse (matrix.IsInvertible, "IsInvertible");
  			Graphics g = Get (16, 16);
  			g.MultiplyTransform (matrix);
  		}
  
  		[Test]
  		[ExpectedException (typeof (ArgumentNullException))]
  		public void Multiply_Null ()
  		{
  			Graphics g = Get (16, 16);
  			g.MultiplyTransform (null);
  		}
  
  		private void CheckBounds (string msg, RectangleF bounds, float x, float y, float w, float h)
  		{
  			AssertEquals (msg + ".X", x, bounds.X, 0.1);
  			AssertEquals (msg + ".Y", y, bounds.Y, 0.1);
  			AssertEquals (msg + ".Width", w, bounds.Width, 0.1);
  			AssertEquals (msg + ".Height", h, bounds.Height, 0.1);
  		}
  
  		[Test]
  		public void ClipBounds ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			CheckBounds ("clip.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			CheckBounds ("clip.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void ClipBounds_Rotate ()
  		{
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			g.RotateTransform (90);
  			CheckBounds ("rotate.ClipBounds", g.ClipBounds, 0, -8, 8, 8);
  			CheckBounds ("rotate.Clip.GetBounds", g.Clip.GetBounds (g), 0, -8, 8, 8);
  
  			g.Transform = new Matrix ();
  			CheckBounds ("identity.ClipBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  			CheckBounds ("identity.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void ClipBounds_Scale ()
  		{
  			RectangleF clip = new Rectangle (0, 0, 8, 8);
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (clip);
  			g.ScaleTransform (0.25f, 0.5f);
  			CheckBounds ("scale.ClipBounds", g.ClipBounds, 0, 0, 32, 16);
  			CheckBounds ("scale.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 32, 16);
  
  			g.SetClip (clip);
  			CheckBounds ("setclip.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			CheckBounds ("setclip.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void ClipBounds_Translate ()
  		{
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			Region clone = g.Clip.Clone ();
  			g.TranslateTransform (8, 8);
  			CheckBounds ("translate.ClipBounds", g.ClipBounds, -8, -8, 8, 8);
  			CheckBounds ("translate.Clip.GetBounds", g.Clip.GetBounds (g), -8, -8, 8, 8);
  
  			g.SetClip (clone, CombineMode.Replace);
  			CheckBounds ("setclip.ClipBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  			CheckBounds ("setclip.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void ClipBounds_Transform_Translation ()
  		{
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			g.Transform = new Matrix (1, 0, 0, 1, 8, 8);
  			CheckBounds ("transform.ClipBounds", g.ClipBounds, -8, -8, 8, 8);
  			CheckBounds ("transform.Clip.GetBounds", g.Clip.GetBounds (g), -8, -8, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reset.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			CheckBounds ("reset.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void ClipBounds_Transform_Scale ()
  		{
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			g.Transform = new Matrix (0.5f, 0, 0, 0.25f, 0, 0);
  			CheckBounds ("scale.ClipBounds", g.ClipBounds, 0, 0, 16, 32);
  			CheckBounds ("scale.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 32);
  
  			g.ResetClip ();
  			// see next test for ClipBounds
  			CheckBounds ("resetclip.Clip.GetBounds", g.Clip.GetBounds (g), -4194304, -4194304, 8388608, 8388608);
  			Assert.IsTrue (g.Clip.IsInfinite (g), "IsInfinite");
  		}
  
  		[Test]
  		[Category ("NotWorking")]
  		public void ClipBounds_Transform_Scale_Strange ()
  		{
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			g.Transform = new Matrix (0.5f, 0, 0, 0.25f, 0, 0);
  			CheckBounds ("scale.ClipBounds", g.ClipBounds, 0, 0, 16, 32);
  			CheckBounds ("scale.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 32);
  
  			g.ResetClip ();
  			// note: strange case where g.ClipBounds and g.Clip.GetBounds are different
  			CheckBounds ("resetclip.ClipBounds", g.ClipBounds, -8388608, -16777216, 16777216, 33554432);
  		}
  
  		[Test]
  		public void ClipBounds_Multiply ()
  		{
  			Graphics g = Get (16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			g.Transform = new Matrix (1, 0, 0, 1, 8, 8);
  			g.MultiplyTransform (g.Transform);
  			CheckBounds ("multiply.ClipBounds", g.ClipBounds, -16, -16, 8, 8);
  			CheckBounds ("multiply.Clip.GetBounds", g.Clip.GetBounds (g), -16, -16, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reset.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			CheckBounds ("reset.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void ClipBounds_Cumulative_Effects ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			CheckBounds ("clip.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			CheckBounds ("clip.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  
  			g.RotateTransform (90);
  			CheckBounds ("rotate.ClipBounds", g.ClipBounds, 0, -8, 8, 8);
  			CheckBounds ("rotate.Clip.GetBounds", g.Clip.GetBounds (g), 0, -8, 8, 8);
  
  			g.ScaleTransform (0.25f, 0.5f);
  			CheckBounds ("scale.ClipBounds", g.ClipBounds, 0, -16, 32, 16);
  			CheckBounds ("scale.Clip.GetBounds", g.Clip.GetBounds (g), 0, -16, 32, 16);
  
  			g.TranslateTransform (8, 8);
  			CheckBounds ("translate.ClipBounds", g.ClipBounds, -8, -24, 32, 16);
  			CheckBounds ("translate.Clip.GetBounds", g.Clip.GetBounds (g), -8, -24, 32, 16);
  
  			g.MultiplyTransform (g.Transform);
  			CheckBounds ("multiply.ClipBounds", g.ClipBounds, -104, -56, 64, 64);
  			CheckBounds ("multiply.Clip.GetBounds", g.Clip.GetBounds (g), -104, -56, 64, 64);
  
  			g.ResetTransform ();
  			CheckBounds ("reset.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			CheckBounds ("reset.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  		}
  
  		[Test]
  		public void Clip_TranslateTransform_BoundsChange ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  			g.TranslateTransform (-16, -16);
  			CheckBounds ("translated.ClipBounds", g.ClipBounds, 16, 16, 16, 16);
  			CheckBounds ("translated.Clip.GetBounds", g.Clip.GetBounds (g), 16, 16, 16, 16);
  
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			// ClipBounds isn't affected by a previous translation
  			CheckBounds ("rectangle.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			// Clip.GetBounds isn't affected by a previous translation
  			CheckBounds ("rectangle.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reseted.ClipBounds", g.ClipBounds, -16, -16, 8, 8);
  			CheckBounds ("reseted.Clip.GetBounds", g.Clip.GetBounds (g), -16, -16, 8, 8);
  		}
  
  		[Test]
  		public void Clip_RotateTransform_BoundsChange ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  			// we select a "simple" angle because the region will be converted into
  			// a bitmap (well for libgdiplus) and we would lose precision after that
  			g.RotateTransform (90);
  			CheckBounds ("rotated.ClipBounds", g.ClipBounds, 0, -16, 16, 16);
  			CheckBounds ("rotated.Clip.GetBounds", g.Clip.GetBounds (g), 0, -16, 16, 16);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			// ClipBounds isn't affected by a previous rotation (90)
  			CheckBounds ("rectangle.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			// Clip.GetBounds isn't affected by a previous rotation
  			CheckBounds ("rectangle.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reseted.ClipBounds", g.ClipBounds, -8, 0, 8, 8);
  			CheckBounds ("reseted.Clip.GetBounds", g.Clip.GetBounds (g), -8, 0, 8, 8);
  		}
  
  		private void CheckBoundsInt (string msg, RectangleF bounds, int x, int y, int w, int h)
  		{
  			// currently bounds are rounded at 8 pixels (FIXME - we can go down to 1 pixel)
  			AssertEquals (msg + ".X", x, bounds.X, 4f);
  			AssertEquals (msg + ".Y", y, bounds.Y, 4f);
  			AssertEquals (msg + ".Width", w, bounds.Width, 4f);
  			AssertEquals (msg + ".Height", h, bounds.Height, 4f);
  		}
  
  		[Test]
  		[Category ("NotWorking")]
  		public void Clip_RotateTransform_BoundsChange_45 ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  			g.RotateTransform (45);
  			// we can't use the "normal" CheckBound here because of libgdiplus crude rounding
  			CheckBoundsInt ("rotated.ClipBounds", g.ClipBounds, 0, -11, 24, 24);
  			CheckBoundsInt ("rotated.Clip.GetBounds", g.Clip.GetBounds (g), 0, -11, 24, 24);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			// ClipBounds IS affected by a previous rotation (45)
  			CheckBoundsInt ("rectangle.ClipBounds", g.ClipBounds, -3, -4, 16, 16);
  			// Clip.GetBounds isn't affected by a previous rotation
  			CheckBounds ("rectangle.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reseted.ClipBounds", g.ClipBounds, -5, 1, 11, 11);
  			CheckBounds ("reseted.Clip.GetBounds", g.Clip.GetBounds (g), -5.6f, 0, 11.3f, 11.3f);
  		}
  
  		[Test]
  		public void Clip_ScaleTransform_NoBoundsChange ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  			g.ScaleTransform (2, 0.5f);
  			CheckBounds ("scaled.ClipBounds", g.ClipBounds, 0, 0, 8, 32);
  			CheckBounds ("scaled.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 32);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			// ClipBounds isn't affected by a previous scaling
  			CheckBounds ("rectangle.ClipBounds", g.ClipBounds, 0, 0, 8, 8);
  			// Clip.GetBounds isn't affected by a previous scaling
  			CheckBounds ("rectangle.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reseted.ClipBounds", g.ClipBounds, 0, 0, 16, 4);
  			CheckBounds ("reseted.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 4);
  		}
  
  		[Test]
  		[Category ("NotWorking")]
  		public void Clip_MultiplyTransform_NoBoundsChange ()
  		{
  			Graphics g = Get (16, 16);
  			CheckBounds ("graphics.ClipBounds", g.ClipBounds, 0, 0, 16, 16);
  			CheckBounds ("graphics.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 16, 16);
  			g.MultiplyTransform (new Matrix (2.5f, 0.5f, -2.5f, 0.5f, 4, -4));
  			CheckBounds ("multiplied.ClipBounds", g.ClipBounds, 3.2f, 1.6f, 19.2f, 19.2f);
  			CheckBounds ("multiplied.Clip.GetBounds", g.Clip.GetBounds (g), 3.2f, 1.6f, 19.2f, 19.2f);
  			g.Clip = new Region (new Rectangle (0, 0, 8, 8));
  			// ClipBounds IS affected by the previous multiplication
  			CheckBounds ("rectangle.ClipBounds", g.ClipBounds, -3, -3, 15, 15);
  			// Clip.GetBounds isn't affected by the previous multiplication
  			CheckBounds ("rectangle.Clip.GetBounds", g.Clip.GetBounds (g), 0, 0, 8, 8);
  
  			g.ResetTransform ();
  			CheckBounds ("reseted.ClipBounds", g.ClipBounds, -16, -3, 40, 7);
  			CheckBounds ("reseted.Clip.GetBounds", g.Clip.GetBounds (g), -16, -4, 40, 8);
  		}
  
  		[Test]
  		[ExpectedException (typeof (ArgumentException))]
  		public void ScaleTransform_X0 ()
  		{
  			Graphics g = Get (16, 16);
  			g.ScaleTransform (0, 1);
  		}
  
  		[Test]
  		[ExpectedException (typeof (ArgumentException))]
  		public void ScaleTransform_Y0 ()
  		{
  			Graphics g = Get (16, 16);
  			g.ScaleTransform (1, 0);
  		}
  
  		[Test]
  		public void TranslateTransform_Order ()
  		{
  			Graphics g = Get (16, 16);
  			g.Transform = new Matrix (1, 2, 3, 4, 5, 6);
  			g.TranslateTransform (3, -3);
  			float[] elements = g.Transform.Elements;
  			Assert.AreEqual (1, elements[0], "default.0");
  			Assert.AreEqual (2, elements[1], "default.1");
  			Assert.AreEqual (3, elements[2], "default.2");
  			Assert.AreEqual (4, elements[3], "default.3");
  
gt: 			Assert.AreEqual (-1, elements[4], "default.4");