diff -r bd595ad770fc -r 1c2f13fd785c web/enmi/Zend/Pdf/ElementFactory.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi/Zend/Pdf/ElementFactory.php Thu Jan 20 19:30:54 2011 +0100 @@ -0,0 +1,446 @@ + Zend_Pdf_Element_Object + * + * @var array + */ + private $_modifiedObjects = array(); + + /** + * List of the removed objects + * + * Array: ojbectNumber => Zend_Pdf_Element_Object + * + * @var SplObjectStorage + */ + private $_removedObjects; + + /** + * List of registered objects. + * Used for resources clean up when factory is destroyed. + * + * Array of Zend_Pdf_Element objects + * + * @var array + */ + private $_registeredObjects = array(); + + /** + * PDF object counter. + * Actually it's an object number for new PDF object + * + * @var integer + */ + private $_objectCount; + + + /** + * List of the attached object factories. + * Array of Zend_Pdf_ElementFactory_Interface objects + * + * @var array + */ + private $_attachedFactories = array(); + + + /** + * Factory internal id + * + * @var integer + */ + private $_factoryId; + + /** + * Identity, used for factory id generation + * + * @var integer + */ + private static $_identity = 0; + + + /** + * Internal cache to save calculated shifts + * + * @var array + */ + private $_shiftCalculationCache = array(); + + + /** + * Object constructor + * + * @param integer $objCount + */ + public function __construct($objCount) + { + $this->_objectCount = (int)$objCount; + $this->_factoryId = self::$_identity++; + $this->_removedObjects = new SplObjectStorage(); + } + + + /** + * Get factory + * + * @return Zend_Pdf_ElementFactory_Interface + */ + public function getFactory() + { + return $this; + } + + /** + * Factory generator + * + * @param integer $objCount + * @return Zend_Pdf_ElementFactory_Interface + */ + static public function createFactory($objCount) + { + require_once 'Zend/Pdf/ElementFactory/Proxy.php'; + return new Zend_Pdf_ElementFactory_Proxy(new Zend_Pdf_ElementFactory($objCount)); + } + + /** + * Close factory and clean-up resources + * + * @internal + */ + public function close() + { + $this->_modifiedObjects = null; + $this->_removedObjects = null; + $this->_attachedFactories = null; + + foreach ($this->_registeredObjects as $obj) { + $obj->cleanUp(); + } + $this->_registeredObjects = null; + } + + /** + * Get source factory object + * + * @return Zend_Pdf_ElementFactory + */ + public function resolve() + { + return $this; + } + + /** + * Get factory ID + * + * @return integer + */ + public function getId() + { + return $this->_factoryId; + } + + /** + * Set object counter + * + * @param integer $objCount + */ + public function setObjectCount($objCount) + { + $this->_objectCount = (int)$objCount; + } + + /** + * Get object counter + * + * @return integer + */ + public function getObjectCount() + { + $count = $this->_objectCount; + + foreach ($this->_attachedFactories as $attached) { + $count += $attached->getObjectCount() - 1; // -1 as "0" object is a special case and shared between factories + } + + return $count; + } + + + /** + * Attach factory to the current; + * + * @param Zend_Pdf_ElementFactory_Interface $factory + */ + public function attach(Zend_Pdf_ElementFactory_Interface $factory) + { + if ( $factory === $this || isset($this->_attachedFactories[$factory->getId()])) { + /** + * Don't attach factory twice. + * We do not check recusively because of nature of attach operation + * (Pages are always attached to the Documents, Fonts are always attached + * to the pages even if pages already use Document level object factory and so on) + */ + return; + } + + $this->_attachedFactories[$factory->getId()] = $factory; + } + + + /** + * Calculate object enumeration shift. + * + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + */ + public function calculateShift(Zend_Pdf_ElementFactory_Interface $factory) + { + if ($factory === $this) { + return 0; + } + + if (isset($this->_shiftCalculationCache[$factory->_factoryId])) { + return $this->_shiftCalculationCache[$factory->_factoryId]; + } + + $shift = $this->_objectCount - 1; + + foreach ($this->_attachedFactories as $subFactory) { + $subFactoryShift = $subFactory->calculateShift($factory); + + if ($subFactoryShift != -1) { + // context found + $this->_shiftCalculationCache[$factory->_factoryId] = $shift + $subFactoryShift; + return $shift + $subFactoryShift; + } else { + $shift += $subFactory->getObjectCount()-1; + } + } + + $this->_shiftCalculationCache[$factory->_factoryId] = -1; + return -1; + } + + /** + * Clean enumeration shift cache. + * Has to be used after PDF render operation to let followed updates be correct. + */ + public function cleanEnumerationShiftCache() + { + $this->_shiftCalculationCache = array(); + + foreach ($this->_attachedFactories as $attached) { + $attached->cleanEnumerationShiftCache(); + } + } + + /** + * Retrive object enumeration shift. + * + * @param Zend_Pdf_ElementFactory_Interface $factory + * @return integer + * @throws Zend_Pdf_Exception + */ + public function getEnumerationShift(Zend_Pdf_ElementFactory_Interface $factory) + { + if (($shift = $this->calculateShift($factory)) == -1) { + require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Wrong object context'); + } + + return $shift; + } + + /** + * Mark object as modified in context of current factory. + * + * @param Zend_Pdf_Element_Object $obj + * @throws Zend_Pdf_Exception + */ + public function markAsModified(Zend_Pdf_Element_Object $obj) + { + if ($obj->getFactory() !== $this) { + require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object is not generated by this factory'); + } + + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + } + + + /** + * Remove object in context of current factory. + * + * @param Zend_Pdf_Element_Object $obj + * @throws Zend_Pdf_Exception + */ + public function remove(Zend_Pdf_Element_Object $obj) + { + if (!$obj->compareFactory($this)) { + require_once 'Zend/Pdf/Exception.php'; + throw new Zend_Pdf_Exception('Object is not generated by this factory'); + } + + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + $this->_removedObjects->attach($obj); + } + + + /** + * Generate new Zend_Pdf_Element_Object + * + * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. + * + * @param Zend_Pdf_Element $objectValue + * @return Zend_Pdf_Element_Object + */ + public function newObject(Zend_Pdf_Element $objectValue) + { + require_once 'Zend/Pdf/Element/Object.php'; + $obj = new Zend_Pdf_Element_Object($objectValue, $this->_objectCount++, 0, $this); + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + return $obj; + } + + /** + * Generate new Zend_Pdf_Element_Object_Stream + * + * @todo Reusage of the freed object. It's not a support of new feature, but only improvement. + * + * @param mixed $objectValue + * @return Zend_Pdf_Element_Object_Stream + */ + public function newStreamObject($streamValue) + { + require_once 'Zend/Pdf/Element/Object/Stream.php'; + $obj = new Zend_Pdf_Element_Object_Stream($streamValue, $this->_objectCount++, 0, $this); + $this->_modifiedObjects[$obj->getObjNum()] = $obj; + return $obj; + } + + + /** + * Enumerate modified objects. + * Returns array of Zend_Pdf_UpdateInfoContainer + * + * @param Zend_Pdf_ElementFactory_Interface $rootFactory + * @return array + */ + public function listModifiedObjects($rootFactory = null) + { + if ($rootFactory == null) { + $rootFactory = $this; + $shift = 0; + } else { + $shift = $rootFactory->getEnumerationShift($this); + } + + ksort($this->_modifiedObjects); + + $result = array(); + require_once 'Zend/Pdf/UpdateInfoContainer.php'; + foreach ($this->_modifiedObjects as $objNum => $obj) { + if ($this->_removedObjects->contains($obj)) { + $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, + $obj->getGenNum()+1, + true); + } else { + $result[$objNum+$shift] = new Zend_Pdf_UpdateInfoContainer($objNum + $shift, + $obj->getGenNum(), + false, + $obj->dump($rootFactory)); + } + } + + foreach ($this->_attachedFactories as $factory) { + $result += $factory->listModifiedObjects($rootFactory); + } + + return $result; + } + + /** + * Register object in the factory + * + * It's used to clear "parent object" referencies when factory is closed and clean up resources + * + * @param string $refString + * @param Zend_Pdf_Element_Object $obj + */ + public function registerObject(Zend_Pdf_Element_Object $obj, $refString) + { + $this->_registeredObjects[$refString] = $obj; + } + + /** + * Fetch object specified by reference + * + * @param string $refString + * @return Zend_Pdf_Element_Object|null + */ + public function fetchObject($refString) + { + if (!isset($this->_registeredObjects[$refString])) { + return null; + } + return $this->_registeredObjects[$refString]; + } + + + /** + * Check if PDF file was modified + * + * @return boolean + */ + public function isModified() + { + if (count($this->_modifiedObjects) != 0) { + return true; + } + + foreach ($this->_attachedFactories as $subFactory) { + if ($subFactory->isModified()) { + return true; + } + } + + return false; + } +} +