///////////////////////////////////////////////////////////////////////////////// // Paint.NET // // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. // // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // // See license-pdn.txt for full licensing and attribution details. // ///////////////////////////////////////////////////////////////////////////////// using System; using System.Collections.Generic; using System.Runtime.Serialization; using Gdk; namespace Pinta.Core { /// /// Defines a surface that is irregularly shaped, defined by a Region. /// Works by containing an array of PlacedSurface instances. /// Similar to IrregularImage, but works with Surface objects instead. /// Instances of this class are immutable once created. /// [Serializable] public sealed class IrregularSurface : ISurfaceDraw, IDisposable, ICloneable, IDeserializationCallback { private List placedSurfaces; [NonSerialized] private Region region; #region Constructors /// /// Constructs an IrregularSurface by copying the given region-of-interest from an Image. /// /// The Surface to copy pixels from. /// Defines the Region from which to copy pixels from the Image. public IrregularSurface (Cairo.ImageSurface source, Region roi) { Region roiClipped = (Region)roi.Copy (); roiClipped.Intersect (Region.Rectangle (source.GetBounds ())); Rectangle[] rects = roiClipped.GetRectangles (); this.placedSurfaces = new List (rects.Length); foreach (Rectangle rect in rects) this.placedSurfaces.Add (new PlacedSurface (source, rect)); this.region = roiClipped; } public IrregularSurface (Cairo.ImageSurface source, Rectangle[] roi) { this.placedSurfaces = new List (roi.Length); foreach (Rectangle rect in roi) { Rectangle ri = Rectangle.Intersect (source.GetBounds (), rect); if (!ri.IsEmpty) this.placedSurfaces.Add (new PlacedSurface (source, ri)); } this.region = Utility.RectanglesToRegion (roi); this.region.Intersect (Region.Rectangle (source.GetBounds ())); } /// /// Constructs an IrregularSurface by copying the given rectangle-of-interest from an Image. /// /// The Surface to copy pixels from. /// Defines the Rectangle from which to copy pixels from the Image. public IrregularSurface (Cairo.ImageSurface source, Rectangle roi) { this.placedSurfaces = new List (); this.placedSurfaces.Add (new PlacedSurface (source, roi)); this.region = Region.Rectangle (roi); } private IrregularSurface (IrregularSurface cloneMe) { this.placedSurfaces = new List (cloneMe.placedSurfaces.Count); foreach (PlacedSurface ps in cloneMe.placedSurfaces) this.placedSurfaces.Add ((PlacedSurface)ps.Clone ()); this.region = cloneMe.Region.Copy (); } ~IrregularSurface () { Dispose (false); } #endregion #region Public Properties /// /// The Region that the irregular image fills. /// public Region Region { get { if (this.disposed) throw new ObjectDisposedException ("IrregularSurface"); return this.region; } } #endregion #region Public Methods /// /// Draws the IrregularSurface on to the given Surface. /// /// The Surface to draw to. public void Draw (Cairo.ImageSurface dst) { if (disposed) throw new ObjectDisposedException ("IrregularSurface"); foreach (PlacedSurface ps in placedSurfaces) ps.Draw (dst); } public void Draw (Cairo.ImageSurface dst, PixelOp pixelOp) { if (this.disposed) throw new ObjectDisposedException ("IrregularSurface"); foreach (PlacedSurface ps in this.placedSurfaces) ps.Draw (dst, pixelOp); } /// /// Draws the IrregularSurface on to the given Surface starting at the given (x,y) offset. /// /// The Surface to draw to. /// The value to be added to every X coordinate that is used for drawing. /// The value to be added to every Y coordinate that is used for drawing. public void Draw (Cairo.ImageSurface dst, int tX, int tY) { if (this.disposed) throw new ObjectDisposedException ("IrregularSurface"); foreach (PlacedSurface ps in this.placedSurfaces) ps.Draw (dst, tX, tY); } public void Draw (Cairo.ImageSurface dst, int tX, int tY, PixelOp pixelOp) { if (this.disposed) throw new ObjectDisposedException ("IrregularSurface"); foreach (PlacedSurface ps in this.placedSurfaces) ps.Draw (dst, tX, tY, pixelOp); } #endregion #region IDisposable Members private bool disposed = false; public void Dispose () { Dispose (true); System.GC.SuppressFinalize (this); } private void Dispose (bool disposing) { if (!this.disposed) { // TODO: FXCOP: call Dispose() on this.region this.disposed = true; if (disposing) { this.placedSurfaces.Clear (); this.placedSurfaces = null; } } } #endregion #region ICloneable Members /// /// Clones the IrregularSurface. /// /// A copy of the current state of this PlacedSurface. public object Clone () { if (disposed) throw new ObjectDisposedException ("IrregularSurface"); return new IrregularSurface (this); } #endregion #region IDeserializationCallback Members public void OnDeserialization (object sender) { region = Region.Rectangle (Rectangle.Zero); Rectangle[] rects = new Rectangle[placedSurfaces.Count]; for (int i = 0; i < placedSurfaces.Count; ++i) rects[i] = placedSurfaces[i].Bounds; region = Utility.RectanglesToRegion (rects); } #endregion } }