Manager.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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.Collections.Generic;
  22. namespace SharpFont.Cache
  23. {
  24. /// <summary><para>
  25. /// This object corresponds to one instance of the cache-subsystem. It is used to cache one or more
  26. /// <see cref="Face"/> objects, along with corresponding <see cref="FTSize"/> objects.
  27. /// </para><para>
  28. /// The manager intentionally limits the total number of opened <see cref="Face"/> and <see cref="FTSize"/> objects
  29. /// to control memory usage. See the ‘max_faces’ and ‘max_sizes’ parameters of
  30. /// <see cref="Manager(Library, uint, uint, ulong, FaceRequester, IntPtr)"/>.
  31. /// </para><para>
  32. /// The manager is also used to cache ‘nodes’ of various types while limiting their total memory usage.
  33. /// </para><para>
  34. /// All limitations are enforced by keeping lists of managed objects in most-recently-used order, and flushing old
  35. /// nodes to make room for new ones.
  36. /// </para></summary>
  37. public sealed class Manager : IDisposable
  38. {
  39. #region Fields
  40. private IntPtr reference;
  41. private Library parentLibrary;
  42. private bool disposed;
  43. #endregion
  44. #region Constructors
  45. /// <summary>
  46. /// Initializes a new instance of the Manager class.
  47. /// </summary>
  48. /// <param name="library">The parent FreeType library handle to use.</param>
  49. /// <param name="maxFaces">
  50. /// Maximum number of opened <see cref="Face"/> objects managed by this cache instance. Use 0 for defaults.
  51. /// </param>
  52. /// <param name="maxSizes">
  53. /// Maximum number of opened <see cref="FTSize"/> objects managed by this cache instance. Use 0 for defaults.
  54. /// </param>
  55. /// <param name="maxBytes">
  56. /// Maximum number of bytes to use for cached data nodes. Use 0 for defaults. Note that this value does not
  57. /// account for managed <see cref="Face"/> and <see cref="FTSize"/> objects.
  58. /// </param>
  59. /// <param name="requester">
  60. /// An application-provided callback used to translate face IDs into real <see cref="Face"/> objects.
  61. /// </param>
  62. /// <param name="requestData">
  63. /// A generic pointer that is passed to the requester each time it is called (see <see cref="FaceRequester"/>).
  64. /// </param>
  65. [CLSCompliant(false)]
  66. public Manager(Library library, uint maxFaces, uint maxSizes, ulong maxBytes, FaceRequester requester, IntPtr requestData)
  67. {
  68. if (library == null)
  69. throw new ArgumentNullException("library");
  70. IntPtr mgrRef;
  71. Error err = FT.FTC_Manager_New(library.Reference, maxFaces, maxSizes, maxBytes, requester, requestData, out mgrRef);
  72. if (err != Error.Ok)
  73. throw new FreeTypeException(err);
  74. Reference = mgrRef;
  75. this.parentLibrary = library;
  76. library.AddChildManager(this);
  77. }
  78. /// <summary>
  79. /// Finalizes an instance of the Manager class.
  80. /// </summary>
  81. ~Manager()
  82. {
  83. Dispose(false);
  84. }
  85. #endregion
  86. #region Properties
  87. /// <summary>
  88. /// Gets a value indicating whether the object has been disposed.
  89. /// </summary>
  90. public bool IsDisposed
  91. {
  92. get
  93. {
  94. return disposed;
  95. }
  96. }
  97. internal IntPtr Reference
  98. {
  99. get
  100. {
  101. if (disposed)
  102. throw new ObjectDisposedException("Reference", "Cannot access a disposed object.");
  103. return reference;
  104. }
  105. set
  106. {
  107. if (disposed)
  108. throw new ObjectDisposedException("Reference", "Cannot access a disposed object.");
  109. reference = value;
  110. }
  111. }
  112. #endregion
  113. #region Public Members
  114. /// <summary>
  115. /// Empty a given cache manager. This simply gets rid of all the currently cached <see cref="Face"/> and
  116. /// <see cref="FTSize"/> objects within the manager.
  117. /// </summary>
  118. public void Reset()
  119. {
  120. if (disposed)
  121. throw new ObjectDisposedException("Manager", "Cannot access a disposed object.");
  122. FT.FTC_Manager_Reset(Reference);
  123. }
  124. /// <summary>
  125. /// Retrieve the <see cref="Face"/> object that corresponds to a given face ID through a cache manager.
  126. /// </summary>
  127. /// <remarks><para>
  128. /// The returned <see cref="Face"/> object is always owned by the manager. You should never try to discard it
  129. /// yourself.
  130. /// </para><para>
  131. /// The <see cref="Face"/> object doesn't necessarily have a current size object (i.e., <see cref="Face.Size"/>
  132. /// can be 0). If you need a specific ‘font size’, use <see cref="Manager.LookupSize"/> instead.
  133. /// </para><para>
  134. /// Never change the face's transformation matrix (i.e., never call the <see cref="Face.SetTransform"/>
  135. /// function) on a returned face! If you need to transform glyphs, do it yourself after glyph loading.
  136. /// </para><para>
  137. /// When you perform a lookup, out-of-memory errors are detected within the lookup and force incremental
  138. /// flushes of the cache until enough memory is released for the lookup to succeed.
  139. /// </para><para>
  140. /// If a lookup fails with <see cref="Error.OutOfMemory"/> the cache has already been completely flushed, and
  141. /// still no memory was available for the operation.
  142. /// </para></remarks>
  143. /// <param name="faceId">The ID of the face object.</param>
  144. /// <returns>A handle to the face object.</returns>
  145. public Face LookupFace(IntPtr faceId)
  146. {
  147. if (disposed)
  148. throw new ObjectDisposedException("Manager", "Cannot access a disposed object.");
  149. IntPtr faceRef;
  150. Error err = FT.FTC_Manager_LookupFace(Reference, faceId, out faceRef);
  151. if (err != Error.Ok)
  152. throw new FreeTypeException(err);
  153. //HACK fix this later.
  154. return new Face(faceRef, null);
  155. }
  156. /// <summary>
  157. /// Retrieve the <see cref="FTSize"/> object that corresponds to a given <see cref="Scaler"/> pointer through a
  158. /// cache manager.
  159. /// </summary>
  160. /// <remarks><para>
  161. /// The returned <see cref="FTSize"/> object is always owned by the/ manager. You should never try to discard
  162. /// it by yourself.
  163. /// </para><para>
  164. /// You can access the parent <see cref="Face"/> object simply as <see cref="FTSize.Face"/> if you need it.
  165. /// Note that this object is also owned by the manager.
  166. /// </para><para>
  167. /// When you perform a lookup, out-of-memory errors are detected within the lookup and force incremental
  168. /// flushes of the cache until enough memory is released for the lookup to succeed.
  169. /// </para><para>
  170. /// If a lookup fails with <see cref="Error.OutOfMemory"/> the cache has already been completely flushed, and
  171. /// still no memory is available for the operation.
  172. /// </para></remarks>
  173. /// <param name="scaler">A scaler handle.</param>
  174. /// <returns>A handle to the size object.</returns>
  175. public FTSize LookupSize(Scaler scaler)
  176. {
  177. if (disposed)
  178. throw new ObjectDisposedException("Manager", "Cannot access a disposed object.");
  179. IntPtr sizeRef;
  180. Error err = FT.FTC_Manager_LookupSize(Reference, scaler.Reference, out sizeRef);
  181. if (err != Error.Ok)
  182. throw new FreeTypeException(err);
  183. //HACK fix this later.
  184. return new FTSize(sizeRef, false, null);
  185. }
  186. /// <summary>
  187. /// A special function used to indicate to the cache manager that a given FTC_FaceID is no longer valid, either
  188. /// because its content changed, or because it was deallocated or uninstalled.
  189. /// </summary>
  190. /// <remarks><para>
  191. /// This function flushes all nodes from the cache corresponding to this ‘faceID’, with the
  192. /// exception of nodes with a non-null reference count.
  193. /// </para><para>
  194. /// Such nodes are however modified internally so as to never appear in later lookups with the same
  195. /// ‘faceID’ value, and to be immediately destroyed when released by all their users.
  196. /// </para></remarks>
  197. /// <param name="faceId">The FTC_FaceID to be removed.</param>
  198. public void RemoveFaceId(IntPtr faceId)
  199. {
  200. if (disposed)
  201. throw new ObjectDisposedException("Manager", "Cannot access a disposed object.");
  202. FT.FTC_Manager_RemoveFaceID(Reference, faceId);
  203. }
  204. #endregion
  205. #region IDisposable Members
  206. /// <summary>
  207. /// Disposes the Manager.
  208. /// </summary>
  209. public void Dispose()
  210. {
  211. Dispose(true);
  212. GC.SuppressFinalize(this);
  213. }
  214. private void Dispose(bool disposing)
  215. {
  216. if (!disposed)
  217. {
  218. disposed = true;
  219. FT.FTC_Manager_Done(reference);
  220. reference = IntPtr.Zero;
  221. // removes itself from the parent Library, with a check to prevent this from happening when Library is
  222. // being disposed (Library disposes all it's children with a foreach loop, this causes an
  223. // InvalidOperationException for modifying a collection during enumeration)
  224. if (!parentLibrary.IsDisposed)
  225. parentLibrary.RemoveChildManager(this);
  226. }
  227. }
  228. #endregion
  229. }
  230. }