Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*
  2. *
  3. * Copyright 1999-2004 The Apache Software Foundation.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * 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. *
  18. * $Id$
  19. */
  20. package org.apache.fop.fo.flow;
  21. import java.awt.image.BufferedImage;
  22. import java.util.ArrayList;
  23. import java.util.Arrays;
  24. import java.util.BitSet;
  25. import java.util.Collections;
  26. import java.util.HashMap;
  27. import java.util.Iterator;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.NoSuchElementException;
  31. import java.util.Set;
  32. import org.apache.fop.apps.FOPException;
  33. import org.apache.fop.area.Area;
  34. import org.apache.fop.area.Page;
  35. import org.apache.fop.area.PageList;
  36. import org.apache.fop.datastructs.TreeException;
  37. import org.apache.fop.datatypes.EnumType;
  38. import org.apache.fop.datatypes.IntegerType;
  39. import org.apache.fop.datatypes.Numeric;
  40. import org.apache.fop.datatypes.PropertyValue;
  41. import org.apache.fop.fo.FONode;
  42. import org.apache.fop.fo.FOPageSeqNode;
  43. import org.apache.fop.fo.FOTree;
  44. import org.apache.fop.fo.FObjectNames;
  45. import org.apache.fop.fo.FoRoot;
  46. import org.apache.fop.fo.PropNames;
  47. import org.apache.fop.fo.expr.PropertyException;
  48. import org.apache.fop.fo.properties.InitialPageNumber;
  49. import org.apache.fop.xml.FoXmlEvent;
  50. import org.apache.fop.xml.XmlEvent;
  51. import org.apache.fop.xml.XmlEventReader;
  52. /**
  53. * Implements the fo:simple-page-master flow object
  54. * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
  55. * @version $Revision$ $Name$
  56. */
  57. public class FoPageSequence extends FONode {
  58. private static final String tag = "$Name$";
  59. private static final String revision = "$Revision$";
  60. /** Map of <tt>Integer</tt> indices of <i>sparsePropsSet</i> array.
  61. It is indexed by the FO index of the FO associated with a given
  62. position in the <i>sparsePropsSet</i> array.
  63. */
  64. private static final int[] sparsePropsMap;
  65. /** An <tt>int</tt> array of of the applicable property indices, in
  66. property index order. */
  67. private static final int[] sparseIndices;
  68. /** The number of applicable properties. This is the size of the
  69. <i>sparsePropsSet</i> array. */
  70. private static final int numProps;
  71. static {
  72. // Collect the sets of properties that apply
  73. BitSet propsets = new BitSet();
  74. propsets.set(PropNames.COUNTRY);
  75. propsets.set(PropNames.FORMAT);
  76. propsets.set(PropNames.LANGUAGE);
  77. propsets.set(PropNames.LETTER_VALUE);
  78. propsets.set(PropNames.GROUPING_SEPARATOR);
  79. propsets.set(PropNames.GROUPING_SIZE);
  80. propsets.set(PropNames.ID);
  81. propsets.set(PropNames.INITIAL_PAGE_NUMBER);
  82. propsets.set(PropNames.FORCE_PAGE_COUNT);
  83. propsets.set(PropNames.MASTER_REFERENCE);
  84. propsets.set(PropNames.FLOW_MAP_REFERENCE);
  85. // Map these properties into sparsePropsSet
  86. // sparsePropsSet is a HashMap containing the indicies of the
  87. // sparsePropsSet array, indexed by the FO index of the FO slot
  88. // in sparsePropsSet.
  89. sparsePropsMap = new int[PropNames.LAST_PROPERTY_INDEX + 1];
  90. Arrays.fill(sparsePropsMap, -1);
  91. numProps = propsets.cardinality();
  92. sparseIndices = new int[numProps];
  93. int propx = 0;
  94. for (int next = propsets.nextSetBit(0);
  95. next >= 0;
  96. next = propsets.nextSetBit(next + 1)) {
  97. sparseIndices[propx] = next;
  98. sparsePropsMap[next] = propx++;
  99. }
  100. }
  101. /** Child index of fo:title child. */
  102. private int title = -1;
  103. /** Child index of first fo:static-content child. */
  104. private int firstStaticContent = -1;
  105. /**
  106. * Private map of <code>List</code>s of static-content subtrees hashed on
  107. * flow-name. Note that there is no restriction on multiple
  108. * <code>fo:static-content</code> elements being assigned to a single
  109. * <code>flow-name</code>, so the objects keyed by <code>flow-name</code>
  110. * must be able to hold more than one element; hence <code>List</code>s.
  111. *
  112. * Each element of the <code>HashMap</code>, keyed on the
  113. * <code>flow-name</code> is an <code>ArrayList</code> containing one or
  114. * more instances of <code>FoStaticContent</code>.
  115. */
  116. private HashMap staticSubtrees = null;
  117. /** Unmodifiable version of <code>staticSubtrees</code> */
  118. public Map staticContents = null;
  119. /** Child index of fo:flow child. */
  120. private int flowChild = -1;
  121. /** The page currently being processed by this page-sequence */
  122. private Page page = null;
  123. /**
  124. * Gets the current page of this page-sequence
  125. * @return the page
  126. */
  127. public Page getPage() {
  128. return page;
  129. }
  130. /** The <code>PageList</code> containing the flattened
  131. * <code>pageTree</code> for this page-sequence. This PageList contains
  132. * only <code>Page</code> elements. */
  133. private ArrayList pageArray = new ArrayList();
  134. /** The index of the current element in the pageList */
  135. private int pgListIndex = -1;
  136. /** The tree of all layout attempts for this page-sequence */
  137. private PageList pageList = null;
  138. /** An array of indicies mapping the path through the
  139. * <code>pageTree</code> to the current element */
  140. private ArrayList pageTreeMap = null;
  141. /**
  142. * @return the pageList
  143. */
  144. public PageList getPageList() {
  145. return pageList;
  146. }
  147. /**
  148. * @param pageList to set
  149. */
  150. public void setPagelist(PageList pageList) {
  151. this.pageList = pageList;
  152. }
  153. /**
  154. * @return the pgListIndex
  155. */
  156. public int getPgListIndex() {
  157. return pgListIndex;
  158. }
  159. /**
  160. * @param pgListIndex to set
  161. */
  162. public void setPgListIndex(int pgListIndex) {
  163. this.pgListIndex = pgListIndex;
  164. }
  165. public Page getCurr1stPage() {
  166. if (pageArray == null) {
  167. return null;
  168. }
  169. return (Page)(pageArray.get(0));
  170. }
  171. /**
  172. * The number of the page being laid out
  173. */
  174. private int currPageNumber = 0;
  175. private FoRoot root;
  176. private void getInitialPageNumber() {
  177. PropertyValue pv;
  178. try {
  179. pv = getPropertyValue(PropNames.INITIAL_PAGE_NUMBER);
  180. } catch (PropertyException e) {
  181. throw new RuntimeException(
  182. "Unable to obtain InitialPageNumber value");
  183. }
  184. int i = 0;
  185. int lastnum = root.getLastPageNumber();
  186. switch (pv.getType()) {
  187. case PropertyValue.AUTO:
  188. currPageNumber = lastnum + 1;
  189. break;
  190. case PropertyValue.ENUM:
  191. i = ((EnumType)pv).getEnumValue();
  192. switch (i) {
  193. case InitialPageNumber.AUTO_ODD:
  194. currPageNumber =
  195. ((lastnum % 2 == 0) ? lastnum + 1 : lastnum + 2);
  196. break;
  197. case InitialPageNumber.AUTO_EVEN:
  198. currPageNumber =
  199. ((lastnum % 2 == 0) ? lastnum + 2 : lastnum + 1);
  200. break;
  201. default:
  202. throw new RuntimeException(
  203. "Unknown InitialPageNumber enum value: " + i);
  204. }
  205. case PropertyValue.INTEGER:
  206. i = ((IntegerType)pv).getInt();
  207. if (i < 0) {
  208. currPageNumber = 1;
  209. } else {
  210. currPageNumber = i;
  211. }
  212. break;
  213. case PropertyValue.NUMERIC:
  214. i = ((Numeric)pv).asInt();
  215. if (i < 0) {
  216. currPageNumber = 1;
  217. } else {
  218. currPageNumber = i;
  219. }
  220. break;
  221. default:
  222. throw new RuntimeException("Invalid property value type "
  223. + PropertyValue.propertyTypes.get(pv.getType()));
  224. }
  225. }
  226. /** Maps flownames to fo:flow and fo:static-content objects */
  227. private HashMap flowMap = new HashMap(10);
  228. /**
  229. * Maps a flow name to a <code>FoFlow</code> or <code>FoStaticContent</code>
  230. * object.
  231. * @param flowname the name of the flow
  232. * @param flow the flow or static-content object
  233. * @throws FOPException if object that the name is being mapped to is
  234. * not a flow or static-content
  235. */
  236. public void mapFlowName(String flowname, FOPageSeqNode flow)
  237. throws FOPException {
  238. synchronized (flowMap) {
  239. if ( ! (flow.type == FObjectNames.FLOW
  240. || flow.type == FObjectNames.STATIC_CONTENT)) {
  241. throw new FOPException(
  242. "Only fo:flow or fo:static-content allowed in flowmap");
  243. }
  244. flowMap.put(flowname, flow);
  245. }
  246. }
  247. /**
  248. * @param flowname
  249. * @return
  250. */
  251. public FOPageSeqNode unmapFlowName(String flowname) {
  252. synchronized (flowMap) {
  253. return (FOPageSeqNode)(flowMap.get(flowname));
  254. }
  255. }
  256. /** An image on which to draw areas */
  257. private BufferedImage pageSpread = null;
  258. /**
  259. * Gets the page spread image from which the <code>Graphics2D</code> and
  260. * <code>FontRenderContext</code> have been derived.
  261. * @return the page spread
  262. */
  263. public BufferedImage getPageSpread() {
  264. return pageSpread;
  265. }
  266. /**
  267. * @param foTree the FO tree being built
  268. * @param parent the parent FONode of this node
  269. * @param event the <tt>XmlEvent</tt> that triggered the creation of
  270. * this node
  271. * @param pageSeqMasters a <code>Map</code> of the page sequence masters
  272. * from the layout master set
  273. */
  274. public FoPageSequence(FOTree foTree, FONode parent, FoXmlEvent event,
  275. Map pageSeqMasters)
  276. throws TreeException, FOPException
  277. {
  278. super(foTree, FObjectNames.PAGE_SEQUENCE, parent, event,
  279. FONode.PAGESEQ_SET, sparsePropsMap, sparseIndices);
  280. root = (FoRoot)parent;
  281. // Set up the graphics environment
  282. pageSpread =
  283. new BufferedImage(20*72, 12*72, BufferedImage.TYPE_INT_RGB);
  284. XmlEvent ev;
  285. // Look for optional title
  286. log.finer("page-sequence title");
  287. String nowProcessing = "title";
  288. try {
  289. ev = xmlevents.expectStartElement
  290. (FObjectNames.TITLE, XmlEvent.DISCARD_W_SPACE);
  291. if (ev != null) {
  292. // process the title
  293. title = numChildren();
  294. new FoTitle(getFOTree(), this, (FoXmlEvent)ev);
  295. ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
  296. namespaces.relinquishEvent(ev);
  297. } // else ignore
  298. // Look for zero or more static-content subtrees
  299. log.finer("static-content");
  300. nowProcessing = "static-content";
  301. while ((ev = xmlevents.expectStartElement
  302. (FObjectNames.STATIC_CONTENT, XmlEvent.DISCARD_W_SPACE))
  303. != null) {
  304. // Loop over remaining fo:static-content
  305. if (firstStaticContent == -1) {
  306. firstStaticContent = numChildren();
  307. staticSubtrees = new HashMap();
  308. }
  309. FoStaticContent statContent =
  310. new FoStaticContent(getFOTree(), this, (FoXmlEvent)ev);
  311. namespaces.relinquishEvent(ev);
  312. // Collect the static-content subtrees for this page-sequence
  313. String flowname = statContent.getFlowName();
  314. if (! staticSubtrees.containsKey(flowname)) {
  315. // Create a new list for this key
  316. staticSubtrees.put(flowname, new ArrayList(1));
  317. }
  318. // Add an entry to an existing List
  319. ArrayList statconsList =
  320. (ArrayList)(staticSubtrees.get(flowname));
  321. statconsList.add(statContent);
  322. }
  323. // Create the unmodifiable map of unmodifiable lists
  324. // TODO make the contents of the events buffer unmodifiable
  325. // Each value in the Map is an ArrayList. Iterate over all of the
  326. // entries, replacing the ArrayList value in each Map.Entry with an
  327. // unmodifiableList constructed from the ArrayList
  328. if (staticSubtrees != null) {
  329. Set entries = staticSubtrees.entrySet();
  330. Iterator iter = entries.iterator();
  331. while (iter.hasNext()) {
  332. Map.Entry entry = (Map.Entry)(iter.next());
  333. entry.setValue(
  334. Collections.unmodifiableList(
  335. (List)(entry.getValue())));
  336. }
  337. // Now make an unmodifiableMap from the overall HashMap
  338. // of flow-name indexed ArrayLists
  339. staticContents = Collections.unmodifiableMap(staticSubtrees);
  340. }
  341. // Generate a null page for the flow(s)
  342. page = Page.setupNullPage(this, foTree.getNextPageId());
  343. // Intialize the PageList for this page-sequence
  344. pageList = new PageList(page);
  345. pgListIndex = 0;
  346. // Look for one or more fo:flow
  347. // must have at least one: N.B. in 1.0, only one is allowed,
  348. // but in 1.1. multiple flows are allowed with different
  349. // flow maps
  350. log.finer("flow");
  351. nowProcessing = "flow";
  352. ev = xmlevents.expectStartElement
  353. (FObjectNames.FLOW, XmlEvent.DISCARD_W_SPACE);
  354. if (ev == null)
  355. throw new FOPException("No flow found.");
  356. flowChild = numChildren();
  357. new FoFlow(getFOTree(), this, (FoXmlEvent)ev);
  358. ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
  359. namespaces.relinquishEvent(ev);
  360. while ((ev = xmlevents.expectStartElement
  361. (FObjectNames.FLOW, XmlEvent.DISCARD_W_SPACE))
  362. != null) {
  363. // Loop over remaining fo:flow elements
  364. new FoFlow(getFOTree(), this, (FoXmlEvent)ev);
  365. ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
  366. namespaces.relinquishEvent(ev);
  367. }
  368. } catch (NoSuchElementException e) {
  369. throw new FOPException
  370. ("Unexpected EOF while processing " + nowProcessing + ".");
  371. } catch(TreeException e) {
  372. throw new FOPException("TreeException: " + e.getMessage());
  373. } catch(PropertyException e) {
  374. throw new FOPException("PropertyException: " + e.getMessage());
  375. }
  376. makeSparsePropsSet();
  377. }
  378. public Area getReferenceRectangle() throws FOPException {
  379. // TODO Reference rectangle is assumed to be equivalent to the
  380. // "auto" value on "page-height" and "page-width". The
  381. // inline-progression-dimension and block-progression-dimension are
  382. // calculated according to the computed values of the
  383. // reference-orientation and writing-mode of the FO for which the
  384. // percentage is calculated. See
  385. // 7.3 Reference Rectangle for Percentage Computations
  386. throw new FOPException("Called from FoPageSequence");
  387. }
  388. }