#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Globalization;
using PdfSharp.Drawing;
namespace PdfSharp.Pdf.Advanced
{
///
/// Contains all external PDF files from which PdfFormXObjects are imported into the current document.
///
internal sealed class PdfFormXObjectTable : PdfResourceTable
{
// The name PdfFormXObjectTable is technically not correct, because in contrast to PdfFontTable
// or PdfImageTable this class holds no PdfFormXObject objects. Actually it holds instances of
// the class ImportedObjectTable, one for each external document. The PdfFormXObject instances
// are not cached, because they hold a transformation matrix that make them unique. If the user
// wants to use a particual page of a PdfFormXObject more than once, he must reuse the object
// before he changes the PageNumber or the transformation matrix. In other words this class
// caches the indirect objects of an external form, not the form itself.
///
/// Initializes a new instance of this class, which is a singleton for each document.
///
public PdfFormXObjectTable(PdfDocument document)
: base(document)
{ }
///
/// Gets a PdfFormXObject from an XPdfForm. Because the returned objects must be unique, always
/// a new instance of PdfFormXObject is created if none exists for the specified form.
///
public PdfFormXObject GetForm(XForm form)
{
// If the form already has a PdfFormXObject, return it.
if (form._pdfForm != null)
{
Debug.Assert(form.IsTemplate, "An XPdfForm must not have a PdfFormXObject.");
if (ReferenceEquals(form._pdfForm.Owner, Owner))
return form._pdfForm;
//throw new InvalidOperationException("Because of a current limitation of PDFsharp an XPdfForm object can be used only within one single PdfDocument.");
// Dispose PdfFromXObject when document has changed
form._pdfForm = null;
}
XPdfForm pdfForm = form as XPdfForm;
if (pdfForm != null)
{
// Is the external PDF file from which is imported already known for the current document?
Selector selector = new Selector(form);
PdfImportedObjectTable importedObjectTable;
if (!_forms.TryGetValue(selector, out importedObjectTable))
{
// No: Get the external document from the form and create ImportedObjectTable.
PdfDocument doc = pdfForm.ExternalDocument;
importedObjectTable = new PdfImportedObjectTable(Owner, doc);
_forms[selector] = importedObjectTable;
}
PdfFormXObject xObject = importedObjectTable.GetXObject(pdfForm.PageNumber);
if (xObject == null)
{
xObject = new PdfFormXObject(Owner, importedObjectTable, pdfForm);
importedObjectTable.SetXObject(pdfForm.PageNumber, xObject);
}
return xObject;
}
Debug.Assert(form.GetType() == typeof(XForm));
form._pdfForm = new PdfFormXObject(Owner, form);
return form._pdfForm;
}
///
/// Gets the imported object table.
///
public PdfImportedObjectTable GetImportedObjectTable(PdfPage page)
{
// Is the external PDF file from which is imported already known for the current document?
Selector selector = new Selector(page);
PdfImportedObjectTable importedObjectTable;
if (!_forms.TryGetValue(selector, out importedObjectTable))
{
importedObjectTable = new PdfImportedObjectTable(Owner, page.Owner);
_forms[selector] = importedObjectTable;
}
return importedObjectTable;
}
///
/// Gets the imported object table.
///
public PdfImportedObjectTable GetImportedObjectTable(PdfDocument document)
{
if (document == null)
throw new ArgumentNullException("document");
// Is the external PDF file from which is imported already known for the current document?
Selector selector = new Selector(document);
PdfImportedObjectTable importedObjectTable;
if (!_forms.TryGetValue(selector, out importedObjectTable))
{
// Create new table for document.
importedObjectTable = new PdfImportedObjectTable(Owner, document);
_forms[selector] = importedObjectTable;
}
return importedObjectTable;
}
public void DetachDocument(PdfDocument.DocumentHandle handle)
{
if (handle.IsAlive)
{
foreach (Selector selector in _forms.Keys)
{
PdfImportedObjectTable table = _forms[selector];
if (table.ExternalDocument != null && table.ExternalDocument.Handle == handle)
{
_forms.Remove(selector);
break;
}
}
}
// Clean table
bool itemRemoved = true;
while (itemRemoved)
{
itemRemoved = false;
foreach (Selector selector in _forms.Keys)
{
PdfImportedObjectTable table = _forms[selector];
if (table.ExternalDocument == null)
{
_forms.Remove(selector);
itemRemoved = true;
break;
}
}
}
}
///
/// Map from Selector to PdfImportedObjectTable.
///
readonly Dictionary _forms = new Dictionary();
///
/// A collection of information that uniquely identifies a particular ImportedObjectTable.
///
public class Selector
{
///
/// Initializes a new instance of FormSelector from an XPdfForm.
///
public Selector(XForm form)
{
// HACK: just use full path to identify
_path = form._path.ToLowerInvariant();
}
///
/// Initializes a new instance of FormSelector from a PdfPage.
///
public Selector(PdfPage page)
{
PdfDocument owner = page.Owner;
_path = "*" + owner.Guid.ToString("B");
_path = _path.ToLowerInvariant();
}
public Selector(PdfDocument document)
{
_path = "*" + document.Guid.ToString("B");
_path = _path.ToLowerInvariant();
}
public string Path
{
get { return _path; }
set { _path = value; }
}
string _path;
public override bool Equals(object obj)
{
Selector selector = obj as Selector;
if (selector == null)
return false;
return _path == selector._path;
}
public override int GetHashCode()
{
return _path.GetHashCode();
}
}
}
}