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

New feature: "Intermediate format" (IF). The IF is basically the XML dialect written by the area tree renderer (XMLRenderer). A new parser for this format allows reparsing a serialized and possibly modified area tree and rendering it to the final target format. More details on the Wiki at http://wiki.apache.org/xmlgraphics-fop/AreaTreeIntermediateXml. No advanced features have been implemented, yet, only the basic functionality. The whole change should be fully backwards-compatible WRT the outer FOP API except maybe for FOTreeBuilder.addElementMapping(), and the area tree XML which got small changes. The area tree has been cleaned up. The serializability has been restored. The CachedRenderPagesModel works again and can, in certain situations, decrease the maximum amount of memory held at one point in time. Some adjustments were necessary in the area tree to help the work of the AreaTreeParser. The AreaTreeParser is new and is responsible for parsing area tree XML files and adding pages to a RenderPagesModel instance. It is SAX-based and should be pretty efficient. XMLUnit (http://xmlunit.sourceforge.net, BSD license) is a new dependency for the test code. It is used to verify the correctness of the intermediate format code. It doesn't have to be installed for the build to run through, though. ElementMapping got a new method getDOMImplementation() which provides the DOMImplementation used to handle a subdocument of a particular namespace. For example, SVG uses Batik's SVG DOM. The AreaTreeParser needs that to properly recreate foreign objects because it can't use the mechanism of the FO tree. The default implementation returns null. The ElementMapping instances are no longer maintained by the FOTreeBuilder, but by the newly created ElementMappingRegistry class. It is expected that the instance of this class is moved from the FOTreeBuilder and the AreaTreeParser's Handler class to the "environment class" once it is created to cut down on the startup time for each processed document. The XMLRenderer has been slightly modified to improve the serialization/deserialization qualities of the area tree XML format. The XMLRenderer can now mimic another renderer (see mimicRenderer(Renderer)) in order to use its font setup. That way it is made certain that the reparsed area tree will render to the final target format exactly as expected. Fixed a bug in the XMLHandlerRegistry which did not always return the right XMLHandler for every situation. Added a DefaultErrorListener to the util package. I've had problems with Xalan-J swallowing exceptions with its default ErrorListener, so I added a simple one for convenience and use in AreaTreeParser. Example code for working with the AreaTreeParser can be found in examples/embedding. Documentation will follow. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@369753 13f79535-47bb-0310-9956-ffa450edef68
18 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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.Iterator;
  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.Constants;
  28. import org.apache.fop.fo.pagination.Region;
  29. import org.apache.fop.fo.pagination.RegionBody;
  30. import org.apache.fop.fo.pagination.SimplePageMaster;
  31. import org.apache.fop.fo.properties.CommonMarginBlock;
  32. import org.apache.fop.layoutmgr.TraitSetter;
  33. /**
  34. * The page.
  35. * This holds the contents of the page. Each region is added.
  36. * The unresolved references area added so that if the page is
  37. * serialized then it will handle the resolving properly after
  38. * being reloaded.
  39. * This is serializable so it can be saved to cache to save
  40. * memory if there are forward references.
  41. * The page is cloneable so the page master can make copies of
  42. * the top level page and regions.
  43. */
  44. public class Page extends AreaTreeObject implements Serializable, Cloneable {
  45. private static final long serialVersionUID = 6272157047421543866L;
  46. // contains before, start, body, end and after regions
  47. private RegionViewport regionBefore = null;
  48. private RegionViewport regionStart = null;
  49. private RegionViewport regionBody = null;
  50. private RegionViewport regionEnd = null;
  51. private RegionViewport regionAfter = null;
  52. // temporary map of unresolved objects used when serializing the page
  53. private Map unresolved = null;
  54. /** Set to true to make this page behave as if it were not empty. */
  55. private boolean fakeNonEmpty = false;
  56. /**
  57. * Empty constructor, for cloning
  58. */
  59. public Page() {
  60. }
  61. /**
  62. * Constructor
  63. * @param spm SimplePageMaster containing the dimensions for this
  64. * page-reference-area
  65. */
  66. public Page(SimplePageMaster spm) {
  67. // Width and Height of the page view port
  68. FODimension pageViewPortDims = new FODimension(spm.getPageWidth().getValue()
  69. , spm.getPageHeight().getValue());
  70. // Get absolute margin properties (top, left, bottom, right)
  71. CommonMarginBlock mProps = spm.getCommonMarginBlock();
  72. /*
  73. * Create the page reference area rectangle (0,0 is at top left
  74. * of the "page media" and y increases
  75. * when moving towards the bottom of the page.
  76. * The media rectangle itself is (0,0,pageWidth,pageHeight).
  77. */
  78. /* Special rules apply to resolving margins in the page context.
  79. * Contrary to normal margins in this case top and bottom margin
  80. * are resolved relative to the height. In the property subsystem
  81. * all margin properties are configured to using BLOCK_WIDTH.
  82. * That's why we 'cheat' here and setup a context for the height but
  83. * use the LengthBase.BLOCK_WIDTH.
  84. */
  85. SimplePercentBaseContext pageWidthContext
  86. = new SimplePercentBaseContext(null, LengthBase.CONTAINING_BLOCK_WIDTH
  87. , pageViewPortDims.ipd);
  88. SimplePercentBaseContext pageHeightContext
  89. = new SimplePercentBaseContext(null, LengthBase.CONTAINING_BLOCK_WIDTH
  90. , pageViewPortDims.bpd);
  91. Rectangle pageRefRect
  92. = new Rectangle(mProps.marginLeft.getValue(pageWidthContext)
  93. , mProps.marginTop.getValue(pageHeightContext)
  94. , pageViewPortDims.ipd
  95. - mProps.marginLeft.getValue(pageWidthContext)
  96. - mProps.marginRight.getValue(pageWidthContext)
  97. , pageViewPortDims.bpd
  98. - mProps.marginTop.getValue(pageHeightContext)
  99. - mProps.marginBottom.getValue(pageHeightContext));
  100. // Set up the CTM on the page reference area based on writing-mode
  101. // and reference-orientation
  102. FODimension reldims = new FODimension(0, 0);
  103. CTM pageCTM = CTM.getCTMandRelDims(spm.getReferenceOrientation(),
  104. spm.getWritingMode(), pageRefRect, reldims);
  105. // Create a RegionViewport/ reference area pair for each page region
  106. RegionReference rr = null;
  107. for (Iterator regenum = spm.getRegions().values().iterator();
  108. regenum.hasNext();) {
  109. Region r = (Region)regenum.next();
  110. RegionViewport rvp = makeRegionViewport(r, reldims, pageCTM, spm);
  111. if (r.getNameId() == Constants.FO_REGION_BODY) {
  112. rr = new BodyRegion((RegionBody) r, rvp);
  113. } else {
  114. rr = new RegionReference(r, rvp);
  115. }
  116. // set borders and padding traits
  117. // (a little extensions wrt what prescribed by the specs at 6.4.14)
  118. TraitSetter.addBorders(rr, r.getCommonBorderPaddingBackground(),
  119. false, false, false, false, null);
  120. TraitSetter.addPadding(rr, r.getCommonBorderPaddingBackground(),
  121. false, false, false, false, null);
  122. setRegionReferencePosition(rr, r, rvp.getViewArea());
  123. rvp.setRegionReference(rr);
  124. setRegionViewport(r.getNameId(), rvp);
  125. }
  126. }
  127. /**
  128. * Call this method to force this page to pretend not to be empty.
  129. */
  130. public void fakeNonEmpty() {
  131. this.fakeNonEmpty = true;
  132. }
  133. /**
  134. * Creates a RegionViewport Area object for this pagination Region.
  135. * @param r the region the viewport is to be created for
  136. * @param reldims relative dimensions
  137. * @param pageCTM page coordinate transformation matrix
  138. * @param spm the simple-page-master for this page
  139. * @return the new region viewport
  140. */
  141. private RegionViewport makeRegionViewport(Region r, FODimension reldims, CTM pageCTM,
  142. SimplePageMaster spm) {
  143. Rectangle2D relRegionRect = r.getViewportRectangle(reldims, spm);
  144. Rectangle2D absRegionRect = pageCTM.transform(relRegionRect);
  145. // Get the region viewport rectangle in absolute coords by
  146. // transforming it using the page CTM
  147. RegionViewport rv = new RegionViewport(absRegionRect);
  148. rv.setBPD((int)relRegionRect.getHeight());
  149. rv.setIPD((int)relRegionRect.getWidth());
  150. TraitSetter.addBackground(rv, r.getCommonBorderPaddingBackground(), null);
  151. rv.setClip(r.getOverflow() == Constants.EN_HIDDEN
  152. || r.getOverflow() == Constants.EN_ERROR_IF_OVERFLOW);
  153. return rv;
  154. }
  155. /**
  156. * Set the region reference position within the region viewport.
  157. * This sets the transform that is used to place the contents of
  158. * the region reference.
  159. *
  160. * @param rr the region reference area
  161. * @param r the region-xxx formatting object
  162. * @param absRegVPRect The region viewport rectangle in "absolute" coordinates
  163. * where x=distance from left, y=distance from bottom, width=right-left
  164. * height=top-bottom
  165. */
  166. private void setRegionReferencePosition(RegionReference rr, Region r,
  167. Rectangle2D absRegVPRect) {
  168. FODimension reldims = new FODimension(0, 0);
  169. rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(),
  170. r.getWritingMode(), absRegVPRect, reldims));
  171. rr.setIPD(reldims.ipd
  172. - rr.getBorderAndPaddingWidthStart()
  173. - rr.getBorderAndPaddingWidthEnd());
  174. rr.setBPD(reldims.bpd
  175. - rr.getBorderAndPaddingWidthBefore()
  176. - rr.getBorderAndPaddingWidthAfter());
  177. }
  178. /**
  179. * Set the region on this page.
  180. *
  181. * @param areaclass the area class of the region to set
  182. * @param port the region viewport to set
  183. */
  184. public void setRegionViewport(int areaclass, RegionViewport port) {
  185. if (areaclass == Constants.FO_REGION_BEFORE) {
  186. regionBefore = port;
  187. } else if (areaclass == Constants.FO_REGION_START) {
  188. regionStart = port;
  189. } else if (areaclass == Constants.FO_REGION_BODY) {
  190. regionBody = port;
  191. } else if (areaclass == Constants.FO_REGION_END) {
  192. regionEnd = port;
  193. } else if (areaclass == Constants.FO_REGION_AFTER) {
  194. regionAfter = port;
  195. }
  196. }
  197. /**
  198. * Get the region from this page.
  199. *
  200. * @param areaClass the region area class
  201. * @return the region viewport or null if none
  202. */
  203. public RegionViewport getRegionViewport(int areaClass) {
  204. switch (areaClass) {
  205. case Constants.FO_REGION_BEFORE:
  206. return regionBefore;
  207. case Constants.FO_REGION_START:
  208. return regionStart;
  209. case Constants.FO_REGION_BODY:
  210. return regionBody;
  211. case Constants.FO_REGION_END:
  212. return regionEnd;
  213. case Constants.FO_REGION_AFTER:
  214. return regionAfter;
  215. default:
  216. throw new IllegalArgumentException("No such area class with ID = " + areaClass);
  217. }
  218. }
  219. /**
  220. * Indicates whether any FOs have been added to the body region
  221. *
  222. * @return whether any FOs have been added to the body region
  223. */
  224. public boolean isEmpty() {
  225. if (fakeNonEmpty) {
  226. return false;
  227. } else if (regionBody == null) {
  228. return true;
  229. } else {
  230. BodyRegion body = (BodyRegion)regionBody.getRegionReference();
  231. return body.isEmpty();
  232. }
  233. }
  234. /**
  235. * Clone this page.
  236. * This returns a new page with a clone of all the regions.
  237. *
  238. * @return a new clone of this page
  239. */
  240. public Object clone() {
  241. Page p = new Page();
  242. if (regionBefore != null) {
  243. p.regionBefore = (RegionViewport)regionBefore.clone();
  244. }
  245. if (regionStart != null) {
  246. p.regionStart = (RegionViewport)regionStart.clone();
  247. }
  248. if (regionBody != null) {
  249. p.regionBody = (RegionViewport)regionBody.clone();
  250. }
  251. if (regionEnd != null) {
  252. p.regionEnd = (RegionViewport)regionEnd.clone();
  253. }
  254. if (regionAfter != null) {
  255. p.regionAfter = (RegionViewport)regionAfter.clone();
  256. }
  257. return p;
  258. }
  259. /**
  260. * Set the unresolved references on this page for serializing.
  261. *
  262. * @param unres the Map of unresolved objects
  263. */
  264. public void setUnresolvedReferences(Map unres) {
  265. unresolved = unres;
  266. }
  267. /**
  268. * Get the map unresolved references from this page.
  269. * This should be called after deserializing to retrieve
  270. * the map of unresolved references that were serialized.
  271. *
  272. * @return the de-serialized HashMap of unresolved objects
  273. */
  274. public Map getUnresolvedReferences() {
  275. return unresolved;
  276. }
  277. }