#region MIT License /*Copyright (c) 2012 Robert Rouhani SharpFont based on Tao.FreeType, Copyright (c) 2003-2007 Tao Framework Team 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.*/ #endregion using System; namespace SharpFont { /// /// Opaque handler to a path stroker object. /// public class Stroker : IDisposable { #region Fields private IntPtr reference; private bool disposed; private Library parentLibrary; #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// FreeType library handle. public Stroker(Library library) { IntPtr strokerRef; Error err = FT.FT_Stroker_New(library.Reference, out strokerRef); if (err != Error.Ok) throw new FreeTypeException(err); Reference = strokerRef; library.AddChildStroker(this); parentLibrary = library; } /// /// Finalizes an instance of the class. /// ~Stroker() { Dispose(false); } #endregion #region Properties /// /// Gets a value indicating whether the has been disposed. /// public bool IsDisposed { get { return disposed; } } internal IntPtr Reference { get { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); return reference; } set { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); reference = value; } } #endregion #region Methods /// /// Reset a stroker object's attributes. /// /// /// The radius is expressed in the same units as the outline coordinates. /// /// The border radius. /// The line cap style. /// The line join style. /// /// The miter limit for the and /// line join styles, expressed as 16.16 fixed point value. /// public void Set(int radius, StrokerLineCap lineCap, StrokerLineJoin lineJoin, int miterLimit) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); FT.FT_Stroker_Set(Reference, radius, lineCap, lineJoin, miterLimit); } /// /// Reset a stroker object without changing its attributes. You should call this function before beginning a /// new series of calls to or . /// public void Rewind() { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); FT.FT_Stroker_Rewind(Reference); } /// /// A convenience function used to parse a whole outline with the stroker. The resulting outline(s) can be /// retrieved later by functions like and . /// /// /// If ‘opened’ is 0 (the default), the outline is treated as a closed path, and the stroker generates two /// distinct ‘border’ outlines. /// /// If ‘opened’ is 1, the outline is processed as an open path, and the stroker generates a single ‘stroke’ /// outline. /// /// This function calls automatically. /// /// The source outline. /// /// A boolean. If 1, the outline is treated as an open path instead of a closed one. /// public void ParseOutline(Outline outline, bool opened) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); if (outline == null) throw new ArgumentNullException("outline"); Error err = FT.FT_Stroker_ParseOutline(Reference, outline.Reference, opened); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// Start a new sub-path in the stroker. /// /// /// This function is useful when you need to stroke a path that is not stored as an /// object. /// /// A pointer to the start vector. /// A boolean. If 1, the sub-path is treated as an open one. public void BeginSubPath(FTVector to, bool open) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_BeginSubPath(Reference, ref to, open); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// Close the current sub-path in the stroker. /// /// /// You should call this function after . If the subpath was not ‘opened’, this /// function ‘draws’ a single line segment to the start position when needed. /// public void EndSubPath() { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_EndSubPath(Reference); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// ‘Draw’ a single line segment in the stroker's current sub-path, from the last position. /// /// /// You should call this function between and . /// /// A pointer to the destination point. public void LineTo(FTVector to) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_LineTo(Reference, ref to); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// ‘Draw’ a single quadratic Bézier in the stroker's current sub-path, from the last position. /// /// /// You should call this function between and . /// /// A pointer to a Bézier control point. /// A pointer to the destination point. public void ConicTo(FTVector control, FTVector to) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_ConicTo(Reference, ref control, ref to); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// ‘Draw’ a single cubic Bézier in the stroker's current sub-path, from the last position. /// /// /// You should call this function between and . /// /// A pointer to the first Bézier control point. /// A pointer to second Bézier control point. /// A pointer to the destination point. public void CubicTo(FTVector control1, FTVector control2, FTVector to) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_CubicTo(Reference, ref control1, ref control2, ref to); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// Call this function once you have finished parsing your paths with the stroker. It returns the number of /// points and contours necessary to export one of the ‘border’ or ‘stroke’ outlines generated by the stroker. /// /// /// When an outline, or a sub-path, is ‘closed’, the stroker generates two independent ‘border’ outlines, named /// ‘left’ and ‘right’. /// /// When the outline, or a sub-path, is ‘opened’, the stroker merges the ‘border’ outlines with caps. The /// ‘left’ border receives all points, while the ‘right’ border becomes empty. /// /// Use the function instead if you want to retrieve the counts associated to both /// borders. /// /// The border index. /// The number of points. /// The number of contours. [CLSCompliant(false)] public void GetBorderCounts(StrokerBorder border, out uint pointsCount, out uint contoursCount) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_GetBorderCounts(Reference, border, out pointsCount, out contoursCount); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// Call this function after to export the corresponding border to your own /// structure. /// /// Note that this function appends the border points and contours to your outline, but does not try to resize /// its arrays. /// /// /// Always call this function after to get sure that there is enough room in your /// object to receive all new data. /// /// When an outline, or a sub-path, is ‘closed’, the stroker generates two independent ‘border’ outlines, named /// ‘left’ and ‘right’. /// /// When the outline, or a sub-path, is ‘opened’, the stroker merges the ‘border’ outlines with caps. The /// ‘left’ border receives all points, while the ‘right’ border becomes empty. /// /// Use the function instead if you want to retrieve all borders at once. /// /// The border index. /// The target outline handle. public void ExportBorder(StrokerBorder border, Outline outline) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); if (outline == null) throw new ArgumentNullException("outline"); FT.FT_Stroker_ExportBorder(Reference, border, outline.Reference); } /// /// Call this function once you have finished parsing your paths with the stroker. It returns the number of /// points and contours necessary to export all points/borders from the stroked outline/path. /// /// The number of points. /// The number of contours. [CLSCompliant(false)] public void GetCounts(out uint pointsCount, out uint contoursCount) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); Error err = FT.FT_Stroker_GetCounts(Reference, out pointsCount, out contoursCount); if (err != Error.Ok) throw new FreeTypeException(err); } /// /// Call this function after to export all borders to your own /// structure. /// /// Note that this function appends the border points and contours to your outline, but does not try to resize /// its arrays. /// /// The target outline handle. public void Export(Outline outline) { if (disposed) throw new ObjectDisposedException("Stroker", "Cannot access a disposed object."); if (outline == null) throw new ArgumentNullException("outline"); FT.FT_Stroker_Export(Reference, outline.Reference); } /// /// Disposes an instance of the class. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!disposed) { disposed = true; FT.FT_Stroker_Done(reference); // removes itself from the parent Library, with a check to prevent this from happening when Library is // being disposed (Library disposes all it's children with a foreach loop, this causes an // InvalidOperationException for modifying a collection during enumeration) if (!parentLibrary.IsDisposed) parentLibrary.RemoveChildStroker(this); } } #endregion } }