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.

PageViewport.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * $Id: PageViewport.java,v 1.16 2003/03/05 15:19:31 jeremias Exp $
  3. * ============================================================================
  4. * The Apache Software License, Version 1.1
  5. * ============================================================================
  6. *
  7. * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modifica-
  10. * tion, are permitted provided that the following conditions are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if any, must
  20. * include the following acknowledgment: "This product includes software
  21. * developed by the Apache Software Foundation (http://www.apache.org/)."
  22. * Alternately, this acknowledgment may appear in the software itself, if
  23. * and wherever such third-party acknowledgments normally appear.
  24. *
  25. * 4. The names "FOP" and "Apache Software Foundation" must not be used to
  26. * endorse or promote products derived from this software without prior
  27. * written permission. For written permission, please contact
  28. * apache@apache.org.
  29. *
  30. * 5. Products derived from this software may not be called "Apache", nor may
  31. * "Apache" appear in their name, without prior written permission of the
  32. * Apache Software Foundation.
  33. *
  34. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  35. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  36. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  37. * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  38. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
  39. * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  40. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  41. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  43. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. * ============================================================================
  45. *
  46. * This software consists of voluntary contributions made by many individuals
  47. * on behalf of the Apache Software Foundation and was originally created by
  48. * James Tauber <jtauber@jtauber.com>. For more information on the Apache
  49. * Software Foundation, please see <http://www.apache.org/>.
  50. */
  51. package org.apache.fop.area;
  52. import java.awt.geom.Rectangle2D;
  53. import java.io.ObjectOutputStream;
  54. import java.io.ObjectInputStream;
  55. import java.util.ArrayList;
  56. import java.util.List;
  57. import java.util.Map;
  58. import java.util.HashMap;
  59. import java.util.Iterator;
  60. import org.apache.fop.fo.properties.RetrievePosition;
  61. /**
  62. * Page viewport that specifies the viewport area and holds the page contents.
  63. * This is the top level object for a page and remains valid for the life
  64. * of the document and the area tree.
  65. * This object may be used as a key to reference a page.
  66. * This is the level that creates the page.
  67. * The page (reference area) is then rendered inside the page object
  68. */
  69. public class PageViewport implements Resolveable, Cloneable {
  70. private Page page;
  71. private Rectangle2D viewArea;
  72. private boolean clip = false;
  73. private String pageNumber = null;
  74. // list of id references and the rectangle on the page
  75. private Map idReferences = null;
  76. // this keeps a list of currently unresolved areas or extensions
  77. // once the thing is resolved it is removed
  78. // when this is empty the page can be rendered
  79. private Map unresolved = null;
  80. private Map pendingResolved = null;
  81. // hashmap of markers for this page
  82. // start and end are added by the fo that contains the markers
  83. private Map markerFirstStart = null;
  84. private Map markerLastStart = null;
  85. private Map markerFirstAny = null;
  86. private Map markerLastEnd = null;
  87. private Map markerLastAny = null;
  88. /**
  89. * Create a page viewport.
  90. * @param p the page reference area that holds the contents
  91. * @param bounds the bounds of this viewport
  92. */
  93. public PageViewport(Page p, Rectangle2D bounds) {
  94. page = p;
  95. viewArea = bounds;
  96. }
  97. /**
  98. * Set if this viewport should clip.
  99. * @param c true if this viewport should clip
  100. */
  101. public void setClip(boolean c) {
  102. clip = c;
  103. }
  104. /**
  105. * Get the view area rectangle of this viewport.
  106. * @return the rectangle for this viewport
  107. */
  108. public Rectangle2D getViewArea() {
  109. return viewArea;
  110. }
  111. /**
  112. * Get the page reference area with the contents.
  113. * @return the page reference area
  114. */
  115. public Page getPage() {
  116. return page;
  117. }
  118. /**
  119. * Set the page number for this page.
  120. * @param num the string representing the page number
  121. */
  122. public void setPageNumber(String num) {
  123. pageNumber = num;
  124. }
  125. /**
  126. * Get the page number of this page.
  127. * @return the string that represents this page
  128. */
  129. public String getPageNumber() {
  130. return pageNumber;
  131. }
  132. /**
  133. * Get the key for this page viewport.
  134. * This is used so that a serializable key can be used to
  135. * lookup the page or some other reference.
  136. *
  137. * @return a unique page viewport key for this area tree
  138. */
  139. public String getKey() {
  140. return toString();
  141. }
  142. /**
  143. * Add an unresolved id to this page.
  144. * All unresolved ids for the contents of this page are
  145. * added to this page. This is so that the resolvers can be
  146. * serialized with the page to preserve the proper function.
  147. * @param id the id of the reference
  148. * @param res the resolver of the reference
  149. */
  150. public void addUnresolvedID(String id, Resolveable res) {
  151. if (unresolved == null) {
  152. unresolved = new HashMap();
  153. }
  154. List list = (List)unresolved.get(id);
  155. if (list == null) {
  156. list = new ArrayList();
  157. unresolved.put(id, list);
  158. }
  159. list.add(res);
  160. }
  161. /**
  162. * Check if this page has been fully resolved.
  163. * @return true if the page is resolved and can be rendered
  164. */
  165. public boolean isResolved() {
  166. return unresolved == null;
  167. }
  168. /**
  169. * Get the id references for this page.
  170. * @return always null
  171. */
  172. public String[] getIDs() {
  173. return null;
  174. }
  175. /**
  176. * This resolves reference with a list of pages.
  177. * The pages (PageViewport) contain the rectangle of the area.
  178. * @param id the id to resolve
  179. * @param pages the list of pages with the id area
  180. * may be null if not found
  181. */
  182. public void resolve(String id, List pages) {
  183. if (page == null) {
  184. if (pendingResolved == null) {
  185. pendingResolved = new HashMap();
  186. }
  187. pendingResolved.put(id, pages);
  188. } else {
  189. if (unresolved != null) {
  190. List todo = (List)unresolved.get(id);
  191. if (todo != null) {
  192. for (int count = 0; count < todo.size(); count++) {
  193. Resolveable res = (Resolveable)todo.get(count);
  194. res.resolve(id, pages);
  195. }
  196. }
  197. }
  198. }
  199. if (unresolved != null) {
  200. unresolved.remove(id);
  201. if (unresolved.isEmpty()) {
  202. unresolved = null;
  203. }
  204. }
  205. }
  206. /**
  207. * Add the markers for this page.
  208. * Only the required markers are kept.
  209. * For "first-starting-within-page" it adds the markers
  210. * that are starting only if the marker class name is not
  211. * already added.
  212. * For "first-including-carryover" it adds any starting marker
  213. * if the marker class name is not already added.
  214. * For "last-starting-within-page" it adds all marks that
  215. * are starting, replacing earlier markers.
  216. * For "last-ending-within-page" it adds all markers that
  217. * are ending, replacing earlier markers.
  218. *
  219. * Should this logic be placed in the Page layout manager.
  220. *
  221. * @param marks the map of markers to add
  222. * @param start if the area being added is starting or ending
  223. * @param isfirst isfirst or islast flag
  224. */
  225. public void addMarkers(Map marks, boolean start, boolean isfirst) {
  226. if (start) {
  227. if (isfirst) {
  228. if (markerFirstStart == null) {
  229. markerFirstStart = new HashMap();
  230. }
  231. if (markerFirstAny == null) {
  232. markerFirstAny = new HashMap();
  233. }
  234. // only put in new values, leave current
  235. for (Iterator iter = marks.keySet().iterator(); iter.hasNext();) {
  236. Object key = iter.next();
  237. if (!markerFirstStart.containsKey(key)) {
  238. markerFirstStart.put(key, marks.get(key));
  239. }
  240. if (!markerFirstAny.containsKey(key)) {
  241. markerFirstAny.put(key, marks.get(key));
  242. }
  243. }
  244. if (markerLastStart == null) {
  245. markerLastStart = new HashMap();
  246. }
  247. // replace all
  248. markerLastStart.putAll(marks);
  249. } else {
  250. if (markerFirstAny == null) {
  251. markerFirstAny = new HashMap();
  252. }
  253. // only put in new values, leave current
  254. for (Iterator iter = marks.keySet().iterator(); iter.hasNext();) {
  255. Object key = iter.next();
  256. if (!markerFirstAny.containsKey(key)) {
  257. markerFirstAny.put(key, marks.get(key));
  258. }
  259. }
  260. }
  261. } else {
  262. if (!isfirst) {
  263. if (markerLastEnd == null) {
  264. markerLastEnd = new HashMap();
  265. }
  266. // replace all
  267. markerLastEnd.putAll(marks);
  268. }
  269. if (markerLastAny == null) {
  270. markerLastAny = new HashMap();
  271. }
  272. // replace all
  273. markerLastAny.putAll(marks);
  274. }
  275. }
  276. /**
  277. * Get a marker from this page.
  278. * This will retrieve a marker with the class name
  279. * and position.
  280. *
  281. * @param name The class name of the marker to retrieve
  282. * @param pos the position to retrieve
  283. * @return Object the marker found or null
  284. */
  285. public Object getMarker(String name, int pos) {
  286. Object mark = null;
  287. switch (pos) {
  288. case RetrievePosition.FSWP:
  289. if (markerFirstStart != null) {
  290. mark = markerFirstStart.get(name);
  291. }
  292. if (mark == null && markerFirstAny != null) {
  293. mark = markerFirstAny.get(name);
  294. }
  295. break;
  296. case RetrievePosition.FIC:
  297. if (markerFirstAny != null) {
  298. mark = markerFirstAny.get(name);
  299. }
  300. break;
  301. case RetrievePosition.LSWP:
  302. if (markerLastStart != null) {
  303. mark = markerLastStart.get(name);
  304. }
  305. if (mark == null && markerLastAny != null) {
  306. mark = markerLastAny.get(name);
  307. }
  308. break;
  309. case RetrievePosition.LEWP:
  310. if (markerLastEnd != null) {
  311. mark = markerLastEnd.get(name);
  312. }
  313. if (mark == null && markerLastAny != null) {
  314. mark = markerLastAny.get(name);
  315. }
  316. break;
  317. }
  318. return mark;
  319. }
  320. /**
  321. * Save the page contents to an object stream.
  322. * The map of unresolved references are set on the page so that
  323. * the resolvers can be properly serialized and reloaded.
  324. * @param out the object output stream to write the contents
  325. * @throws Exception if there is a problem saving the page
  326. */
  327. public void savePage(ObjectOutputStream out) throws Exception {
  328. // set the unresolved references so they are serialized
  329. page.setUnresolvedReferences(unresolved);
  330. out.writeObject(page);
  331. page = null;
  332. }
  333. /**
  334. * Load the page contents from an object stream.
  335. * This loads the page contents from the stream and
  336. * if there are any unresolved references that were resolved
  337. * while saved they will be resolved on the page contents.
  338. * @param in the object input stream to read the page from
  339. * @throws Exception if there is an error loading the page
  340. */
  341. public void loadPage(ObjectInputStream in) throws Exception {
  342. page = (Page) in.readObject();
  343. unresolved = page.getUnresolvedReferences();
  344. if (unresolved != null && pendingResolved != null) {
  345. for (Iterator iter = pendingResolved.keySet().iterator();
  346. iter.hasNext();) {
  347. String id = (String) iter.next();
  348. resolve(id, (List)pendingResolved.get(id));
  349. }
  350. pendingResolved = null;
  351. }
  352. }
  353. /**
  354. * Clone this page.
  355. * Used by the page master to create a copy of an original page.
  356. * @return a copy of this page and associated viewports
  357. */
  358. public Object clone() {
  359. Page p = (Page)page.clone();
  360. PageViewport ret = new PageViewport(p, (Rectangle2D)viewArea.clone());
  361. return ret;
  362. }
  363. /**
  364. * Clear the page contents to save memory.
  365. * This object is kept for the life of the area tree since
  366. * it holds id and marker information and is used as a key.
  367. */
  368. public void clear() {
  369. page = null;
  370. }
  371. /**
  372. * @see java.lang.Object#toString()
  373. */
  374. public String toString() {
  375. StringBuffer sb = new StringBuffer(64);
  376. sb.append("PageViewport: page=");
  377. sb.append(getPageNumber());
  378. return sb.toString();
  379. }
  380. }