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 12KB

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