Glyph.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #region MIT License
  2. /*Copyright (c) 2012 Robert Rouhani <robert.rouhani@gmail.com>
  3. SharpFont based on Tao.FreeType, Copyright (c) 2003-2007 Tao Framework Team
  4. Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. this software and associated documentation files (the "Software"), to deal in
  6. the Software without restriction, including without limitation the rights to
  7. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  8. of the Software, and to permit persons to whom the Software is furnished to do
  9. so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.*/
  19. #endregion
  20. using System;
  21. using System.Runtime.InteropServices;
  22. using SharpFont.Internal;
  23. namespace SharpFont
  24. {
  25. /// <summary>
  26. /// The root glyph structure contains a given glyph image plus its advance width in 16.16 fixed float format.
  27. /// </summary>
  28. public class Glyph : IDisposable
  29. {
  30. #region Fields
  31. private bool disposed;
  32. private IntPtr reference;
  33. private GlyphRec rec;
  34. private Library parentLibrary;
  35. #endregion
  36. #region Constructors
  37. internal Glyph(IntPtr reference, Library parentLibrary)
  38. {
  39. Reference = reference;
  40. this.parentLibrary = parentLibrary;
  41. parentLibrary.AddChildGlyph(this);
  42. }
  43. internal Glyph(GlyphRec rec, Library parentLibrary)
  44. {
  45. this.rec = rec;
  46. this.parentLibrary = parentLibrary;
  47. parentLibrary.AddChildGlyph(this);
  48. }
  49. /// <summary>
  50. /// Finalizes an instance of the Glyph class.
  51. /// </summary>
  52. ~Glyph()
  53. {
  54. Dispose(false);
  55. }
  56. #endregion
  57. #region Properties
  58. /// <summary>
  59. /// Gets a value indicating whether the object has been disposed.
  60. /// </summary>
  61. public bool IsDisposed
  62. {
  63. get
  64. {
  65. return disposed;
  66. }
  67. }
  68. /// <summary>
  69. /// Gets a handle to the FreeType library object.
  70. /// </summary>
  71. public Library Library
  72. {
  73. get
  74. {
  75. if (disposed)
  76. throw new ObjectDisposedException("Library", "Cannot access a disposed object.");
  77. return parentLibrary;
  78. }
  79. }
  80. /// <summary>
  81. /// Gets the format of the glyph's image.
  82. /// </summary>
  83. [CLSCompliant(false)]
  84. public GlyphFormat Format
  85. {
  86. get
  87. {
  88. if (disposed)
  89. throw new ObjectDisposedException("Format", "Cannot access a disposed object.");
  90. return rec.format;
  91. }
  92. }
  93. /// <summary>
  94. /// Gets a 16.16 vector that gives the glyph's advance width.
  95. /// </summary>
  96. public FTVector Advance
  97. {
  98. get
  99. {
  100. if (disposed)
  101. throw new ObjectDisposedException("Advance", "Cannot access a disposed object.");
  102. return rec.advance;
  103. }
  104. }
  105. internal IntPtr Reference
  106. {
  107. get
  108. {
  109. if (disposed)
  110. throw new ObjectDisposedException("Reference", "Cannot access a disposed object.");
  111. return reference;
  112. }
  113. set
  114. {
  115. if (disposed)
  116. throw new ObjectDisposedException("Reference", "Cannot access a disposed object.");
  117. reference = value;
  118. rec = PInvokeHelper.PtrToStructure<GlyphRec>(reference);
  119. }
  120. }
  121. #endregion
  122. #region Methods
  123. /// <summary>
  124. /// A function used to copy a glyph image. Note that the created <see cref="Glyph"/> object must be released
  125. /// with <see cref="Glyph.Dispose()"/>.
  126. /// </summary>
  127. /// <returns>A handle to the target glyph object. 0 in case of error.</returns>
  128. public Glyph Copy()
  129. {
  130. if (disposed)
  131. throw new ObjectDisposedException("Glyph", "Cannot access a disposed object.");
  132. IntPtr glyphRef;
  133. Error err = FT.FT_Glyph_Copy(Reference, out glyphRef);
  134. if (err != Error.Ok)
  135. throw new FreeTypeException(err);
  136. return new Glyph(glyphRef, Library);
  137. }
  138. /// <summary>
  139. /// Transform a glyph image if its format is scalable.
  140. /// </summary>
  141. /// <param name="matrix">A pointer to a 2x2 matrix to apply.</param>
  142. /// <param name="delta">
  143. /// A pointer to a 2d vector to apply. Coordinates are expressed in 1/64th of a pixel.
  144. /// </param>
  145. public void Transform(FTMatrix matrix, FTVector delta)
  146. {
  147. if (disposed)
  148. throw new ObjectDisposedException("Glyph", "Cannot access a disposed object.");
  149. Error err = FT.FT_Glyph_Transform(Reference, ref matrix, ref delta);
  150. if (err != Error.Ok)
  151. throw new FreeTypeException(err);
  152. }
  153. /// <summary><para>
  154. /// Return a glyph's ‘control box’. The control box encloses all the outline's points, including Bézier control
  155. /// points. Though it coincides with the exact bounding box for most glyphs, it can be slightly larger in some
  156. /// situations (like when rotating an outline which contains Bézier outside arcs).
  157. /// </para><para>
  158. /// Computing the control box is very fast, while getting the bounding box can take much more time as it needs
  159. /// to walk over all segments and arcs in the outline. To get the latter, you can use the ‘ftbbox’ component
  160. /// which is dedicated to this single task.
  161. /// </para></summary>
  162. /// <remarks><para>
  163. /// Coordinates are relative to the glyph origin, using the y upwards convention.
  164. /// </para><para>
  165. /// If the glyph has been loaded with <see cref="LoadFlags.NoScale"/>, ‘bbox_mode’ must be set to
  166. /// <see cref="GlyphBBoxMode.Unscaled"/> to get unscaled font units in 26.6 pixel format. The value
  167. /// <see cref="GlyphBBoxMode.Subpixels"/> is another name for this constant.
  168. /// </para><para>
  169. /// If the font is tricky and the glyph has been loaded with <see cref="LoadFlags.NoScale"/>, the resulting
  170. /// CBox is meaningless. To get reasonable values for the CBox it is necessary to load the glyph at a large
  171. /// ppem value (so that the hinting instructions can properly shift and scale the subglyphs), then extracting
  172. /// the CBox which can be eventually converted back to font units.
  173. /// </para><para>
  174. /// Note that the maximum coordinates are exclusive, which means that one can compute the width and height of
  175. /// the glyph image (be it in integer or 26.6 pixels) as:
  176. /// </para><para>
  177. /// <code>
  178. /// width = bbox.xMax - bbox.xMin;
  179. /// height = bbox.yMax - bbox.yMin;
  180. /// </code>
  181. /// </para><para>
  182. /// Note also that for 26.6 coordinates, if ‘bbox_mode’ is set to <see cref="GlyphBBoxMode.Gridfit"/>, the
  183. /// coordinates will also be grid-fitted, which corresponds to:
  184. /// </para><para>
  185. /// <code>
  186. /// bbox.xMin = FLOOR(bbox.xMin);
  187. /// bbox.yMin = FLOOR(bbox.yMin);
  188. /// bbox.xMax = CEILING(bbox.xMax);
  189. /// bbox.yMax = CEILING(bbox.yMax);
  190. /// </code>
  191. /// </para><para>
  192. /// To get the bbox in pixel coordinates, set ‘bbox_mode’ to <see cref="GlyphBBoxMode.Truncate"/>.
  193. /// </para><para>
  194. /// To get the bbox in grid-fitted pixel coordinates, set ‘bbox_mode’ to <see cref="GlyphBBoxMode.Pixels"/>.
  195. /// </para></remarks>
  196. /// <param name="mode">The mode which indicates how to interpret the returned bounding box values.</param>
  197. /// <returns>
  198. /// The glyph coordinate bounding box. Coordinates are expressed in 1/64th of pixels if it is grid-fitted.
  199. /// </returns>
  200. [CLSCompliant(false)]
  201. public BBox GetCBox(GlyphBBoxMode mode)
  202. {
  203. if (disposed)
  204. throw new ObjectDisposedException("Glyph", "Cannot access a disposed object.");
  205. IntPtr cboxRef;
  206. FT.FT_Glyph_Get_CBox(Reference, mode, out cboxRef);
  207. return new BBox(cboxRef);
  208. }
  209. /// <summary>
  210. /// Convert a given glyph object to a bitmap glyph object.
  211. /// </summary>
  212. /// <remarks><para>
  213. /// This function does nothing if the glyph format isn't scalable.
  214. /// </para><para>
  215. /// The glyph image is translated with the ‘origin’ vector before rendering.
  216. /// </para><para>
  217. /// The first parameter is a pointer to an <see cref="Glyph"/> handle, that will be replaced by this function
  218. /// (with newly allocated data). Typically, you would use (omitting error handling):
  219. /// </para><para>
  220. /// --sample code ommitted--
  221. /// </para></remarks>
  222. /// <param name="renderMode">An enumeration that describes how the data is rendered.</param>
  223. /// <param name="origin">
  224. /// A pointer to a vector used to translate the glyph image before rendering. Can be 0 (if no translation). The
  225. /// origin is expressed in 26.6 pixels.
  226. /// </param>
  227. /// <param name="destroy">
  228. /// A boolean that indicates that the original glyph image should be destroyed by this function. It is never
  229. /// destroyed in case of error.
  230. /// </param>
  231. public void ToBitmap(RenderMode renderMode, FTVector origin, bool destroy)
  232. {
  233. if (disposed)
  234. throw new ObjectDisposedException("Glyph", "Cannot access a disposed object.");
  235. IntPtr glyphRef = Reference;
  236. Error err = FT.FT_Glyph_To_Bitmap(ref glyphRef, renderMode, ref origin, destroy);
  237. Reference = glyphRef;
  238. if (err != Error.Ok)
  239. throw new FreeTypeException(err);
  240. }
  241. #region Glyph Stroker
  242. /// <summary>
  243. /// Stroke a given outline glyph object with a given stroker.
  244. /// </summary>
  245. /// <remarks>
  246. /// The source glyph is untouched in case of error.
  247. /// </remarks>
  248. /// <param name="stroker">A stroker handle.</param>
  249. /// <param name="destroy">A Boolean. If 1, the source glyph object is destroyed on success.</param>
  250. /// <returns>New glyph handle.</returns>
  251. public Glyph Stroke(Stroker stroker, bool destroy)
  252. {
  253. if (disposed)
  254. throw new ObjectDisposedException("Glyph", "Cannot access a disposed object.");
  255. if (stroker == null)
  256. throw new ArgumentNullException("stroker");
  257. IntPtr sourceRef = Reference;
  258. Error err = FT.FT_Glyph_Stroke(ref sourceRef, stroker.Reference, destroy);
  259. if (destroy)
  260. {
  261. //TODO when Glyph implements IDisposable, dispose the glyph.
  262. }
  263. if (err != Error.Ok)
  264. throw new FreeTypeException(err);
  265. if (sourceRef == Reference)
  266. return this;
  267. else
  268. return new Glyph(sourceRef, Library);
  269. }
  270. /// <summary>
  271. /// Stroke a given outline glyph object with a given stroker, but only return either its inside or outside
  272. /// border.
  273. /// </summary>
  274. /// <remarks>
  275. /// The source glyph is untouched in case of error.
  276. /// </remarks>
  277. /// <param name="stroker">A stroker handle.</param>
  278. /// <param name="inside">A Boolean. If 1, return the inside border, otherwise the outside border.</param>
  279. /// <param name="destroy">A Boolean. If 1, the source glyph object is destroyed on success.</param>
  280. /// <returns>New glyph handle.</returns>
  281. public Glyph StrokeBorder(Stroker stroker, bool inside, bool destroy)
  282. {
  283. if (disposed)
  284. throw new ObjectDisposedException("Glyph", "Cannot access a disposed object.");
  285. if (stroker == null)
  286. throw new ArgumentNullException("stroker");
  287. IntPtr sourceRef = Reference;
  288. Error err = FT.FT_Glyph_StrokeBorder(ref sourceRef, stroker.Reference, inside, destroy);
  289. if (destroy)
  290. {
  291. //TODO when Glyph implements IDisposable, dispose the glyph.
  292. }
  293. if (err != Error.Ok)
  294. throw new FreeTypeException(err);
  295. if (sourceRef == Reference)
  296. return this;
  297. else
  298. return new Glyph(sourceRef, Library);
  299. }
  300. #endregion
  301. /// <summary>
  302. /// Disposes the Glyph.
  303. /// </summary>
  304. public void Dispose()
  305. {
  306. Dispose(true);
  307. GC.SuppressFinalize(this);
  308. }
  309. private void Dispose(bool disposing)
  310. {
  311. if (!disposed)
  312. {
  313. disposed = true;
  314. FT.FT_Done_Glyph(reference);
  315. // removes itself from the parent Library, with a check to prevent this from happening when Library is
  316. // being disposed (Library disposes all it's children with a foreach loop, this causes an
  317. // InvalidOperationException for modifying a collection during enumeration)
  318. if (!parentLibrary.IsDisposed)
  319. parentLibrary.RemoveChildGlyph(this);
  320. reference = IntPtr.Zero;
  321. }
  322. }
  323. #endregion
  324. }
  325. }