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.

Page.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright 1999-2006 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.area;
  18. import java.awt.Rectangle;
  19. import java.awt.geom.Rectangle2D;
  20. import java.io.Serializable;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import org.apache.fop.datatypes.FODimension;
  24. import org.apache.fop.datatypes.LengthBase;
  25. import org.apache.fop.datatypes.SimplePercentBaseContext;
  26. import org.apache.fop.fo.Constants;
  27. import org.apache.fop.fo.pagination.Region;
  28. import org.apache.fop.fo.pagination.RegionBody;
  29. import org.apache.fop.fo.pagination.SimplePageMaster;
  30. import org.apache.fop.fo.properties.CommonMarginBlock;
  31. import org.apache.fop.layoutmgr.TraitSetter;
  32. /**
  33. * The page.
  34. * This holds the contents of the page. Each region is added.
  35. * The unresolved references area added so that if the page is
  36. * serialized then it will handle the resolving properly after
  37. * being reloaded.
  38. * This is serializable so it can be saved to cache to save
  39. * memory if there are forward references.
  40. * The page is cloneable so the page master can make copies of
  41. * the top level page and regions.
  42. */
  43. public class Page implements Serializable, Cloneable {
  44. // contains before, start, body, end and after regions
  45. private RegionViewport regionBefore = null;
  46. private RegionViewport regionStart = null;
  47. private RegionViewport regionBody = null;
  48. private RegionViewport regionEnd = null;
  49. private RegionViewport regionAfter = null;
  50. // temporary map of unresolved objects used when serializing the page
  51. private Map unresolved = null;
  52. /** Set to true to make this page behave as if it were not empty. */
  53. private boolean fakeNonEmpty = false;
  54. /**
  55. * Empty constructor, for cloning
  56. */
  57. public Page() {
  58. }
  59. /**
  60. * Constructor
  61. * @param spm SimplePageMaster containing the dimensions for this
  62. * page-reference-area
  63. */
  64. public Page(SimplePageMaster spm) {
  65. // Width and Height of the page view port
  66. FODimension pageViewPortDims = new FODimension(spm.getPageWidth().getValue()
  67. , spm.getPageHeight().getValue());
  68. // Get absolute margin properties (top, left, bottom, right)
  69. CommonMarginBlock mProps = spm.getCommonMarginBlock();
  70. /*
  71. * Create the page reference area rectangle (0,0 is at top left
  72. * of the "page media" and y increases
  73. * when moving towards the bottom of the page.
  74. * The media rectangle itself is (0,0,pageWidth,pageHeight).
  75. */
  76. /* Special rules apply to resolving margins in the page context.
  77. * Contrary to normal margins in this case top and bottom margin
  78. * are resolved relative to the height. In the property subsystem
  79. * all margin properties are configured to using BLOCK_WIDTH.
  80. * That's why we 'cheat' here and setup a context for the height but
  81. * use the LengthBase.BLOCK_WIDTH.
  82. */
  83. SimplePercentBaseContext pageWidthContext
  84. = new SimplePercentBaseContext(null, LengthBase.CONTAINING_BLOCK_WIDTH
  85. , pageViewPortDims.ipd);
  86. SimplePercentBaseContext pageHeightContext
  87. = new SimplePercentBaseContext(null, LengthBase.CONTAINING_BLOCK_WIDTH
  88. , pageViewPortDims.bpd);
  89. Rectangle pageRefRect
  90. = new Rectangle(mProps.marginLeft.getValue(pageWidthContext)
  91. , mProps.marginTop.getValue(pageHeightContext)
  92. , pageViewPortDims.ipd
  93. - mProps.marginLeft.getValue(pageWidthContext)
  94. - mProps.marginRight.getValue(pageWidthContext)
  95. , pageViewPortDims.bpd
  96. - mProps.marginTop.getValue(pageHeightContext)
  97. - mProps.marginBottom.getValue(pageHeightContext));
  98. // Set up the CTM on the page reference area based on writing-mode
  99. // and reference-orientation
  100. FODimension reldims = new FODimension(0, 0);
  101. CTM pageCTM = CTM.getCTMandRelDims(spm.getReferenceOrientation(),
  102. spm.getWritingMode(), pageRefRect, reldims);
  103. // Create a RegionViewport/ reference area pair for each page region
  104. RegionReference rr = null;
  105. for (Iterator regenum = spm.getRegions().values().iterator();
  106. regenum.hasNext();) {
  107. Region r = (Region)regenum.next();
  108. RegionViewport rvp = makeRegionViewport(r, reldims, pageCTM, spm);
  109. if (r.getNameId() == Constants.FO_REGION_BODY) {
  110. rr = new BodyRegion((RegionBody) r, rvp);
  111. } else {
  112. rr = new RegionReference(r, rvp);
  113. }
  114. setRegionReferencePosition(rr, r, rvp.getViewArea());
  115. rvp.setRegionReference(rr);
  116. setRegionViewport(r.getNameId(), rvp);
  117. }
  118. }
  119. /**
  120. * Call this method to force this page to pretend not to be empty.
  121. */
  122. public void fakeNonEmpty() {
  123. this.fakeNonEmpty = true;
  124. }
  125. /**
  126. * Creates a RegionViewport Area object for this pagination Region.
  127. * @param r the region the viewport is to be created for
  128. * @param reldims relative dimensions
  129. * @param pageCTM page coordinate transformation matrix
  130. * @param spm the simple-page-master for this page
  131. * @return the new region viewport
  132. */
  133. private RegionViewport makeRegionViewport(Region r, FODimension reldims, CTM pageCTM,
  134. SimplePageMaster spm) {
  135. Rectangle2D relRegionRect = r.getViewportRectangle(reldims, spm);
  136. Rectangle2D absRegionRect = pageCTM.transform(relRegionRect);
  137. // Get the region viewport rectangle in absolute coords by
  138. // transforming it using the page CTM
  139. RegionViewport rv = new RegionViewport(absRegionRect);
  140. rv.setBPD((int)relRegionRect.getHeight());
  141. rv.setIPD((int)relRegionRect.getWidth());
  142. TraitSetter.addBackground(rv, r.getCommonBorderPaddingBackground(), null);
  143. rv.setClip(r.getOverflow() == Constants.EN_HIDDEN
  144. || r.getOverflow() == Constants.EN_ERROR_IF_OVERFLOW);
  145. return rv;
  146. }
  147. /**
  148. * Set the region reference position within the region viewport.
  149. * This sets the transform that is used to place the contents of
  150. * the region reference.
  151. *
  152. * @param rr the region reference area
  153. * @param r the region-xxx formatting object
  154. * @param absRegVPRect The region viewport rectangle in "absolute" coordinates
  155. * where x=distance from left, y=distance from bottom, width=right-left
  156. * height=top-bottom
  157. */
  158. private void setRegionReferencePosition(RegionReference rr, Region r,
  159. Rectangle2D absRegVPRect) {
  160. FODimension reldims = new FODimension(0, 0);
  161. rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(),
  162. r.getWritingMode(), absRegVPRect, reldims));
  163. rr.setIPD(reldims.ipd);
  164. rr.setBPD(reldims.bpd);
  165. }
  166. /**
  167. * Set the region on this page.
  168. *
  169. * @param areaclass the area class of the region to set
  170. * @param port the region viewport to set
  171. */
  172. public void setRegionViewport(int areaclass, RegionViewport port) {
  173. if (areaclass == Constants.FO_REGION_BEFORE) {
  174. regionBefore = port;
  175. } else if (areaclass == Constants.FO_REGION_START) {
  176. regionStart = port;
  177. } else if (areaclass == Constants.FO_REGION_BODY) {
  178. regionBody = port;
  179. } else if (areaclass == Constants.FO_REGION_END) {
  180. regionEnd = port;
  181. } else if (areaclass == Constants.FO_REGION_AFTER) {
  182. regionAfter = port;
  183. }
  184. }
  185. /**
  186. * Get the region from this page.
  187. *
  188. * @param areaclass the region area class
  189. * @return the region viewport or null if none
  190. */
  191. public RegionViewport getRegionViewport(int areaclass) {
  192. if (areaclass == Constants.FO_REGION_BEFORE) {
  193. return regionBefore;
  194. } else if (areaclass == Constants.FO_REGION_START) {
  195. return regionStart;
  196. } else if (areaclass == Constants.FO_REGION_BODY) {
  197. return regionBody;
  198. } else if (areaclass == Constants.FO_REGION_END) {
  199. return regionEnd;
  200. } else if (areaclass == Constants.FO_REGION_AFTER) {
  201. return regionAfter;
  202. }
  203. throw new IllegalArgumentException("No such area class with ID = "
  204. + areaclass);
  205. }
  206. /**
  207. * indicates whether any FOs have been added to the body region
  208. *
  209. * @return whether any FOs have been added to the body region
  210. */
  211. public boolean isEmpty() {
  212. if (fakeNonEmpty) {
  213. return false;
  214. } else if (regionBody == null) {
  215. return true;
  216. } else {
  217. BodyRegion body = (BodyRegion)regionBody.getRegionReference();
  218. return body.isEmpty();
  219. }
  220. }
  221. /**
  222. * Clone this page.
  223. * This returns a new page with a clone of all the regions.
  224. *
  225. * @return a new clone of this page
  226. */
  227. public Object clone() {
  228. Page p = new Page();
  229. if (regionBefore != null) {
  230. p.regionBefore = (RegionViewport)regionBefore.clone();
  231. }
  232. if (regionStart != null) {
  233. p.regionStart = (RegionViewport)regionStart.clone();
  234. }
  235. if (regionBody != null) {
  236. p.regionBody = (RegionViewport)regionBody.clone();
  237. }
  238. if (regionEnd != null) {
  239. p.regionEnd = (RegionViewport)regionEnd.clone();
  240. }
  241. if (regionAfter != null) {
  242. p.regionAfter = (RegionViewport)regionAfter.clone();
  243. }
  244. return p;
  245. }
  246. /**
  247. * Set the unresolved references on this page for serializing.
  248. *
  249. * @param unres the Map of unresolved objects
  250. */
  251. public void setUnresolvedReferences(Map unres) {
  252. unresolved = unres;
  253. }
  254. /**
  255. * Get the map unresolved references from this page.
  256. * This should be called after deserializing to retrieve
  257. * the map of unresolved references that were serialized.
  258. *
  259. * @return the de-serialized HashMap of unresolved objects
  260. */
  261. public Map getUnresolvedReferences() {
  262. return unresolved;
  263. }
  264. }