PDFLibrary.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. using System;
  2. using System.Collections;
  3. using Paroxe.PdfRenderer.Internal;
  4. using System.Text;
  5. using UnityEngine;
  6. namespace Paroxe.PdfRenderer
  7. {
  8. public class PDFLibrary : IDisposable
  9. {
  10. public static readonly Encoding Encoding = new UnicodeEncoding(false, false, false);
  11. #if (UNITY_IOS || UNITY_WEBGL) && !UNITY_EDITOR
  12. public const string PLUGIN_ASSEMBLY = "__Internal";
  13. #else
  14. public const string PLUGIN_ASSEMBLY = "pdfrenderer";
  15. #endif
  16. public static object nativeLock = new object();
  17. public enum ErrorCode
  18. {
  19. ErrSuccess = 0, // No error.
  20. ErrUnknown = 1, // Unknown error.
  21. ErrFile = 2, // File not found or could not be opened.
  22. ErrFormat = 3, // File not in PDF format or corrupted.
  23. ErrPassword = 4, // Password required or incorrect password.
  24. ErrSecurity = 5, // Unsupported security scheme.
  25. ErrPage = 6 // Page not found or content error.
  26. }
  27. private static bool m_Disposed;
  28. private static PDFLibrary m_Instance;
  29. private static int m_RefCount;
  30. private
  31. #if UNITY_WEBGL && !UNITY_EDITOR
  32. static
  33. #endif
  34. bool m_IsInitialized;
  35. private static bool m_AlreadyDestroyed;
  36. #if UNITY_WEBGL || !UNITY_EDITOR
  37. private static bool m_AlreadyInitialized;
  38. #endif
  39. private PDFLibrary()
  40. {
  41. #if UNITY_WEBGL && !UNITY_EDITOR
  42. if (!m_AlreadyInitialized)
  43. {
  44. NativeMethods.PDFJS_InitLibrary();
  45. m_AlreadyInitialized = true;
  46. }
  47. #else
  48. #if !UNITY_EDITOR
  49. if (!m_AlreadyInitialized)
  50. #endif
  51. {
  52. m_IsInitialized = true;
  53. m_AlreadyDestroyed = false;
  54. NativeMethods.FPDF_InitLibrary();
  55. #if !UNITY_EDITOR
  56. m_AlreadyInitialized = true;
  57. #endif
  58. }
  59. #endif
  60. }
  61. ~PDFLibrary()
  62. {
  63. Dispose(false);
  64. }
  65. /// <summary>
  66. /// Return the last error code.
  67. /// </summary>
  68. /// <returns></returns>
  69. public static ErrorCode GetLastError()
  70. {
  71. #if UNITY_WEBGL && !UNITY_EDITOR
  72. return ErrorCode.ErrSuccess;
  73. #else
  74. Instance.EnsureInitialized();
  75. return (ErrorCode) NativeMethods.FPDF_GetLastError();
  76. #endif
  77. }
  78. public void Dispose()
  79. {
  80. Dispose(true);
  81. GC.SuppressFinalize(this);
  82. }
  83. protected virtual void Dispose(bool disposing)
  84. {
  85. lock (nativeLock)
  86. {
  87. if (!m_Disposed)
  88. {
  89. if (m_RefCount == 0)
  90. {
  91. #if PDFRENDERER_DEBUG
  92. PrintInstanceMap();
  93. #endif
  94. #if !UNITY_WEBGL || UNITY_EDITOR
  95. if (!m_AlreadyDestroyed)
  96. {
  97. m_AlreadyDestroyed = true;
  98. #if UNITY_EDITOR
  99. NativeMethods.FPDF_DestroyLibrary();
  100. #endif
  101. }
  102. #endif
  103. m_Disposed = true;
  104. m_Instance = null;
  105. }
  106. m_Disposed = true;
  107. }
  108. }
  109. }
  110. #if PDFRENDERER_DEBUG
  111. private static Dictionary<string, int> s_InstanceMap = new Dictionary<string, int>();
  112. private static void PrintInstanceMap()
  113. {
  114. foreach (string key in s_InstanceMap.Keys)
  115. {
  116. Debug.Log(key + " Count: " + s_InstanceMap[key]);
  117. }
  118. }
  119. #endif
  120. internal static void AddRef(string token)
  121. {
  122. lock (nativeLock)
  123. {
  124. #if PDFRENDERER_DEBUG
  125. if (s_InstanceMap.ContainsKey(token))
  126. s_InstanceMap[token] = s_InstanceMap[token] + 1;
  127. else
  128. s_InstanceMap.Add(token, 1);
  129. #endif
  130. ++m_RefCount;
  131. Instance.EnsureInitialized();
  132. }
  133. }
  134. internal static void RemoveRef(string token)
  135. {
  136. lock (nativeLock)
  137. {
  138. --m_RefCount;
  139. #if PDFRENDERER_DEBUG
  140. s_InstanceMap[token] = s_InstanceMap[token] - 1;
  141. #endif
  142. if (m_RefCount == 0)
  143. {
  144. if (m_Disposed)
  145. {
  146. #if PDFRENDERER_DEBUG
  147. PrintInstanceMap();
  148. #endif
  149. #if !UNITY_WEBGL || UNITY_EDITOR
  150. if (!m_AlreadyDestroyed)
  151. {
  152. m_AlreadyDestroyed = true;
  153. NativeMethods.FPDF_DestroyLibrary();
  154. }
  155. #endif
  156. m_Instance = null;
  157. }
  158. else
  159. m_Instance.Dispose();
  160. }
  161. }
  162. }
  163. public static PDFLibrary Instance
  164. {
  165. get
  166. {
  167. if (m_Instance == null)
  168. m_Instance = new PDFLibrary();
  169. return m_Instance;
  170. }
  171. }
  172. public void EnsureInitialized()
  173. {
  174. }
  175. public bool IsInitialized
  176. {
  177. get { return m_IsInitialized; }
  178. set { m_IsInitialized = value; }
  179. }
  180. public static int RefCount
  181. {
  182. get { return m_RefCount; }
  183. }
  184. public void ForceGabageCollection()
  185. {
  186. if (PDFLibraryMemoryWatcher.I != null)
  187. PDFLibraryMemoryWatcher.I.ForceGarbageCollection = true;
  188. }
  189. }
  190. public class PDFLibraryMemoryWatcher : MonoBehaviour
  191. {
  192. private static PDFLibraryMemoryWatcher s_I;
  193. public static PDFLibraryMemoryWatcher I
  194. {
  195. get { return s_I; }
  196. }
  197. [RuntimeInitializeOnLoadMethod]
  198. private static void EnsureInitialized()
  199. {
  200. if (s_I == null)
  201. {
  202. GameObject newObj = new GameObject("PDFLibraryMemoryWatcher");
  203. newObj.hideFlags = HideFlags.HideInHierarchy;
  204. DontDestroyOnLoad(newObj);
  205. s_I = newObj.AddComponent<PDFLibraryMemoryWatcher>();
  206. }
  207. }
  208. public bool ForceGarbageCollection { get; set; }
  209. private const int CollectPressure = 16;
  210. private const float CollectPressureInterval = 2.0f;
  211. private int m_LastCollectRefCount;
  212. private IEnumerator Start()
  213. {
  214. while (true)
  215. {
  216. if (ForceGarbageCollection || Mathf.Abs(m_LastCollectRefCount - PDFLibrary.RefCount) >= CollectPressure)
  217. {
  218. m_LastCollectRefCount = PDFLibrary.RefCount;
  219. if (ForceGarbageCollection)
  220. {
  221. ForceGarbageCollection = false;
  222. yield return null;
  223. }
  224. GC.Collect();
  225. float time = Time.unscaledTime;
  226. while (Time.unscaledTime - time < CollectPressureInterval)
  227. yield return null;
  228. }
  229. else
  230. {
  231. yield return null;
  232. }
  233. }
  234. }
  235. }
  236. }