You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

404 lines
14 KiB

11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Pdf
  17. * @subpackage Actions
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /** Internally used classes */
  23. // require_once 'Zend/Pdf/Element.php';
  24. // require_once 'Zend/Pdf/Element/Array.php';
  25. /** Zend_Pdf_Target */
  26. // require_once 'Zend/Pdf/Target.php';
  27. /**
  28. * Abstract PDF action representation class
  29. *
  30. * @package Zend_Pdf
  31. * @subpackage Actions
  32. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. abstract class Zend_Pdf_Action extends Zend_Pdf_Target implements RecursiveIterator, Countable
  36. {
  37. /**
  38. * Action dictionary
  39. *
  40. * @var Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference
  41. */
  42. protected $_actionDictionary;
  43. /**
  44. * An original list of chained actions
  45. *
  46. * @var array Array of Zend_Pdf_Action objects
  47. */
  48. protected $_originalNextList;
  49. /**
  50. * A list of next actions in actions tree (used for actions chaining)
  51. *
  52. * @var array Array of Zend_Pdf_Action objects
  53. */
  54. public $next = array();
  55. /**
  56. * Object constructor
  57. *
  58. * @param Zend_Pdf_Element_Dictionary $dictionary
  59. * @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references
  60. * @throws Zend_Pdf_Exception
  61. */
  62. public function __construct(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions)
  63. {
  64. // require_once 'Zend/Pdf/Element.php';
  65. if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
  66. // require_once 'Zend/Pdf/Exception.php';
  67. throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
  68. }
  69. $this->_actionDictionary = $dictionary;
  70. if ($dictionary->Next !== null) {
  71. if ($dictionary->Next instanceof Zend_Pdf_Element_Dictionary) {
  72. // Check if dictionary object is not already processed
  73. if (!$processedActions->contains($dictionary->Next)) {
  74. $processedActions->attach($dictionary->Next);
  75. $this->next[] = Zend_Pdf_Action::load($dictionary->Next, $processedActions);
  76. }
  77. } else if ($dictionary->Next instanceof Zend_Pdf_Element_Array) {
  78. foreach ($dictionary->Next->items as $chainedActionDictionary) {
  79. // Check if dictionary object is not already processed
  80. if (!$processedActions->contains($chainedActionDictionary)) {
  81. $processedActions->attach($chainedActionDictionary);
  82. $this->next[] = Zend_Pdf_Action::load($chainedActionDictionary, $processedActions);
  83. }
  84. }
  85. } else {
  86. // require_once 'Zend/Pdf/Exception.php';
  87. throw new Zend_Pdf_Exception('PDF Action dictionary Next entry must be a dictionary or an array.');
  88. }
  89. }
  90. $this->_originalNextList = $this->next;
  91. }
  92. /**
  93. * Load PDF action object using specified dictionary
  94. *
  95. * @internal
  96. * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object)
  97. * @param SplObjectStorage $processedActions list of already processed action dictionaries, used to avoid cyclic references
  98. * @return Zend_Pdf_Action
  99. * @throws Zend_Pdf_Exception
  100. */
  101. public static function load(Zend_Pdf_Element $dictionary, SplObjectStorage $processedActions = null)
  102. {
  103. if ($processedActions === null) {
  104. $processedActions = new SplObjectStorage();
  105. }
  106. // require_once 'Zend/Pdf/Element.php';
  107. if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
  108. // require_once 'Zend/Pdf/Exception.php';
  109. throw new Zend_Pdf_Exception('$dictionary mast be a direct or an indirect dictionary object.');
  110. }
  111. if (isset($dictionary->Type) && $dictionary->Type->value != 'Action') {
  112. // require_once 'Zend/Pdf/Exception.php';
  113. throw new Zend_Pdf_Exception('Action dictionary Type entry must be set to \'Action\'.');
  114. }
  115. if ($dictionary->S === null) {
  116. // require_once 'Zend/Pdf/Exception.php';
  117. throw new Zend_Pdf_Exception('Action dictionary must contain S entry');
  118. }
  119. switch ($dictionary->S->value) {
  120. case 'GoTo':
  121. // require_once 'Zend/Pdf/Action/GoTo.php';
  122. return new Zend_Pdf_Action_GoTo($dictionary, $processedActions);
  123. break;
  124. case 'GoToR':
  125. // require_once 'Zend/Pdf/Action/GoToR.php';
  126. return new Zend_Pdf_Action_GoToR($dictionary, $processedActions);
  127. break;
  128. case 'GoToE':
  129. // require_once 'Zend/Pdf/Action/GoToE.php';
  130. return new Zend_Pdf_Action_GoToE($dictionary, $processedActions);
  131. break;
  132. case 'Launch':
  133. // require_once 'Zend/Pdf/Action/Launch.php';
  134. return new Zend_Pdf_Action_Launch($dictionary, $processedActions);
  135. break;
  136. case 'Thread':
  137. // require_once 'Zend/Pdf/Action/Thread.php';
  138. return new Zend_Pdf_Action_Thread($dictionary, $processedActions);
  139. break;
  140. case 'URI':
  141. // require_once 'Zend/Pdf/Action/URI.php';
  142. return new Zend_Pdf_Action_URI($dictionary, $processedActions);
  143. break;
  144. case 'Sound':
  145. // require_once 'Zend/Pdf/Action/Sound.php';
  146. return new Zend_Pdf_Action_Sound($dictionary, $processedActions);
  147. break;
  148. case 'Movie':
  149. // require_once 'Zend/Pdf/Action/Movie.php';
  150. return new Zend_Pdf_Action_Movie($dictionary, $processedActions);
  151. break;
  152. case 'Hide':
  153. // require_once 'Zend/Pdf/Action/Hide.php';
  154. return new Zend_Pdf_Action_Hide($dictionary, $processedActions);
  155. break;
  156. case 'Named':
  157. // require_once 'Zend/Pdf/Action/Named.php';
  158. return new Zend_Pdf_Action_Named($dictionary, $processedActions);
  159. break;
  160. case 'SubmitForm':
  161. // require_once 'Zend/Pdf/Action/SubmitForm.php';
  162. return new Zend_Pdf_Action_SubmitForm($dictionary, $processedActions);
  163. break;
  164. case 'ResetForm':
  165. // require_once 'Zend/Pdf/Action/ResetForm.php';
  166. return new Zend_Pdf_Action_ResetForm($dictionary, $processedActions);
  167. break;
  168. case 'ImportData':
  169. // require_once 'Zend/Pdf/Action/ImportData.php';
  170. return new Zend_Pdf_Action_ImportData($dictionary, $processedActions);
  171. break;
  172. case 'JavaScript':
  173. // require_once 'Zend/Pdf/Action/JavaScript.php';
  174. return new Zend_Pdf_Action_JavaScript($dictionary, $processedActions);
  175. break;
  176. case 'SetOCGState':
  177. // require_once 'Zend/Pdf/Action/SetOCGState.php';
  178. return new Zend_Pdf_Action_SetOCGState($dictionary, $processedActions);
  179. break;
  180. case 'Rendition':
  181. // require_once 'Zend/Pdf/Action/Rendition.php';
  182. return new Zend_Pdf_Action_Rendition($dictionary, $processedActions);
  183. break;
  184. case 'Trans':
  185. // require_once 'Zend/Pdf/Action/Trans.php';
  186. return new Zend_Pdf_Action_Trans($dictionary, $processedActions);
  187. break;
  188. case 'GoTo3DView':
  189. // require_once 'Zend/Pdf/Action/GoTo3DView.php';
  190. return new Zend_Pdf_Action_GoTo3DView($dictionary, $processedActions);
  191. break;
  192. default:
  193. // require_once 'Zend/Pdf/Action/Unknown.php';
  194. return new Zend_Pdf_Action_Unknown($dictionary, $processedActions);
  195. break;
  196. }
  197. }
  198. /**
  199. * Get resource
  200. *
  201. * @internal
  202. * @return Zend_Pdf_Element
  203. */
  204. public function getResource()
  205. {
  206. return $this->_actionDictionary;
  207. }
  208. /**
  209. * Dump Action and its child actions into PDF structures
  210. *
  211. * Returns dictionary indirect object or reference
  212. *
  213. * @internal
  214. * @param Zend_Pdf_ElementFactory $factory Object factory for newly created indirect objects
  215. * @param SplObjectStorage $processedActions list of already processed actions (used to prevent infinity loop caused by cyclic references)
  216. * @return Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference Dictionary indirect object
  217. */
  218. public function dumpAction(Zend_Pdf_ElementFactory_Interface $factory, SplObjectStorage $processedActions = null)
  219. {
  220. if ($processedActions === null) {
  221. $processedActions = new SplObjectStorage();
  222. }
  223. if ($processedActions->contains($this)) {
  224. // require_once 'Zend/Pdf/Exception.php';
  225. throw new Zend_Pdf_Exception('Action chain cyclyc reference is detected.');
  226. }
  227. $processedActions->attach($this);
  228. $childListUpdated = false;
  229. if (count($this->_originalNextList) != count($this->next)) {
  230. // If original and current children arrays have different size then children list was updated
  231. $childListUpdated = true;
  232. } else if ( !(array_keys($this->_originalNextList) === array_keys($this->next)) ) {
  233. // If original and current children arrays have different keys (with a glance to an order) then children list was updated
  234. $childListUpdated = true;
  235. } else {
  236. foreach ($this->next as $key => $childAction) {
  237. if ($this->_originalNextList[$key] !== $childAction) {
  238. $childListUpdated = true;
  239. break;
  240. }
  241. }
  242. }
  243. if ($childListUpdated) {
  244. $this->_actionDictionary->touch();
  245. switch (count($this->next)) {
  246. case 0:
  247. $this->_actionDictionary->Next = null;
  248. break;
  249. case 1:
  250. $child = reset($this->next);
  251. $this->_actionDictionary->Next = $child->dumpAction($factory, $processedActions);
  252. break;
  253. default:
  254. // require_once 'Zend/Pdf/Element/Array.php';
  255. $pdfChildArray = new Zend_Pdf_Element_Array();
  256. foreach ($this->next as $child) {
  257. $pdfChildArray->items[] = $child->dumpAction($factory, $processedActions);
  258. }
  259. $this->_actionDictionary->Next = $pdfChildArray;
  260. break;
  261. }
  262. } else {
  263. foreach ($this->next as $child) {
  264. $child->dumpAction($factory, $processedActions);
  265. }
  266. }
  267. if ($this->_actionDictionary instanceof Zend_Pdf_Element_Dictionary) {
  268. // It's a newly created action. Register it within object factory and return indirect object
  269. return $factory->newObject($this->_actionDictionary);
  270. } else {
  271. // It's a loaded object
  272. return $this->_actionDictionary;
  273. }
  274. }
  275. ////////////////////////////////////////////////////////////////////////
  276. // RecursiveIterator interface methods
  277. //////////////
  278. /**
  279. * Returns current child action.
  280. *
  281. * @return Zend_Pdf_Action
  282. */
  283. public function current()
  284. {
  285. return current($this->next);
  286. }
  287. /**
  288. * Returns current iterator key
  289. *
  290. * @return integer
  291. */
  292. public function key()
  293. {
  294. return key($this->next);
  295. }
  296. /**
  297. * Go to next child
  298. */
  299. public function next()
  300. {
  301. return next($this->next);
  302. }
  303. /**
  304. * Rewind children
  305. */
  306. public function rewind()
  307. {
  308. return reset($this->next);
  309. }
  310. /**
  311. * Check if current position is valid
  312. *
  313. * @return boolean
  314. */
  315. public function valid()
  316. {
  317. return current($this->next) !== false;
  318. }
  319. /**
  320. * Returns the child action.
  321. *
  322. * @return Zend_Pdf_Action|null
  323. */
  324. public function getChildren()
  325. {
  326. return current($this->next);
  327. }
  328. /**
  329. * Implements RecursiveIterator interface.
  330. *
  331. * @return bool whether container has any pages
  332. */
  333. public function hasChildren()
  334. {
  335. return count($this->next) > 0;
  336. }
  337. ////////////////////////////////////////////////////////////////////////
  338. // Countable interface methods
  339. //////////////
  340. /**
  341. * count()
  342. *
  343. * @return int
  344. */
  345. public function count()
  346. {
  347. return count($this->childOutlines);
  348. }
  349. }