Outline.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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. /// This structure is used to describe an outline to the scan-line converter.
  27. /// </summary>
  28. /// <remarks>
  29. /// The B/W rasterizer only checks bit 2 in the ‘tags’ array for the first point of each contour. The drop-out mode
  30. /// as given with <see cref="OutlineFlags.IgnoreDropouts"/>, <see cref="OutlineFlags.SmartDropouts"/>, and
  31. /// <see cref="OutlineFlags.IncludeStubs"/> in ‘flags’ is then overridden.
  32. /// </remarks>
  33. public sealed class Outline : IDisposable
  34. {
  35. #region Fields
  36. private bool disposed;
  37. private bool duplicate;
  38. private IntPtr reference;
  39. private OutlineRec rec;
  40. private Library parentLibrary;
  41. private Memory parentMemory;
  42. #endregion
  43. #region Constructor
  44. /// <summary>
  45. /// Initializes a new instance of the <see cref="Outline"/> class.
  46. /// </summary>
  47. /// <remarks>
  48. /// The reason why this function takes a ‘library’ parameter is simply to use the library's memory allocator.
  49. /// </remarks>
  50. /// <param name="library">
  51. /// A handle to the library object from where the outline is allocated. Note however that the new outline will
  52. /// not necessarily be freed, when destroying the library, by <see cref="Library.Finalize"/>.
  53. /// </param>
  54. /// <param name="pointsCount">The maximum number of points within the outline.</param>
  55. /// <param name="contoursCount">The maximum number of contours within the outline.</param>
  56. [CLSCompliant(false)]
  57. public Outline(Library library, uint pointsCount, int contoursCount)
  58. {
  59. IntPtr reference;
  60. Error err = FT.FT_Outline_New(library.Reference, pointsCount, contoursCount, out reference);
  61. if (err != Error.Ok)
  62. throw new FreeTypeException(err);
  63. parentLibrary = library;
  64. parentLibrary.AddChildOutline(this);
  65. }
  66. /// <summary>
  67. /// Initializes a new instance of the <see cref="Outline"/> class.
  68. /// </summary>
  69. /// <param name="memory">A handle to the memory object from where the outline is allocated.</param>
  70. /// <param name="pointsCount">The maximum number of points within the outline.</param>
  71. /// <param name="contoursCount">The maximum number of contours within the outline.</param>
  72. [CLSCompliant(false)]
  73. public Outline(Memory memory, uint pointsCount, int contoursCount)
  74. {
  75. IntPtr reference;
  76. Error err = FT.FT_Outline_New_Internal(memory.Reference, pointsCount, contoursCount, out reference);
  77. if (err != Error.Ok)
  78. throw new FreeTypeException(err);
  79. parentMemory = memory; //TODO Should Memory be disposable as well?
  80. }
  81. internal Outline(IntPtr reference, Library parent)
  82. {
  83. Reference = reference;
  84. parentLibrary = parent;
  85. parentLibrary.AddChildOutline(this);
  86. }
  87. internal Outline(OutlineRec outlineInt)
  88. {
  89. this.rec = outlineInt;
  90. duplicate = true;
  91. }
  92. /// <summary>
  93. /// Finalizes an instance of the <see cref="Outline"/> class.
  94. /// </summary>
  95. ~Outline()
  96. {
  97. Dispose(false);
  98. }
  99. #endregion
  100. #region Properties
  101. /// <summary>
  102. /// Gets a value indicating whether the <see cref="Outline"/> has been disposed.
  103. /// </summary>
  104. public bool IsDisposed
  105. {
  106. get
  107. {
  108. return disposed;
  109. }
  110. }
  111. /// <summary>
  112. /// Gets the number of contours in the outline.
  113. /// </summary>
  114. public short ContoursCount
  115. {
  116. get
  117. {
  118. if (disposed)
  119. throw new ObjectDisposedException("ContoursCount", "Cannot access a disposed object.");
  120. return rec.n_contours;
  121. }
  122. }
  123. /// <summary>
  124. /// Gets the number of points in the outline.
  125. /// </summary>
  126. public short PointsCount
  127. {
  128. get
  129. {
  130. if (disposed)
  131. throw new ObjectDisposedException("PointsCount", "Cannot access a disposed object.");
  132. return rec.n_points;
  133. }
  134. }
  135. /// <summary>
  136. /// Gets a pointer to an array of ‘PointsCount’ <see cref="FTVector"/> elements, giving the outline's point
  137. /// coordinates.
  138. /// </summary>
  139. public FTVector[] Points
  140. {
  141. get
  142. {
  143. if (disposed)
  144. throw new ObjectDisposedException("Points", "Cannot access a disposed object.");
  145. int count = PointsCount;
  146. if (count == 0)
  147. return null;
  148. FTVector[] points = new FTVector[count];
  149. IntPtr array = rec.points;
  150. for (int i = 0; i < count; i++)
  151. {
  152. points[i] = new FTVector(new IntPtr(array.ToInt64() + IntPtr.Size * i));
  153. }
  154. return points;
  155. }
  156. }
  157. /// <summary><para>
  158. /// Gets a pointer to an array of ‘PointsCount’ chars, giving each outline point's type.
  159. /// </para><para>
  160. /// If bit 0 is unset, the point is ‘off’ the curve, i.e., a Bézier control point, while it is ‘on’ if set.
  161. /// </para><para>
  162. /// Bit 1 is meaningful for ‘off’ points only. If set, it indicates a third-order Bézier arc control point; and
  163. /// a second-order control point if unset.
  164. /// </para><para>
  165. /// If bit 2 is set, bits 5-7 contain the drop-out mode (as defined in the OpenType specification; the value is
  166. /// the same as the argument to the SCANMODE instruction).
  167. /// </para><para>
  168. /// Bits 3 and 4 are reserved for internal purposes.
  169. /// </para></summary>
  170. public byte[] Tags
  171. {
  172. get
  173. {
  174. if (disposed)
  175. throw new ObjectDisposedException("Tags", "Cannot access a disposed object.");
  176. int count = PointsCount;
  177. if (count == 0)
  178. return null;
  179. byte[] tags = new byte[count];
  180. IntPtr array = rec.tags;
  181. for (int i = 0; i < count; i++)
  182. {
  183. tags[i] = Marshal.ReadByte(array, IntPtr.Size * i);
  184. }
  185. return tags;
  186. }
  187. }
  188. /// <summary>
  189. /// Gets an array of ‘ContoursCount’ shorts, giving the end point of each contour within the outline. For
  190. /// example, the first contour is defined by the points ‘0’ to ‘Contours[0]’, the second one is defined by the
  191. /// points ‘Contours[0]+1’ to ‘Contours[1]’, etc.
  192. /// </summary>
  193. public short[] Contours
  194. {
  195. get
  196. {
  197. if (disposed)
  198. throw new ObjectDisposedException("Contours", "Cannot access a disposed object.");
  199. int count = ContoursCount;
  200. if (count == 0)
  201. return null;
  202. short[] contours = new short[count];
  203. IntPtr array = rec.contours;
  204. for (int i = 0; i < count; i++)
  205. {
  206. contours[i] = Marshal.ReadInt16(array, IntPtr.Size * i);
  207. }
  208. return contours;
  209. }
  210. }
  211. /// <summary>
  212. /// Gets a set of bit flags used to characterize the outline and give hints to the scan-converter and hinter on
  213. /// how to convert/grid-fit it.
  214. /// </summary>
  215. /// <see cref="OutlineFlags"/>
  216. public OutlineFlags Flags
  217. {
  218. get
  219. {
  220. if (disposed)
  221. throw new ObjectDisposedException("Flags", "Cannot access a disposed object.");
  222. return rec.flags;
  223. }
  224. }
  225. internal IntPtr Reference
  226. {
  227. get
  228. {
  229. if (disposed)
  230. throw new ObjectDisposedException("Reference", "Cannot access a disposed object.");
  231. return reference;
  232. }
  233. set
  234. {
  235. if (disposed)
  236. throw new ObjectDisposedException("Reference", "Cannot access a disposed object.");
  237. reference = value;
  238. rec = PInvokeHelper.PtrToStructure<OutlineRec>(reference);
  239. }
  240. }
  241. #endregion
  242. #region Methods
  243. #region Outline Processing
  244. /// <summary>
  245. /// Copy an outline into another one. Both objects must have the same sizes (number of points &amp; number of
  246. /// contours) when this function is called.
  247. /// </summary>
  248. /// <param name="target">A handle to the target outline.</param>
  249. public void Copy(Outline target)
  250. {
  251. if (disposed)
  252. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  253. if (target == null)
  254. throw new ArgumentNullException("target");
  255. IntPtr targetRef = target.Reference;
  256. Error err = FT.FT_Outline_Copy(reference, ref targetRef);
  257. target.Reference = reference;
  258. if (err != Error.Ok)
  259. throw new FreeTypeException(err);
  260. }
  261. /// <summary>
  262. /// Apply a simple translation to the points of an outline.
  263. /// </summary>
  264. /// <param name="offsetX">The horizontal offset.</param>
  265. /// <param name="offsetY">The vertical offset.</param>
  266. public void Translate(int offsetX, int offsetY)
  267. {
  268. if (disposed)
  269. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  270. FT.FT_Outline_Translate(reference, offsetX, offsetY);
  271. }
  272. /// <summary>
  273. /// Apply a simple 2x2 matrix to all of an outline's points. Useful for applying rotations, slanting, flipping,
  274. /// etc.
  275. /// </summary>
  276. /// <remarks>
  277. /// You can use <see cref="Translate"/> if you need to translate the outline's points.
  278. /// </remarks>
  279. /// <param name="matrix">A pointer to the transformation matrix.</param>
  280. public void Transform(FTMatrix matrix)
  281. {
  282. if (disposed)
  283. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  284. FT.FT_Outline_Transform(reference, ref matrix);
  285. }
  286. /// <summary><para>
  287. /// Embolden an outline. The new outline will be at most 4 times ‘strength’ pixels wider and higher. You may
  288. /// think of the left and bottom borders as unchanged.
  289. /// </para><para>
  290. /// Negative ‘strength’ values to reduce the outline thickness are possible also.
  291. /// </para></summary>
  292. /// <remarks><para>
  293. /// The used algorithm to increase or decrease the thickness of the glyph doesn't change the number of points;
  294. /// this means that certain situations like acute angles or intersections are sometimes handled incorrectly.
  295. /// </para><para>
  296. /// If you need ‘better’ metrics values you should call <see cref="GetCBox"/> or <see cref="GetBBox"/>.
  297. /// </para></remarks>
  298. /// <example>
  299. /// FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
  300. /// if ( face-&gt;slot-&gt;format == FT_GLYPH_FORMAT_OUTLINE )
  301. /// FT_Outline_Embolden( &amp;face-&gt;slot-&gt;outline, strength );
  302. /// </example>
  303. /// <param name="strength">How strong the glyph is emboldened. Expressed in 26.6 pixel format.</param>
  304. public void Embolden(int strength)
  305. {
  306. if (disposed)
  307. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  308. Error err = FT.FT_Outline_Embolden(reference, strength);
  309. if (err != Error.Ok)
  310. throw new FreeTypeException(err);
  311. }
  312. /// <summary>
  313. /// Embolden an outline. The new outline will be ‘xstrength’ pixels wider and ‘ystrength’ pixels higher.
  314. /// Otherwise, it is similar to <see cref="Embolden"/>, which uses the same strength in both directions.
  315. /// </summary>
  316. /// <param name="strengthX">
  317. /// How strong the glyph is emboldened in the X direction. Expressed in 26.6 pixel format.
  318. /// </param>
  319. /// <param name="strengthY">
  320. /// How strong the glyph is emboldened in the Y direction. Expressed in 26.6 pixel format.
  321. /// </param>
  322. public void EmboldenXY(int strengthX, int strengthY)
  323. {
  324. if (disposed)
  325. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  326. Error err = FT.FT_Outline_EmboldenXY(reference, strengthX, strengthY);
  327. if (err != Error.Ok)
  328. throw new FreeTypeException(err);
  329. }
  330. /// <summary>
  331. /// Reverse the drawing direction of an outline. This is used to ensure consistent fill conventions for
  332. /// mirrored glyphs.
  333. /// </summary>
  334. /// <remarks><para>
  335. /// This function toggles the bit flag <see cref="OutlineFlags.ReverseFill"/> in the outline's ‘flags’ field.
  336. /// </para><para>
  337. /// It shouldn't be used by a normal client application, unless it knows what it is doing.
  338. /// </para></remarks>
  339. public void Reverse()
  340. {
  341. if (disposed)
  342. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  343. FT.FT_Outline_Reverse(reference);
  344. }
  345. /// <summary>
  346. /// Check the contents of an outline descriptor.
  347. /// </summary>
  348. public void Check()
  349. {
  350. if (disposed)
  351. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  352. Error err = FT.FT_Outline_Check(reference);
  353. if (err != Error.Ok)
  354. throw new FreeTypeException(err);
  355. }
  356. /// <summary>
  357. /// Compute the exact bounding box of an outline. This is slower than computing the control box. However, it
  358. /// uses an advanced algorithm which returns very quickly when the two boxes coincide. Otherwise, the outline
  359. /// Bézier arcs are traversed to extract their extrema.
  360. /// </summary>
  361. /// <remarks>
  362. /// If the font is tricky and the glyph has been loaded with <see cref="LoadFlags.NoScale"/>, the resulting
  363. /// BBox is meaningless. To get reasonable values for the BBox it is necessary to load the glyph at a large
  364. /// ppem value (so that the hinting instructions can properly shift and scale the subglyphs), then extracting
  365. /// the BBox which can be eventually converted back to font units.
  366. /// </remarks>
  367. /// <returns>The outline's exact bounding box.</returns>
  368. public BBox GetBBox()
  369. {
  370. if (disposed)
  371. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  372. IntPtr bboxRef;
  373. Error err = FT.FT_Outline_Get_BBox(reference, out bboxRef);
  374. if (err != Error.Ok)
  375. throw new FreeTypeException(err);
  376. return new BBox(bboxRef);
  377. }
  378. /// <summary>
  379. /// Walk over an outline's structure to decompose it into individual segments and Bézier arcs. This function
  380. /// also emits ‘move to’ operations to indicate the start of new contours in the outline.
  381. /// </summary>
  382. /// <param name="funcInterface">
  383. /// A table of ‘emitters’, i.e., function pointers called during decomposition to indicate path operations.
  384. /// </param>
  385. /// <param name="user">
  386. /// A typeless pointer which is passed to each emitter during the decomposition. It can be used to store the
  387. /// state during the decomposition.
  388. /// </param>
  389. public void Decompose(OutlineFuncs funcInterface, IntPtr user)
  390. {
  391. if (disposed)
  392. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  393. if (funcInterface == null)
  394. throw new ArgumentNullException("funcInterface");
  395. //TODO cleanup/move to the outlinefuncs class
  396. IntPtr funcInterfaceRef = Marshal.AllocHGlobal(OutlineFuncsRec.SizeInBytes);
  397. Marshal.WriteIntPtr(funcInterfaceRef, Marshal.GetFunctionPointerForDelegate(funcInterface.MoveFunction));
  398. Marshal.WriteIntPtr(funcInterfaceRef, (int)Marshal.OffsetOf(typeof(OutlineFuncsRec), "line_to"), Marshal.GetFunctionPointerForDelegate(funcInterface.LineFuction));
  399. Marshal.WriteIntPtr(funcInterfaceRef, (int)Marshal.OffsetOf(typeof(OutlineFuncsRec), "conic_to"), Marshal.GetFunctionPointerForDelegate(funcInterface.ConicFunction));
  400. Marshal.WriteIntPtr(funcInterfaceRef, (int)Marshal.OffsetOf(typeof(OutlineFuncsRec), "cubic_to"), Marshal.GetFunctionPointerForDelegate(funcInterface.CubicFunction));
  401. Marshal.WriteInt32(funcInterfaceRef, (int)Marshal.OffsetOf(typeof(OutlineFuncsRec), "shift"), funcInterface.Shift);
  402. Marshal.WriteInt32(funcInterfaceRef, (int)Marshal.OffsetOf(typeof(OutlineFuncsRec), "delta"), funcInterface.Delta);
  403. Error err = FT.FT_Outline_Decompose(reference, funcInterfaceRef, user);
  404. Marshal.FreeHGlobal(funcInterfaceRef);
  405. if (err != Error.Ok)
  406. throw new FreeTypeException(err);
  407. }
  408. /// <summary><para>
  409. /// Return an outline's ‘control box’. The control box encloses all the outline's points, including Bézier
  410. /// control points. Though it coincides with the exact bounding box for most glyphs, it can be slightly larger
  411. /// in some situations (like when rotating an outline which contains Bézier outside arcs).
  412. /// </para><para>
  413. /// Computing the control box is very fast, while getting the bounding box can take much more time as it needs
  414. /// to walk over all segments and arcs in the outline. To get the latter, you can use the ‘ftbbox’ component
  415. /// which is dedicated to this single task.
  416. /// </para></summary>
  417. /// <remarks>See <see cref="Glyph.GetCBox"/> for a discussion of tricky fonts.</remarks>
  418. /// <returns>The outline's control box.</returns>
  419. public BBox GetCBox()
  420. {
  421. if (disposed)
  422. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  423. IntPtr cboxRef;
  424. FT.FT_Outline_Get_CBox(reference, out cboxRef);
  425. return new BBox(cboxRef);
  426. }
  427. /// <summary>
  428. /// Render an outline within a bitmap. The outline's image is simply OR-ed to the target bitmap.
  429. /// </summary>
  430. /// <remarks><para>
  431. /// This function does NOT CREATE the bitmap, it only renders an outline image within the one you pass to it!
  432. /// Consequently, the various fields in ‘abitmap’ should be set accordingly.
  433. /// </para><para>
  434. /// It will use the raster corresponding to the default glyph format.
  435. /// </para><para>
  436. /// The value of the ‘num_grays’ field in ‘abitmap’ is ignored. If you select the gray-level rasterizer, and
  437. /// you want less than 256 gray levels, you have to use <see cref="Render(RasterParams)"/> directly.
  438. /// </para></remarks>
  439. /// <param name="bitmap">A pointer to the target bitmap descriptor.</param>
  440. public void GetBitmap(FTBitmap bitmap)
  441. {
  442. if (disposed)
  443. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  444. Error err = FT.FT_Outline_Get_Bitmap(parentLibrary.Reference, reference, bitmap.Reference);
  445. if (err != Error.Ok)
  446. throw new FreeTypeException(err);
  447. }
  448. /// <summary>
  449. /// Render an outline within a bitmap. The outline's image is simply OR-ed to the target bitmap.
  450. /// </summary>
  451. /// <remarks><para>
  452. /// This function does NOT CREATE the bitmap, it only renders an outline image within the one you pass to it!
  453. /// Consequently, the various fields in ‘abitmap’ should be set accordingly.
  454. /// </para><para>
  455. /// It will use the raster corresponding to the default glyph format.
  456. /// </para><para>
  457. /// The value of the ‘num_grays’ field in ‘abitmap’ is ignored. If you select the gray-level rasterizer, and
  458. /// you want less than 256 gray levels, you have to use <see cref="Render(Library, RasterParams)"/> directly.
  459. /// </para></remarks>
  460. /// <param name="library">A handle to a FreeType library object.</param>
  461. /// <param name="bitmap">A pointer to the target bitmap descriptor.</param>
  462. public void GetBitmap(Library library, FTBitmap bitmap)
  463. {
  464. if (disposed)
  465. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  466. if (library == null)
  467. throw new ArgumentNullException("library");
  468. if (bitmap == null)
  469. throw new ArgumentNullException("bitmap");
  470. Error err = FT.FT_Outline_Get_Bitmap(library.Reference, reference, bitmap.Reference);
  471. if (err != Error.Ok)
  472. throw new FreeTypeException(err);
  473. }
  474. /// <summary>
  475. /// Render an outline within a bitmap using the current scan-convert. This function uses an
  476. /// <see cref="RasterParams"/> structure as an argument, allowing advanced features like direct composition,
  477. /// translucency, etc.
  478. /// </summary>
  479. /// <remarks><para>
  480. /// You should know what you are doing and how <see cref="RasterParams"/> works to use this function.
  481. /// </para><para>
  482. /// The field ‘params.source’ will be set to ‘outline’ before the scan converter is called, which means that
  483. /// the value you give to it is actually ignored.
  484. /// </para><para>
  485. /// The gray-level rasterizer always uses 256 gray levels. If you want less gray levels, you have to provide
  486. /// your own span callback. See the <see cref="RasterFlags.Direct"/> value of the ‘flags’ field in the
  487. /// <see cref="RasterParams"/> structure for more details.
  488. /// </para></remarks>
  489. /// <param name="parameters">
  490. /// A pointer to an <see cref="RasterParams"/> structure used to describe the rendering operation.
  491. /// </param>
  492. public void Render(RasterParams parameters)
  493. {
  494. if (disposed)
  495. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  496. if (parameters == null)
  497. throw new ArgumentNullException("parameters");
  498. Error err = FT.FT_Outline_Render(parentLibrary.Reference, reference, parameters.Reference);
  499. if (err != Error.Ok)
  500. throw new FreeTypeException(err);
  501. }
  502. /// <summary>
  503. /// Render an outline within a bitmap using the current scan-convert. This function uses an
  504. /// <see cref="RasterParams"/> structure as an argument, allowing advanced features like direct composition,
  505. /// translucency, etc.
  506. /// </summary>
  507. /// <remarks><para>
  508. /// You should know what you are doing and how <see cref="RasterParams"/> works to use this function.
  509. /// </para><para>
  510. /// The field ‘params.source’ will be set to ‘outline’ before the scan converter is called, which means that
  511. /// the value you give to it is actually ignored.
  512. /// </para><para>
  513. /// The gray-level rasterizer always uses 256 gray levels. If you want less gray levels, you have to provide
  514. /// your own span callback. See the <see cref="RasterFlags.Direct"/> value of the ‘flags’ field in the
  515. /// <see cref="RasterParams"/> structure for more details.
  516. /// </para></remarks>
  517. /// <param name="library">A handle to a FreeType library object.</param>
  518. /// <param name="parameters">
  519. /// A pointer to an <see cref="RasterParams"/> structure used to describe the rendering operation.
  520. /// </param>
  521. public void Render(Library library, RasterParams parameters)
  522. {
  523. if (disposed)
  524. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  525. if (library == null)
  526. throw new ArgumentNullException("library");
  527. if (parameters == null)
  528. throw new ArgumentNullException("parameters");
  529. Error err = FT.FT_Outline_Render(library.Reference, reference, parameters.Reference);
  530. if (err != Error.Ok)
  531. throw new FreeTypeException(err);
  532. }
  533. /// <summary><para>
  534. /// This function analyzes a glyph outline and tries to compute its fill orientation (see
  535. /// <see cref="Orientation"/>). This is done by computing the direction of each global horizontal and/or
  536. /// vertical extrema within the outline.
  537. /// </para><para>
  538. /// Note that this will return <see cref="Orientation.TrueType"/> for empty outlines.
  539. /// </para></summary>
  540. /// <returns>The orientation.</returns>
  541. public Orientation GetOrientation()
  542. {
  543. if (disposed)
  544. throw new ObjectDisposedException("Outline", "Cannot access a disposed object.");
  545. return FT.FT_Outline_Get_Orientation(reference);
  546. }
  547. #endregion
  548. #region Glyph Stroker
  549. /// <summary>
  550. /// Retrieve the <see cref="StrokerBorder"/> value corresponding to the ‘inside’ borders of a given outline.
  551. /// </summary>
  552. /// <returns>The border index. <see cref="StrokerBorder.Right"/> for empty or invalid outlines.</returns>
  553. public StrokerBorder GetInsideBorder()
  554. {
  555. return FT.FT_Outline_GetInsideBorder(Reference);
  556. }
  557. /// <summary>
  558. /// Retrieve the <see cref="StrokerBorder"/> value corresponding to the ‘outside’ borders of a given outline.
  559. /// </summary>
  560. /// <returns>The border index. <see cref="StrokerBorder.Left"/> for empty or invalid outlines.</returns>
  561. public StrokerBorder GetOutsideBorder()
  562. {
  563. return FT.FT_Outline_GetOutsideBorder(Reference);
  564. }
  565. #endregion
  566. /// <summary>
  567. /// Disposes an instance of the <see cref="Outline"/> class.
  568. /// </summary>
  569. public void Dispose()
  570. {
  571. Dispose(true);
  572. GC.SuppressFinalize(this);
  573. }
  574. private void Dispose(bool disposing)
  575. {
  576. if (!disposed)
  577. {
  578. disposed = true;
  579. if (!duplicate)
  580. {
  581. Error err;
  582. if (parentLibrary != null)
  583. err = FT.FT_Outline_Done(parentLibrary.Reference, reference);
  584. else
  585. err = FT.FT_Outline_Done_Internal(parentMemory.Reference, reference);
  586. if (err != Error.Ok)
  587. throw new FreeTypeException(err);
  588. // removes itself from the parent Library, with a check to prevent this from happening when Library is
  589. // being disposed (Library disposes all it's children with a foreach loop, this causes an
  590. // InvalidOperationException for modifying a collection during enumeration)
  591. if (!parentLibrary.IsDisposed)
  592. parentLibrary.RemoveChildOutline(this);
  593. }
  594. reference = IntPtr.Zero;
  595. rec = default(OutlineRec);
  596. }
  597. }
  598. #endregion
  599. }
  600. }