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.

FObj.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Copyright 1999-2004 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.fo;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.Iterator;
  21. import java.util.ListIterator;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import org.apache.fop.fo.flow.Marker;
  25. import org.apache.fop.fo.properties.PropertyMaker;
  26. import org.xml.sax.Attributes;
  27. import org.xml.sax.Locator;
  28. import org.xml.sax.SAXParseException;
  29. /**
  30. * Base class for representation of formatting objects and their processing.
  31. */
  32. public class FObj extends FONode implements Constants {
  33. public static PropertyMaker[] propertyListTable = null;
  34. /** The immediate child nodes of this node. */
  35. public ArrayList childNodes = null;
  36. /** Used to indicate if this FO is either an Out Of Line FO (see rec)
  37. or a descendant of one. Used during validateChildNode() FO
  38. validation.
  39. */
  40. private boolean isOutOfLineFODescendant = false;
  41. /** Markers added to this element. */
  42. protected Map markers = null;
  43. /** Dynamic layout dimension. Used to resolve relative lengths. */
  44. protected Map layoutDimension = null;
  45. /**
  46. * Create a new formatting object.
  47. * All formatting object classes extend this class.
  48. *
  49. * @param parent the parent node
  50. * @todo move propertyListTable initialization someplace else?
  51. */
  52. public FObj(FONode parent) {
  53. super(parent);
  54. // determine if isOutOfLineFODescendant should be set
  55. if (parent != null && parent instanceof FObj) {
  56. if (((FObj)parent).getIsOutOfLineFODescendant() == true) {
  57. isOutOfLineFODescendant = true;
  58. } else {
  59. int foID = getNameId();
  60. if (foID == FO_FLOAT || foID == FO_FOOTNOTE
  61. || foID == FO_FOOTNOTE_BODY) {
  62. isOutOfLineFODescendant = true;
  63. }
  64. }
  65. }
  66. if (propertyListTable == null) {
  67. propertyListTable = new PropertyMaker[Constants.PROPERTY_COUNT+1];
  68. PropertyMaker[] list = FOPropertyMapping.getGenericMappings();
  69. for (int i = 1; i < list.length; i++) {
  70. if (list[i] != null)
  71. propertyListTable[i] = list[i];
  72. }
  73. }
  74. }
  75. /**
  76. * @see org.apache.fop.fo.FONode#processNode
  77. */
  78. public void processNode(String elementName, Locator locator,
  79. Attributes attlist, PropertyList pList) throws SAXParseException {
  80. setLocator(locator);
  81. pList.addAttributesToList(attlist);
  82. pList.setWritingMode();
  83. bind(pList);
  84. }
  85. /**
  86. * Create a default property list for this element.
  87. */
  88. protected PropertyList createPropertyList(PropertyList parent, FOEventHandler foEventHandler) throws SAXParseException {
  89. return foEventHandler.getPropertyListMaker().make(this, parent);
  90. }
  91. /**
  92. * Bind property values from the property list to the FO node.
  93. * Must be overriden in all FObj subclasses.
  94. * @param pList the PropertyList where the properties can be found.
  95. * @throws SAXParseException
  96. */
  97. public void bind(PropertyList pList) throws SAXParseException {
  98. // throw new SAXParseException("Unconverted element " + this, locator);
  99. }
  100. /**
  101. * Setup the id for this formatting object.
  102. * Most formatting objects can have an id that can be referenced.
  103. * This methods checks that the id isn't already used by another
  104. * fo and sets the id attribute of this object.
  105. */
  106. protected void checkId(String id) throws SAXParseException {
  107. if (!id.equals("")) {
  108. Set idrefs = getFOEventHandler().getIDReferences();
  109. if (!idrefs.contains(id)) {
  110. idrefs.add(id);
  111. } else {
  112. throw new SAXParseException("Property id \"" + id +
  113. "\" previously used; id values must be unique" +
  114. " in document.", locator);
  115. }
  116. }
  117. }
  118. /**
  119. * Returns Out Of Line FO Descendant indicator.
  120. * @return true if Out of Line FO or Out Of Line descendant, false otherwise
  121. */
  122. public boolean getIsOutOfLineFODescendant() {
  123. return isOutOfLineFODescendant;
  124. }
  125. /**
  126. * @see org.apache.fop.fo.FONode#addChildNode(FONode)
  127. */
  128. protected void addChildNode(FONode child) throws SAXParseException {
  129. if (PropertySets.canHaveMarkers(getNameId()) &&
  130. child.getNameId() == FO_MARKER) {
  131. addMarker((Marker) child);
  132. } else {
  133. if (childNodes == null) {
  134. childNodes = new ArrayList();
  135. }
  136. childNodes.add(child);
  137. }
  138. }
  139. /**
  140. * Find the nearest parent, grandparent, etc. FONode that is also an FObj
  141. * @return FObj the nearest ancestor FONode that is an FObj
  142. */
  143. public FObj findNearestAncestorFObj() {
  144. FONode par = parent;
  145. while (par != null && !(par instanceof FObj)) {
  146. par = par.parent;
  147. }
  148. return (FObj) par;
  149. }
  150. /* This section is the implemenation of the property context. */
  151. /**
  152. * Assign the size of a layout dimension to the key.
  153. * @param key the Layout dimension, from PercentBase.
  154. * @param dimension The layout length.
  155. */
  156. public void setLayoutDimension(Integer key, int dimension) {
  157. if (layoutDimension == null){
  158. layoutDimension = new HashMap();
  159. }
  160. layoutDimension.put(key, new Integer(dimension));
  161. }
  162. /**
  163. * Assign the size of a layout dimension to the key.
  164. * @param key the Layout dimension, from PercentBase.
  165. * @param dimension The layout length.
  166. */
  167. public void setLayoutDimension(Integer key, float dimension) {
  168. if (layoutDimension == null){
  169. layoutDimension = new HashMap();
  170. }
  171. layoutDimension.put(key, new Float(dimension));
  172. }
  173. /**
  174. * Return the size associated with the key.
  175. * @param key The layout dimension key.
  176. * @return the length.
  177. */
  178. public Number getLayoutDimension(Integer key) {
  179. if (layoutDimension != null) {
  180. Number result = (Number) layoutDimension.get(key);
  181. if (result != null) {
  182. return result;
  183. }
  184. }
  185. if (parent != null) {
  186. return ((FObj) parent).getLayoutDimension(key);
  187. }
  188. return new Integer(0);
  189. }
  190. /**
  191. * Check if this formatting object generates reference areas.
  192. * @return true if generates reference areas
  193. * @todo see if needed
  194. */
  195. public boolean generatesReferenceAreas() {
  196. return false;
  197. }
  198. /**
  199. * @see org.apache.fop.fo.FONode#getChildNodes()
  200. */
  201. public ListIterator getChildNodes() {
  202. if (childNodes != null) {
  203. return childNodes.listIterator();
  204. }
  205. return null;
  206. }
  207. /**
  208. * Return an iterator over the object's childNodes starting
  209. * at the passed-in node.
  210. * @param childNode First node in the iterator
  211. * @return A ListIterator or null if childNode isn't a child of
  212. * this FObj.
  213. */
  214. public ListIterator getChildNodes(FONode childNode) {
  215. if (childNodes != null) {
  216. int i = childNodes.indexOf(childNode);
  217. if (i >= 0) {
  218. return childNodes.listIterator(i);
  219. }
  220. }
  221. return null;
  222. }
  223. /**
  224. * Add the marker to this formatting object.
  225. * If this object can contain markers it checks that the marker
  226. * has a unique class-name for this object and that it is
  227. * the first child.
  228. * @param marker Marker to add.
  229. */
  230. protected void addMarker(Marker marker) {
  231. String mcname = marker.getMarkerClassName();
  232. if (childNodes != null) {
  233. // check for empty childNodes
  234. for (Iterator iter = childNodes.iterator(); iter.hasNext();) {
  235. FONode node = (FONode)iter.next();
  236. if (node instanceof FOText) {
  237. FOText text = (FOText)node;
  238. if (text.willCreateArea()) {
  239. getLogger().error("fo:marker must be an initial child: " + mcname);
  240. return;
  241. } else {
  242. iter.remove();
  243. }
  244. } else {
  245. getLogger().error("fo:marker must be an initial child: " + mcname);
  246. return;
  247. }
  248. }
  249. }
  250. if (markers == null) {
  251. markers = new HashMap();
  252. }
  253. if (!markers.containsKey(mcname)) {
  254. markers.put(mcname, marker);
  255. } else {
  256. getLogger().error("fo:marker 'marker-class-name' "
  257. + "must be unique for same parent: " + mcname);
  258. }
  259. }
  260. /**
  261. * @return true if there are any Markers attached to this object
  262. */
  263. public boolean hasMarkers() {
  264. return markers != null && !markers.isEmpty();
  265. }
  266. /**
  267. * @return th collection of Markers attached to this object
  268. */
  269. public Map getMarkers() {
  270. return markers;
  271. }
  272. /*
  273. * Return a string representation of the fo element.
  274. * Deactivated in order to see precise ID of each fo element created
  275. * (helpful for debugging)
  276. */
  277. /* public String toString() {
  278. return getName() + " at line " + line + ":" + column;
  279. }
  280. */
  281. /**
  282. * Convenience method for validity checking. Checks if the
  283. * incoming node is a member of the "%block;" parameter entity
  284. * as defined in Sect. 6.2 of the XSL 1.0 & 1.1 Recommendations
  285. * @param nsURI namespace URI of incoming node
  286. * @param lName local name (i.e., no prefix) of incoming node
  287. * @return true if a member, false if not
  288. */
  289. protected boolean isBlockItem(String nsURI, String lName) {
  290. return (nsURI == FO_URI &&
  291. (lName.equals("block")
  292. || lName.equals("table")
  293. || lName.equals("table-and-caption")
  294. || lName.equals("block-container")
  295. || lName.equals("list-block")
  296. || lName.equals("float")
  297. || isNeutralItem(nsURI, lName)));
  298. }
  299. /**
  300. * Convenience method for validity checking. Checks if the
  301. * incoming node is a member of the "%inline;" parameter entity
  302. * as defined in Sect. 6.2 of the XSL 1.0 & 1.1 Recommendations
  303. * @param nsURI namespace URI of incoming node
  304. * @param lName local name (i.e., no prefix) of incoming node
  305. * @return true if a member, false if not
  306. */
  307. protected boolean isInlineItem(String nsURI, String lName) {
  308. return (nsURI == FO_URI &&
  309. (lName.equals("bidi-override")
  310. || lName.equals("character")
  311. || lName.equals("external-graphic")
  312. || lName.equals("instream-foreign-object")
  313. || lName.equals("inline")
  314. || lName.equals("inline-container")
  315. || lName.equals("leader")
  316. || lName.equals("page-number")
  317. || lName.equals("page-number-citation")
  318. || lName.equals("basic-link")
  319. || (lName.equals("multi-toggle")
  320. && (getNameId() == FO_MULTI_CASE || findAncestor(FO_MULTI_CASE) > 0))
  321. || (lName.equals("footnote") && !isOutOfLineFODescendant)
  322. || isNeutralItem(nsURI, lName)));
  323. }
  324. /**
  325. * Convenience method for validity checking. Checks if the
  326. * incoming node is a member of the "%block;" parameter entity
  327. * or "%inline;" parameter entity
  328. * @param nsURI namespace URI of incoming node
  329. * @param lName local name (i.e., no prefix) of incoming node
  330. * @return true if a member, false if not
  331. */
  332. protected boolean isBlockOrInlineItem(String nsURI, String lName) {
  333. return (isBlockItem(nsURI, lName) || isInlineItem(nsURI, lName));
  334. }
  335. /**
  336. * Convenience method for validity checking. Checks if the
  337. * incoming node is a member of the neutral item list
  338. * as defined in Sect. 6.2 of the XSL 1.0 & 1.1 Recommendations
  339. * @param nsURI namespace URI of incoming node
  340. * @param lName local name (i.e., no prefix) of incoming node
  341. * @return true if a member, false if not
  342. */
  343. protected boolean isNeutralItem(String nsURI, String lName) {
  344. return (nsURI == FO_URI &&
  345. (lName.equals("multi-switch")
  346. || lName.equals("multi-properties")
  347. || lName.equals("wrapper")
  348. || (!isOutOfLineFODescendant && lName.equals("float"))
  349. || lName.equals("retrieve-marker")));
  350. }
  351. /**
  352. * Convenience method for validity checking. Checks if the
  353. * current node has an ancestor of a given name.
  354. * @param ancestorID -- Constants ID of node name to check for (e.g., FO_ROOT)
  355. * @return number of levels above FO where ancestor exists,
  356. * -1 if not found
  357. */
  358. protected int findAncestor(int ancestorID) {
  359. int found = 1;
  360. FONode temp = getParent();
  361. while (temp != null) {
  362. if (temp.getNameId() == ancestorID) {
  363. return found;
  364. }
  365. found += 1;
  366. temp = temp.getParent();
  367. }
  368. return -1;
  369. }
  370. }