XRoom_Unity/Assets/Paroxe/PDFRenderer/Internal/Scripts/NativeDisposeCoordinator.cs
2025-05-31 10:20:20 +03:30

243 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace Paroxe.PdfRenderer.Internal
{
public interface ICoordinatedNativeDisposable
{
IntPtr NativePointer { get; }
ICoordinatedNativeDisposable NativeParent { get; }
Action<IntPtr> GetDisposeMethod();
}
#if !UNITY_WEBGL || UNITY_EDITOR
public struct NativePointerrWithType
{
public Type ManagedType;
public IntPtr NativePointerr;
public NativePointerrWithType(Type managedType, IntPtr nativePointerr)
{
ManagedType = managedType;
NativePointerr = nativePointerr;
}
}
public class NativeDisposeCoordinator
{
private readonly NativeDependencyTree m_DependencyRoot;
private readonly Dictionary<NativePointerrWithType, NativeDependencyTree> m_DependencyMap;
private readonly Dictionary<Type, Action<IntPtr>> m_DisposeMethods = new Dictionary<Type, Action<IntPtr>>();
private bool m_IsLibraryInitialized;
private List<NativeDependencyTree> m_PendingDisposes = new List<NativeDependencyTree>(128);
private static Predicate<NativeDependencyTree> m_RemoveDisposedNodesPredicate = t => t.IsDisposed;
public bool IsLibraryInitialized
{
get { return m_IsLibraryInitialized; }
}
public NativeDisposeCoordinator()
{
m_DependencyRoot = new NativeDependencyTree(new NativePointerrWithType(null, IntPtr.Zero), null);
m_DependencyMap = new Dictionary<NativePointerrWithType, NativeDependencyTree>();
}
public void EnsureNativeLibraryIsInitialized()
{
lock (PDFLibrary.nativeLock)
{
if (!m_IsLibraryInitialized)
{
NativeMethods.FPDF_InitLibrary();
m_IsLibraryInitialized = true;
}
}
}
public void AddReference(ICoordinatedNativeDisposable nativeObject)
{
lock (PDFLibrary.nativeLock)
{
EnsureNativeLibraryIsInitialized();
NativeDependencyTree node;
NativePointerrWithType handlerWithType = new NativePointerrWithType(nativeObject.GetType(), nativeObject.NativePointer);
if (!m_DependencyMap.TryGetValue(handlerWithType, out node))
{
if (nativeObject.NativeParent == null)
{
node = m_DependencyRoot.AddChild(handlerWithType);
}
else
{
NativeDependencyTree parentNode = null;
if (m_DependencyMap.TryGetValue(new NativePointerrWithType(nativeObject.NativeParent.GetType(), nativeObject.NativeParent.NativePointer), out parentNode))
{
node = parentNode.AddChild(handlerWithType);
}
else
throw new InvalidOperationException("Supplied parent NativePointerr is not found within the dependencies tree.");
}
m_DependencyMap.Add(handlerWithType, node);
}
++node.ReferenceCount;
}
}
public void RemoveReference(ICoordinatedNativeDisposable nativeObject)
{
if (!m_DisposeMethods.ContainsKey(nativeObject.GetType()))
m_DisposeMethods.Add(nativeObject.GetType(), nativeObject.GetDisposeMethod());
lock (PDFLibrary.nativeLock)
{
NativeDependencyTree node = null;
NativePointerrWithType handlerWithType = new NativePointerrWithType(nativeObject.GetType(), nativeObject.NativePointer);
if (m_DependencyMap.TryGetValue(handlerWithType, out node))
{
--node.ReferenceCount;
if (node.ReferenceCount == 0)
{
if (node.ChildCount == 0)
{
DisposeNativeObject(node);
node.Parent.RemoveChild(node);
m_DependencyMap.Remove(node.NativePointerrWithType);
}
else
{
m_PendingDisposes.Add(node);
}
}
}
bool disposing = false;
do
{
disposing = ProcessPendingDisposes();
}
while (disposing);
if (m_IsLibraryInitialized && m_DependencyMap.Count == 0)
{
NativeMethods.FPDF_DestroyLibrary();
m_IsLibraryInitialized = false;
}
}
}
private void DisposeNativeObject(NativeDependencyTree handler)
{
m_DisposeMethods[handler.NativePointerrWithType.ManagedType](handler.NativePointerrWithType.NativePointerr);
handler.IsDisposed = true;
}
private bool ProcessPendingDisposes()
{
if (!m_PendingDisposes.Any())
return false;
bool disposing = false;
foreach (NativeDependencyTree node in m_PendingDisposes)
{
if (node.ChildCount == 0)
{
disposing = true;
node.Parent.RemoveChild(node);
m_DependencyMap.Remove(node.NativePointerrWithType);
DisposeNativeObject(node);
}
}
if (disposing)
m_PendingDisposes.RemoveAll(m_RemoveDisposedNodesPredicate);
return disposing;
}
}
public class NativeDependencyTree
{
private readonly NativePointerrWithType m_NativePointerWithType;
private readonly LinkedList<NativeDependencyTree> m_Children;
private readonly NativeDependencyTree m_Parent;
private int m_ReferenceCount;
private bool m_IsDisposed;
public NativePointerrWithType NativePointerrWithType
{
get { return m_NativePointerWithType; }
}
public int ReferenceCount
{
get { return m_ReferenceCount; }
set { m_ReferenceCount = value; }
}
public bool IsDisposed
{
get { return m_IsDisposed; }
set { m_IsDisposed = value; }
}
public int ChildCount
{
get { return m_Children.Count; }
}
public NativeDependencyTree Parent
{
get { return m_Parent; }
}
public LinkedList<NativeDependencyTree> Children
{
get { return m_Children; }
}
public NativeDependencyTree(NativePointerrWithType nativePointerrWithType, NativeDependencyTree parentNode)
{
m_NativePointerWithType = nativePointerrWithType;
m_Parent = parentNode;
m_Children = new LinkedList<NativeDependencyTree>();
}
public NativeDependencyTree AddChild(NativePointerrWithType nativePointerrWithType)
{
NativeDependencyTree node = new NativeDependencyTree(nativePointerrWithType, this);
m_Children.AddFirst(node);
return node;
}
public void RemoveChild(NativeDependencyTree node)
{
m_Children.Remove(node);
}
}
#endif
}