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.

FONode.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*
  2. Copyright 2002-2004 The Apache Software Foundation.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. * Created: Sat Nov 10 01:39:37 2001
  13. * $Id: FONode.java,v 1.19.2.33 2003/06/12 18:19:33 pbwest Exp $
  14. */
  15. package org.apache.fop.fo;
  16. import java.util.BitSet;
  17. import java.util.HashMap;
  18. import java.util.Iterator;
  19. import java.util.logging.Level;
  20. import java.util.logging.Logger;
  21. import org.apache.fop.apps.FOPException;
  22. import org.apache.fop.datastructs.ROBitSet;
  23. import org.apache.fop.datastructs.SyncedNode;
  24. import org.apache.fop.datastructs.TreeException;
  25. import org.apache.fop.datatypes.Numeric;
  26. import org.apache.fop.datatypes.PropertyValue;
  27. import org.apache.fop.datatypes.PropertyValueList;
  28. import org.apache.fop.datatypes.TextDecorations;
  29. import org.apache.fop.datatypes.indirect.IndirectValue;
  30. import org.apache.fop.fo.expr.FunctionNotImplementedException;
  31. import org.apache.fop.fo.expr.PropertyException;
  32. import org.apache.fop.fo.expr.PropertyParser;
  33. import org.apache.fop.fo.properties.CorrespondingProperty;
  34. import org.apache.fop.fo.properties.Property;
  35. import org.apache.fop.xml.XmlEvent;
  36. import org.apache.fop.xml.Namespaces;
  37. import org.apache.fop.xml.XmlEventReader;
  38. /**
  39. * Class for nodes in the FO tree.
  40. *
  41. * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
  42. * @version $Revision: 1.19.2.33 $ $Name: $
  43. */
  44. public class FONode extends SyncedNode{
  45. private static final String tag = "$Name: $";
  46. private static final String revision = "$Revision: 1.19.2.33 $";
  47. /**
  48. * State flags: a bit set of states applicable during FO tree build.
  49. * N.B. States must be powers of 2.
  50. * <p><b>BEWARE</b> At what point are these ancestry flags supposed to
  51. * apply? If they are son-of (MC), they should only be expected to
  52. * be applied on the children of a particular node type. I don't think
  53. * the higher level FO nodes are making this assumption.
  54. * <p>Just changed most of the higher-level flags by removing the MC_
  55. * prefix, which remains on some of the lower levels. Use this convention
  56. * for now: unprefixed name (e.g. Root), is a self-or-descendent
  57. * indicator, while MC_ prefixed names are descendents only.
  58. * <p>TODO: check for consistency of application.
  59. */
  60. public static final int
  61. NOSTATE = 0
  62. // These are used to select the attribute set for the node
  63. ,ROOT = 1
  64. ,DECLARATIONS = 2
  65. ,LAYOUT = 4
  66. ,SEQ_MASTER = 8
  67. ,PAGESEQ = 16
  68. ,FLOW = 32
  69. ,STATIC = 64
  70. ,TITLE = 128
  71. ,MC_MARKER = 256
  72. ,MC_FLOAT = 512
  73. ,MC_FOOTNOTE = 1024
  74. ,MC_MULTI_CASE = 2048
  75. ,MC_ABSOLUTELY_POSITIONED = 4096
  76. ,MC_LEADER = 8192
  77. ;
  78. public static final int
  79. ROOT_SET = ROOT
  80. ,DECLARATIONS_SET = ROOT | DECLARATIONS
  81. ,LAYOUT_SET = ROOT | LAYOUT
  82. ,SEQ_MASTER_SET = LAYOUT_SET | SEQ_MASTER
  83. ,PAGESEQ_SET = ROOT | PAGESEQ
  84. ,FLOW_SET = PAGESEQ_SET | FLOW
  85. ,STATIC_SET = PAGESEQ_SET | STATIC
  86. ,TITLE_SET = PAGESEQ_SET | TITLE
  87. ,MARKER_SET = FLOW_SET | MC_MARKER
  88. ;
  89. public static final int MC_OUT_OF_LINE =
  90. MC_FLOAT | MC_FOOTNOTE | MC_ABSOLUTELY_POSITIONED;
  91. /** The subset of <i>stateFlags</i> that select the relevant
  92. atttribute set or the node. */
  93. public static final int ATTRIBUTESETS =
  94. ROOT | DECLARATIONS | LAYOUT | SEQ_MASTER |
  95. PAGESEQ | FLOW | STATIC | TITLE | MC_MARKER;
  96. /**
  97. * The FO Tree
  98. */
  99. protected final FOTree foTree;
  100. protected final Logger log;
  101. /** The buffer from which parser events are drawn. */
  102. protected final XmlEventReader xmlevents;
  103. /** The namespaces object associated with <i>xmlevents</i>. */
  104. protected final Namespaces namespaces;
  105. /** The FO type. */
  106. public final int type;
  107. /** The attributes defined on this node. When the FO subtree of this
  108. * node has been constructed, it will be deleted. */
  109. public FOAttributes foAttributes;
  110. /** The map of properties specified on this node. N.B. This
  111. * <tt>HashMap</tt> starts life in FOAttributes. It is modifiable, and
  112. * will be modified when is contains shorthands or compounds.
  113. * When the FO subtree of this node has been constructed, and the
  114. * <i>propertySet</i> is complete, it will be deleted. */
  115. public HashMap foProperties = null;
  116. /** The sorted keys of <i>foProperties</i>. */
  117. protected Integer[] foKeys = null;
  118. /** The size of <i>foKeys</i>. */
  119. private int numAttrs = 0;
  120. /** BitSet of properties which have been specified on this node. */
  121. private BitSet specifiedProps =
  122. new BitSet(PropNames.LAST_PROPERTY_INDEX + 1);
  123. /** The property set for this node. This reference has two lives.
  124. During FO subtree building, it holds all values which may potentially
  125. be defined on the node. It must, therefore, be able to accommodate
  126. every property. When FO subtree construction is completed, the
  127. <i>sparsePropsSet</i> array is constructed for use during Area
  128. tree building, and <i>propertySet</i> is nullified.
  129. While <i>sparsePropsSet</i> is null,
  130. this variable will be a reference to the complete property set. */
  131. private PropertyValue[] propertySet;
  132. /** The set of properties directly applicable to this node. Its size is
  133. determined by the <i>numProps</i> value passed in to the constructor.
  134. */
  135. private PropertyValue[] sparsePropsSet;
  136. /** Map of <tt>Integer</tt> indices of <i>sparsePropsSet</i> array.
  137. It is indexed by the FO index of the FO associated with a given
  138. position in the <i>propertySet</i> array. */
  139. private final int[] sparsePropsMap;
  140. /** An array of of the applicable property indices, in property index
  141. order. */
  142. private final int[] sparseIndices;
  143. /** The number of applicable properties. Size of <i>sparsePropsSet</i>. */
  144. private final int numProps;
  145. /** The property expression parser in the FOTree. */
  146. protected PropertyParser exprParser;
  147. /** The <tt>ROBitSet</tt> from the <i>stateFlags</i> argument. */
  148. protected ROBitSet attrBitSet;
  149. /** The state flags passed to this node. */
  150. protected int stateFlags;
  151. /** Ancestor reference area of this FONode. */
  152. protected FONode ancestorRefArea = null;
  153. /** The number of markers on this FO. */
  154. protected int numMarkers = 0;
  155. /**
  156. * @param foTree an <tt>FOTree</tt> to which this node belongs
  157. * @param type the fo type of this FONode.
  158. * @param parent node of this node in <i>foTree</i>
  159. * @param event that triggered the creation of this node
  160. * @param stateFlags the set of states relevant at this point in the
  161. * tree. Includes the state information necessary to select an attribute
  162. * set for this node.
  163. * @param sparsePropsMap maps the property indices
  164. * to their offsets in the set of properties applicable to this node.
  165. * @param sparseIndices holds the set of property
  166. * indices applicable to this node, in ascending order.
  167. * <i>sparsePropsMap</i> maps property indices to a position in this array.
  168. * Together they provide a sparse array facility for this node's
  169. * properties.
  170. */
  171. public FONode
  172. (FOTree foTree, int type, FONode parent, XmlEvent event,
  173. int stateFlags, int[] sparsePropsMap, int[] sparseIndices)
  174. throws TreeException, FOPException, PropertyException
  175. {
  176. super(parent, foTree);
  177. this.foTree = foTree;
  178. this.log = foTree.getLogger();
  179. this.type = type;
  180. this.stateFlags = stateFlags;
  181. this.sparsePropsMap = sparsePropsMap;
  182. this.sparseIndices = sparseIndices;
  183. this.numProps = sparseIndices.length;
  184. attrBitSet = FOPropertySets.getAttrROBitSet(stateFlags);
  185. xmlevents = foTree.xmlevents;
  186. namespaces = xmlevents.getNamespaces();
  187. exprParser = foTree.exprParser;
  188. propertySet = new PropertyValue[PropNames.LAST_PROPERTY_INDEX + 1];
  189. foAttributes = new FOAttributes(event, this);
  190. if ((stateFlags & MC_MARKER) == 0) {
  191. processAttributes();
  192. }
  193. // Do not set up the remaining properties now.
  194. // These will be developed by inheritance or from the initial values
  195. // as the property values are referenced.
  196. }
  197. private void processAttributes() throws FOPException, PropertyException {
  198. // Process the FOAttributes - parse and stack the values
  199. // Build a HashMap of the properties defined on this node
  200. foProperties = foAttributes.getFoAttrMap();
  201. numAttrs = foProperties.size();
  202. if (numAttrs > 0) {
  203. foKeys = foAttributes.getFoAttrKeys();
  204. }
  205. for (int propx = 0; propx < numAttrs; propx++) {
  206. PropertyValue props;
  207. int ptype;
  208. int property;
  209. int prop = foKeys[propx].intValue();
  210. if ( ! attrBitSet.get(prop)) {
  211. if (log.isLoggable(Level.FINE)) {
  212. log.fine("Ignoring "
  213. + PropNames.getPropertyName(prop)
  214. + " on "
  215. + FObjectNames.getFOName(type)
  216. + " for attribute set "
  217. + FOPropertySets.getAttrSetName(stateFlags)
  218. + ".");
  219. continue;
  220. }
  221. }
  222. String attrValue = foAttributes.getFoAttrValue(prop);
  223. try {
  224. props = handleAttrValue(prop, attrValue);
  225. ptype = props.getType();
  226. if (ptype != PropertyValue.LIST) {
  227. handlePropertyValue(props);
  228. } else { // a list
  229. PropertyValue value;
  230. Iterator propvals = ((PropertyValueList)props).iterator();
  231. while (propvals.hasNext()) {
  232. value = (PropertyValue)(propvals.next());
  233. handlePropertyValue(value);
  234. }
  235. }
  236. } catch (FunctionNotImplementedException e) {
  237. log.info
  238. ("Function not implemented: " + e.getMessage()
  239. + ". Ignoring property '"
  240. + PropNames.getPropertyName(prop) + "'.");
  241. } catch (PropertyException e) {
  242. log.info
  243. ("Problem with '" + PropNames.getPropertyName(prop)
  244. + "':\n" + e.getMessage() + "\nIgnoring property.");
  245. }
  246. }
  247. }
  248. private void handlePropertyValue(PropertyValue propval)
  249. throws PropertyException {
  250. int property = propval.getProperty();
  251. Property tempP =
  252. PropertyConsts.pconsts.getProperty(property);
  253. specifiedProps.set(property);
  254. // Handle corresponding properties here
  255. // Note that the resolution of corresponding properties, like
  256. // shorthands and compounds, relies on the ordering imposed by the
  257. // property indices. Each property, in increasing index order, is
  258. // processed as if it were the only relevant assignment. The lowest
  259. // priority properties (among shorthands and their expansions,
  260. // compounds and their expansions, and corresponding properties and
  261. // their correspondents) are processed first, then higher priority
  262. // assignments simply overwrite the earlier value assignments.
  263. if (tempP instanceof CorrespondingProperty) {
  264. // Update the propertySet
  265. propertySet[property] = propval;
  266. int corresP =
  267. ((CorrespondingProperty)tempP)
  268. .getCorrespondingProperty(this);
  269. propertySet[corresP] = propval;
  270. }
  271. else {
  272. // Not a corresponding property
  273. // Update the propertySet
  274. propertySet[property] = propval;
  275. }
  276. }
  277. private PropertyValue handleAttrValue(int property, String attrValue)
  278. throws FunctionNotImplementedException, PropertyException
  279. {
  280. // parse the expression
  281. exprParser.resetParser();
  282. Property prop = PropertyConsts.pconsts.setupProperty(property);
  283. PropertyValue pv = exprParser.parse(this, property, attrValue);
  284. return prop.refineParsing(pv.getProperty(), this, pv);
  285. }
  286. /**
  287. * Reduce the properties currently associated with the node to a
  288. * sparse propeties set of only those properties relevant to the node.
  289. * During tree building, a node may have associated with it properties
  290. * which have no direct relevance to the node, but which may be used
  291. * by descendant nodes. Once the tree building process is finished, these
  292. * properties are no longer required. The property set for the node can
  293. * be reduced to the minimum required for this formatting object.
  294. * This minimal set is maintained in a sparse array.
  295. * @see #sparsePropsSet
  296. * @see #sparsePropsMap
  297. * @see #sparseIndices
  298. */
  299. public void makeSparsePropsSet() throws PropertyException {
  300. sparsePropsSet = new PropertyValue[numProps];
  301. // Scan the sparseIndices array, and copy the PropertyValue from
  302. // propertySet[], if it exists. Else generate the pertinent value
  303. // for that property.
  304. for (int i = 0; i < numProps; i++)
  305. sparsePropsSet[i] = getPropertyValue(sparseIndices[i]);
  306. // Clean up structures that are no longer needed
  307. propertySet = null;
  308. specifiedProps = null;
  309. attrBitSet = null;
  310. foKeys = null;
  311. foProperties = null;
  312. foAttributes = null;
  313. }
  314. /**
  315. * Get the eclosing <tt>FOTree</tt> instance of this <tt>FONode</tt>.
  316. * @return the <tt>FOTree</tt>.
  317. */
  318. public FOTree getFOTree() {
  319. return foTree;
  320. }
  321. /**
  322. * Get the adjusted <tt>PropertyValue</tt> of the property
  323. * on the nearest ancestor with a specified value for that property.
  324. * @see #fromNearestSpecified(int,int)
  325. * @see #getNearestSpecifiedValue(int)
  326. * @param property - the index of both target and source properties.
  327. * to the PropertyTriplet.
  328. * @return - the adjusted value corresponding to the nearest specified
  329. * value if it exists, else the adjusted initial value.
  330. */
  331. public PropertyValue fromNearestSpecified(int property)
  332. throws PropertyException
  333. {
  334. return fromNearestSpecified(property, property);
  335. }
  336. /**
  337. * Get the adjusted <tt>PropertyValue</tt> of the source property
  338. * on the nearest ancestor with a specified value for that property.
  339. * <p>If this node is not the root, call the
  340. * <i>getNearestSpecifiedValue</i> method in the parent node, adjust
  341. * that value, and return the adjusted value. Do not set the current
  342. * value of the property on this node.
  343. * <p>If this is the root node, return the adjusted initial value for the
  344. * property. Do not set the current value of the property on this node.
  345. * <p>The <b>adjusted value</b> is either the value itself, or, if the
  346. * value is an unresolved relative length, an <tt>IndirectValue</tt>
  347. * referring to that unresolved length.
  348. * Cf. {@link #getNearestSpecifiedValue(int)}.
  349. * @param property - the index of the target property.
  350. * @param sourceProperty - the index of the source property.
  351. * @return - the adjusted value corresponding to the nearest specified
  352. * value if it exists, else the adjusted initial value.
  353. */
  354. public PropertyValue fromNearestSpecified
  355. (int property, int sourceProperty)
  356. throws PropertyException
  357. {
  358. if (parent != null)
  359. return IndirectValue.adjustedPropertyValue
  360. (((FONode)parent).getNearestSpecifiedValue(sourceProperty));
  361. else // root
  362. return IndirectValue.adjustedPropertyValue
  363. (PropertyConsts.pconsts.getInitialValue(sourceProperty));
  364. }
  365. /**
  366. * Get the adjusted <tt>PropertyValue</tt> of the property on the nearest
  367. * ancestor with a specified value for the given property.
  368. * <p>If a value has been specified on this node, return the adjusted
  369. * value.
  370. * <p>Otherwise, if the this node is not the root, return the adjusted
  371. * value from a recursive call.
  372. * <p>If this is the root node, return the adjusted initial value for the
  373. * property.
  374. * <p>The <b>adjusted value</b> is either the value itself, or, if the
  375. * value is an unresolved relative length, an <tt>IndirectValue</tt>
  376. * referring to that unresolved length.
  377. * @param property - the property of interest.
  378. * @return the adjusted value of the nearest specified
  379. * <tt>PropertyValue</tt>.
  380. */
  381. public PropertyValue getNearestSpecifiedValue(int property)
  382. throws PropertyException
  383. {
  384. if (specifiedProps.get(property))
  385. return IndirectValue.adjustedPropertyValue(propertySet[property]);
  386. if (parent != null)
  387. return IndirectValue.adjustedPropertyValue
  388. (((FONode)parent).getNearestSpecifiedValue(property));
  389. else // root
  390. return IndirectValue.adjustedPropertyValue
  391. (PropertyConsts.pconsts.getInitialValue(property));
  392. }
  393. /**
  394. * Get the adjusted value from the parent FO of the source property.
  395. * @see #fromParent(int,int)
  396. * @see #getPropertyValue(int)
  397. * @param property - the index of both target and source properties.
  398. * @return - the adjusted value from the parent FO node, if it exists.
  399. * If not, get the adjusted initial value.
  400. */
  401. public PropertyValue fromParent(int property)
  402. throws PropertyException
  403. {
  404. return fromParent(property, property);
  405. }
  406. /**
  407. * Get the adjusted <tt>PropertyValue</tt> for the given source property
  408. * on the parent <tt>FONode</tt>. If this node is not the root,
  409. * call the <i>getPropertyValue</i> method in the parent node, adjust
  410. * that value, and return the adjusted value. Do not set the current
  411. * value of the property on this node.
  412. * <p>If this is the root node, return the adjusted initial value for the
  413. * property. Do not set the current value of the property on this node.
  414. * <p>The <b>adjusted value</b> is either the value itself, or, if the
  415. * value is an unresolved relative length, an <tt>IndirectValue</tt>
  416. * referring to that unresolved length.
  417. * Cf. {@link #getPropertyValue(int)}.
  418. * @param property - the index of the target property.
  419. * @param sourceProperty - the index of the source property.
  420. * @return - the computed value from the parent FO node, if it exists.
  421. * If not, get the adjusted initial value.
  422. */
  423. public PropertyValue fromParent(int property, int sourceProperty)
  424. throws PropertyException
  425. {
  426. if (parent != null)
  427. return IndirectValue.adjustedPropertyValue
  428. (((FONode)parent).getPropertyValue(sourceProperty));
  429. else // root
  430. return IndirectValue.adjustedPropertyValue
  431. (PropertyConsts.pconsts.getInitialValue(sourceProperty));
  432. }
  433. /**
  434. * Get the adjusted <tt>PropertyValue</tt> for the given property index.
  435. * <pre>
  436. * If the property has a value in the node, return that adjusted value.
  437. * If not, and
  438. * if this node is not the root,
  439. * and the property is an inherited property,
  440. * call this method in the parent node,
  441. * adjust that that value,
  442. * set this node's value to the adjusted value,
  443. * and return the adjusted value.
  444. * else this node is the root, or the property is not inherited
  445. * get the adjusted initial value of the property
  446. * set the property value in this node to that value,
  447. * and return that value.
  448. * <pre>
  449. * <p>The <b>adjusted value</b> is either the value itself, or, if the
  450. * value is an unresolved relative length, an <tt>IndirectValue</tt>
  451. * referring to that unresolved length
  452. * @param property the property index
  453. * @return a <tt>PropertyValue</tt> containing the adjusted property
  454. * value for the indexed property
  455. */
  456. public PropertyValue getPropertyValue(int property)
  457. throws PropertyException
  458. {
  459. PropertyValue pval;
  460. if (propertySet == null) {
  461. return IndirectValue.adjustedPropertyValue
  462. (sparsePropsSet[ sparsePropsMap[property] ]);
  463. }
  464. if ((pval = propertySet[property]) != null)
  465. return IndirectValue.adjustedPropertyValue(pval);
  466. if (parent != null && PropertyConsts.pconsts.isInherited(property))
  467. return (propertySet[property] =
  468. IndirectValue.adjustedPropertyValue
  469. (((FONode)parent).getPropertyValue(property)));
  470. else // root
  471. return (propertySet[property] =
  472. IndirectValue.adjustedPropertyValue
  473. (PropertyConsts.pconsts.getInitialValue(property)));
  474. }
  475. /**
  476. * Get the property value for the given property from the
  477. * <i>sparsePropsSet</i> array.
  478. * @param prop - the <tt>int</tt> property index.
  479. * @return the <tt>PropertyValue</tt> for the specified property.
  480. */
  481. public PropertyValue getSparsePropValue(int prop) {
  482. return sparsePropsSet[ sparsePropsMap[prop] ];
  483. }
  484. /**
  485. * Clone the adjusted <tt>PropertyValue</tt> for the given property index.
  486. * <p>The <b>adjusted value</b> is either the value itself, or, if the
  487. * value is an unresolved relative length, an <tt>IndirectValue</tt>
  488. * referring to that unresolved length.
  489. * Cf. {@link #getPropertyValue(int)}.
  490. * @param index - the property index.
  491. * @return a <tt>PropertyValue</tt> containing a clone of the adjusted
  492. * property value for the indexed property.
  493. */
  494. public PropertyValue clonePropertyValue(int index)
  495. throws PropertyException
  496. {
  497. PropertyValue tmpval = getPropertyValue(index);
  498. try {
  499. return (PropertyValue)(tmpval.clone());
  500. } catch (CloneNotSupportedException e) {
  501. throw new PropertyException("Clone not supported.");
  502. }
  503. }
  504. /**
  505. * Get the current font size. This is a reference to the
  506. * <tt>PropertyValue</tt> located.
  507. * @return a <tt>Numeric</tt> containing the current font size
  508. * @exception PropertyException if current font size is not defined,
  509. * or is not expressed as a <tt>Numeric</tt>.
  510. */
  511. public Numeric currentFontSize() throws PropertyException {
  512. PropertyValue fontsize = getPropertyValue(PropNames.FONT_SIZE);
  513. if ( ! (fontsize.getType() == PropertyValue.NUMERIC
  514. && ((Numeric)fontsize).isLength()))
  515. throw new PropertyException
  516. ("font-size value is not a length.");
  517. return (Numeric)fontsize;
  518. }
  519. /**
  520. * Clone the current font size.
  521. * @return a <tt>Numeric</tt> containing the current font size
  522. * @exception PropertyException if current font size is not defined,
  523. * or is not expressed as a <tt>Numeric</tt>, or if cloning is not
  524. * supported.
  525. */
  526. public Numeric cloneCurrentFontSize() throws PropertyException {
  527. Numeric tmpval = currentFontSize();
  528. try {
  529. return (Numeric)(tmpval.clone());
  530. } catch (CloneNotSupportedException e) {
  531. throw new PropertyException(e);
  532. }
  533. }
  534. /**
  535. * Clone the current <i>TextDecorations</i> property.
  536. * @return a <tt>TextDecorations</tt> object containing the current
  537. * text decorations
  538. * @exception PropertyException if current text decorations are not
  539. * defined, or are not expressed as <tt>TextDecorations</tt>.
  540. */
  541. public TextDecorations cloneCurrentTextDecorations()
  542. throws PropertyException
  543. {
  544. PropertyValue textdec = getPropertyValue(PropNames.TEXT_DECORATION);
  545. if (textdec.getType() != PropertyValue.TEXT_DECORATIONS)
  546. throw new PropertyException
  547. ("text-decoration value is not a TextDecorations object.");
  548. try {
  549. return (TextDecorations)(textdec.clone());
  550. } catch (CloneNotSupportedException e) {
  551. throw new PropertyException("Clone not supported.");
  552. }
  553. }
  554. }// FONode