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.

RelativeNumericProperty.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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.fo.expr;
  19. import org.apache.fop.datatypes.Length;
  20. import org.apache.fop.datatypes.PercentBaseContext;
  21. import org.apache.fop.datatypes.Numeric;
  22. import org.apache.fop.fo.properties.Property;
  23. import org.apache.fop.fo.properties.TableColLength;
  24. /**
  25. * This class represent a node in a property expression tree.
  26. * It is created when an operation involve relative expression and is used
  27. * to delay evaluation of the operation until the time where getNumericValue()
  28. * or getValue() is called.
  29. */
  30. public class RelativeNumericProperty extends Property implements Length {
  31. /** ADDITION */
  32. public static final int ADDITION = 1;
  33. /** SUBTRACTION */
  34. public static final int SUBTRACTION = 2;
  35. /** MULTIPLY */
  36. public static final int MULTIPLY = 3;
  37. /** DIVIDE */
  38. public static final int DIVIDE = 4;
  39. /** MODULO */
  40. public static final int MODULO = 5;
  41. /** NEGATE */
  42. public static final int NEGATE = 6;
  43. /** ABS */
  44. public static final int ABS = 7;
  45. /** MAX */
  46. public static final int MAX = 8;
  47. /** MIN */
  48. public static final int MIN = 9;
  49. // Used in the toString() method, indexed by operation id.
  50. private static String operations = " +-*/%";
  51. /**
  52. * The operation identifier.
  53. */
  54. private int operation;
  55. /**
  56. * The first (or only) operand.
  57. */
  58. private Numeric op1;
  59. /**
  60. * The second operand.
  61. */
  62. private Numeric op2 = null;
  63. /**
  64. * The dimension of the result.
  65. */
  66. private int dimension;
  67. /**
  68. * Constructor for a two argument operation.
  69. * @param operation the operation opcode: ADDITION, SUBTRACTION, ...
  70. * @param op1 the first operand.
  71. * @param op2 the second operand
  72. */
  73. public RelativeNumericProperty(int operation, Numeric op1, Numeric op2) {
  74. this.operation = operation;
  75. this.op1 = op1;
  76. this.op2 = op2;
  77. // Calculate the dimension. We can do now.
  78. switch (operation) {
  79. case MULTIPLY:
  80. dimension = op1.getDimension() + op2.getDimension();
  81. break;
  82. case DIVIDE:
  83. dimension = op1.getDimension() - op2.getDimension();
  84. break;
  85. default:
  86. dimension = op1.getDimension();
  87. }
  88. }
  89. /**
  90. * Constructor for a one argument operation.
  91. * @param operation the operation opcode: NEGATE, ABS
  92. * @param op the operand.
  93. */
  94. public RelativeNumericProperty(int operation, Numeric op) {
  95. this.operation = operation;
  96. this.op1 = op;
  97. this.dimension = op.getDimension();
  98. }
  99. /**
  100. * Return a resolved (calculated) Numeric with the value of the expression.
  101. * @param context Evaluation context
  102. * @return the resolved {@link Numeric} corresponding to the value of the expression
  103. * @throws PropertyException when an exception occur during evaluation.
  104. */
  105. private Numeric getResolved(PercentBaseContext context) throws PropertyException {
  106. switch (operation) {
  107. case ADDITION:
  108. return NumericOp.addition2(op1, op2, context);
  109. case SUBTRACTION:
  110. return NumericOp.subtraction2(op1, op2, context);
  111. case MULTIPLY:
  112. return NumericOp.multiply2(op1, op2, context);
  113. case DIVIDE:
  114. return NumericOp.divide2(op1, op2, context);
  115. case MODULO:
  116. return NumericOp.modulo2(op1, op2, context);
  117. case NEGATE:
  118. return NumericOp.negate2(op1, context);
  119. case ABS:
  120. return NumericOp.abs2(op1, context);
  121. case MAX:
  122. return NumericOp.max2(op1, op2, context);
  123. case MIN:
  124. return NumericOp.min2(op1, op2, context);
  125. default:
  126. throw new PropertyException("Unknown expr operation " + operation);
  127. }
  128. }
  129. /**
  130. * Return the resolved (calculated) value of the expression.
  131. * {@inheritDoc}
  132. */
  133. public double getNumericValue() throws PropertyException {
  134. return getResolved(null).getNumericValue(null);
  135. }
  136. /**
  137. * {@inheritDoc}
  138. */
  139. public double getNumericValue(PercentBaseContext context) throws PropertyException {
  140. return getResolved(context).getNumericValue(context);
  141. }
  142. /**
  143. * Return the dimension of the expression
  144. * @return numeric value as dimension
  145. */
  146. public int getDimension() {
  147. return dimension;
  148. }
  149. /**
  150. * Return false since an expression is only created when there is relative
  151. * numerics involved.
  152. * @return true if expression is absolute
  153. */
  154. public boolean isAbsolute() {
  155. return false;
  156. }
  157. /**
  158. * Cast this numeric as a Length.
  159. * @return numeric value as length
  160. */
  161. public Length getLength() {
  162. if (dimension == 1) {
  163. return this;
  164. }
  165. log.error("Can't create length with dimension " + dimension);
  166. return null;
  167. }
  168. /** @return numeric value */
  169. public Numeric getNumeric() {
  170. return this;
  171. }
  172. /**
  173. * {@inheritDoc}
  174. */
  175. public int getValue() {
  176. try {
  177. return (int) getNumericValue();
  178. } catch (PropertyException exc) {
  179. log.error(exc);
  180. }
  181. return 0;
  182. }
  183. /**
  184. * {@inheritDoc}
  185. */
  186. public int getValue(PercentBaseContext context) {
  187. try {
  188. return (int) getNumericValue(context);
  189. } catch (PropertyException exc) {
  190. log.error(exc);
  191. }
  192. return 0;
  193. }
  194. /**
  195. * Return the number of table units which are included in this length
  196. * specification. This will always be 0 unless the property specification
  197. * used the proportional-column-width() function (only on table column FOs).
  198. * <p>
  199. * If this value is not 0, the actual value of the Length cannot be known
  200. * without looking at all of the columns in the table to determine the value
  201. * of a "table-unit".
  202. *
  203. * @return The number of table units which are included in this length
  204. * specification.
  205. */
  206. public double getTableUnits() {
  207. double tu1 = 0.0, tu2 = 0.0;
  208. if (op1 instanceof RelativeNumericProperty) {
  209. tu1 = ((RelativeNumericProperty) op1).getTableUnits();
  210. } else if (op1 instanceof TableColLength) {
  211. tu1 = ((TableColLength) op1).getTableUnits();
  212. }
  213. if (op2 instanceof RelativeNumericProperty) {
  214. tu2 = ((RelativeNumericProperty) op2).getTableUnits();
  215. } else if (op2 instanceof TableColLength) {
  216. tu2 = ((TableColLength) op2).getTableUnits();
  217. }
  218. if (tu1 != 0.0 && tu2 != 0.0) {
  219. switch (operation) {
  220. case ADDITION:
  221. return tu1 + tu2;
  222. case SUBTRACTION:
  223. return tu1 - tu2;
  224. case MULTIPLY:
  225. return tu1 * tu2;
  226. case DIVIDE:
  227. return tu1 / tu2;
  228. case MODULO:
  229. return tu1 % tu2;
  230. case MIN:
  231. return Math.min(tu1, tu2);
  232. case MAX:
  233. return Math.max(tu1, tu2);
  234. default:
  235. assert false;
  236. }
  237. } else if (tu1 != 0.0) {
  238. switch (operation) {
  239. case NEGATE:
  240. return -tu1;
  241. case ABS:
  242. return Math.abs(tu1);
  243. default:
  244. return tu1;
  245. }
  246. } else if (tu2 != 0.0) {
  247. return tu2;
  248. }
  249. return 0.0;
  250. }
  251. /**
  252. * Return a string represention of the expression. Only used for debugging.
  253. * @return the string representation.
  254. */
  255. public String toString() {
  256. switch (operation) {
  257. case ADDITION: case SUBTRACTION:
  258. case DIVIDE: case MULTIPLY: case MODULO:
  259. return "(" + op1 + " " + operations.charAt(operation) + op2 + ")";
  260. case NEGATE:
  261. return "-" + op1;
  262. case MAX:
  263. return "max(" + op1 + ", " + op2 + ")";
  264. case MIN:
  265. return "min(" + op1 + ", " + op2 + ")";
  266. case ABS:
  267. return "abs(" + op1 + ")";
  268. default:
  269. return "unknown operation " + operation;
  270. }
  271. }
  272. }