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.

LengthRangeProperty.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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.properties;
  19. import org.apache.fop.datatypes.CompoundDatatype;
  20. import org.apache.fop.datatypes.Length;
  21. import org.apache.fop.datatypes.PercentBaseContext;
  22. import org.apache.fop.fo.FObj;
  23. import org.apache.fop.fo.PropertyList;
  24. import org.apache.fop.fo.expr.PropertyException;
  25. import org.apache.fop.traits.MinOptMax;
  26. import org.apache.fop.util.CompareUtil;
  27. /**
  28. * Superclass for properties that contain LengthRange values
  29. */
  30. public class LengthRangeProperty extends Property implements CompoundDatatype {
  31. private Property minimum;
  32. private Property optimum;
  33. private Property maximum;
  34. private static final int MINSET = 1;
  35. private static final int OPTSET = 2;
  36. private static final int MAXSET = 4;
  37. private int bfSet; // bit field
  38. private boolean consistent;
  39. /**
  40. * Converts this <code>LengthRangeProperty</code> to a <code>MinOptMax</code>.
  41. *
  42. * @param context Percentage evaluation context
  43. * @return the requested MinOptMax instance
  44. */
  45. public MinOptMax toMinOptMax(PercentBaseContext context) {
  46. int min = getMinimum(context).isAuto() ? 0
  47. : getMinimum(context).getLength().getValue(context);
  48. int opt = getOptimum(context).isAuto() ? min
  49. : getOptimum(context).getLength().getValue(context);
  50. int max = getMaximum(context).isAuto() ? Integer.MAX_VALUE
  51. : getMaximum(context).getLength().getValue(context);
  52. return MinOptMax.getInstance(min, opt, max);
  53. }
  54. /**
  55. * Inner class for a Maker for LengthProperty objects
  56. */
  57. public static class Maker extends CompoundPropertyMaker {
  58. /**
  59. * @param propId the id of the property for which a Maker should be created
  60. */
  61. public Maker(int propId) {
  62. super(propId);
  63. }
  64. /**
  65. * Create a new empty instance of LengthRangeProperty.
  66. * @return the new instance.
  67. */
  68. public Property makeNewProperty() {
  69. return new LengthRangeProperty();
  70. }
  71. private boolean isNegativeLength(Length len) {
  72. return ((len instanceof PercentLength
  73. && ((PercentLength) len).getPercentage() < 0)
  74. || (len.isAbsolute() && len.getValue() < 0));
  75. }
  76. /** {@inheritDoc} */
  77. public Property convertProperty(Property p,
  78. PropertyList propertyList, FObj fo)
  79. throws PropertyException {
  80. if (p instanceof LengthRangeProperty) {
  81. return p;
  82. }
  83. if (this.propId == PR_BLOCK_PROGRESSION_DIMENSION
  84. || this.propId == PR_INLINE_PROGRESSION_DIMENSION) {
  85. Length len = p.getLength();
  86. if (len != null) {
  87. if (isNegativeLength(len)) {
  88. log.warn(FObj.decorateWithContextInfo(
  89. "Replaced negative value (" + len + ") for " + getName()
  90. + " with 0mpt", fo));
  91. p = FixedLength.ZERO_FIXED_LENGTH;
  92. }
  93. }
  94. }
  95. return super.convertProperty(p, propertyList, fo);
  96. }
  97. /**
  98. * {@inheritDoc}
  99. */
  100. protected Property setSubprop(Property baseProperty, int subpropertyId,
  101. Property subproperty) {
  102. CompoundDatatype val = (CompoundDatatype) baseProperty.getObject();
  103. if (this.propId == PR_BLOCK_PROGRESSION_DIMENSION
  104. || this.propId == PR_INLINE_PROGRESSION_DIMENSION) {
  105. Length len = subproperty.getLength();
  106. if (len != null) {
  107. if (isNegativeLength(len)) {
  108. log.warn("Replaced negative value (" + len + ") for " + getName()
  109. + " with 0mpt");
  110. val.setComponent(subpropertyId,
  111. FixedLength.ZERO_FIXED_LENGTH, false);
  112. return baseProperty;
  113. }
  114. }
  115. }
  116. val.setComponent(subpropertyId, subproperty, false);
  117. return baseProperty;
  118. }
  119. }
  120. /**
  121. * {@inheritDoc}
  122. */
  123. public void setComponent(int cmpId, Property cmpnValue,
  124. boolean bIsDefault) {
  125. if (cmpId == CP_MINIMUM) {
  126. setMinimum(cmpnValue, bIsDefault);
  127. } else if (cmpId == CP_OPTIMUM) {
  128. setOptimum(cmpnValue, bIsDefault);
  129. } else if (cmpId == CP_MAXIMUM) {
  130. setMaximum(cmpnValue, bIsDefault);
  131. }
  132. }
  133. /**
  134. * {@inheritDoc}
  135. */
  136. public Property getComponent(int cmpId) {
  137. if (cmpId == CP_MINIMUM) {
  138. return getMinimum(null);
  139. } else if (cmpId == CP_OPTIMUM) {
  140. return getOptimum(null);
  141. } else if (cmpId == CP_MAXIMUM) {
  142. return getMaximum(null);
  143. } else {
  144. return null; // SHOULDN'T HAPPEN
  145. }
  146. }
  147. /**
  148. * Set minimum value to min.
  149. * @param minimum A Length value specifying the minimum value for this
  150. * LengthRange.
  151. * @param bIsDefault If true, this is set as a "default" value
  152. * and not a user-specified explicit value.
  153. */
  154. protected void setMinimum(Property minimum, boolean bIsDefault) {
  155. this.minimum = minimum;
  156. if (!bIsDefault) {
  157. bfSet |= MINSET;
  158. }
  159. consistent = false;
  160. }
  161. /**
  162. * Set maximum value to max if it is &gt;= optimum or optimum isn't set.
  163. * @param max A Length value specifying the maximum value for this
  164. * @param bIsDefault If true, this is set as a "default" value
  165. * and not a user-specified explicit value.
  166. */
  167. protected void setMaximum(Property max, boolean bIsDefault) {
  168. maximum = max;
  169. if (!bIsDefault) {
  170. bfSet |= MAXSET;
  171. }
  172. consistent = false;
  173. }
  174. /**
  175. * Set the optimum value.
  176. * @param opt A Length value specifying the optimum value for this
  177. * @param bIsDefault If true, this is set as a "default" value
  178. * and not a user-specified explicit value.
  179. */
  180. protected void setOptimum(Property opt, boolean bIsDefault) {
  181. optimum = opt;
  182. if (!bIsDefault) {
  183. bfSet |= OPTSET;
  184. }
  185. consistent = false;
  186. }
  187. // Minimum is prioritaire, if explicit
  188. private void checkConsistency(PercentBaseContext context) {
  189. if (consistent) {
  190. return;
  191. }
  192. if (context == null) {
  193. return;
  194. }
  195. // Make sure max >= min
  196. // Must also control if have any allowed enum values!
  197. if (!minimum.isAuto() && !maximum.isAuto()
  198. && minimum.getLength().getValue(context) > maximum.getLength().getValue(context)) {
  199. if ((bfSet & MINSET) != 0) {
  200. // if minimum is explicit, force max to min
  201. if ((bfSet & MAXSET) != 0) {
  202. // Warning: min>max, resetting max to min
  203. log.error("forcing max to min in LengthRange");
  204. }
  205. maximum = minimum;
  206. } else {
  207. minimum = maximum; // minimum was default value
  208. }
  209. }
  210. // Now make sure opt <= max and opt >= min
  211. if (!optimum.isAuto() && !maximum.isAuto()
  212. && optimum.getLength().getValue(context) > maximum.getLength().getValue(context)) {
  213. if ((bfSet & OPTSET) != 0) {
  214. if ((bfSet & MAXSET) != 0) {
  215. // Warning: opt > max, resetting opt to max
  216. log.error("forcing opt to max in LengthRange");
  217. optimum = maximum;
  218. } else {
  219. maximum = optimum; // maximum was default value
  220. }
  221. } else {
  222. // opt is default and max is explicit or default
  223. optimum = maximum;
  224. }
  225. } else if (!optimum.isAuto() && !minimum.isAuto()
  226. && optimum.getLength().getValue(context)
  227. < minimum.getLength().getValue(context)) {
  228. if ((bfSet & MINSET) != 0) {
  229. // if minimum is explicit, force opt to min
  230. if ((bfSet & OPTSET) != 0) {
  231. log.error("forcing opt to min in LengthRange");
  232. }
  233. optimum = minimum;
  234. } else {
  235. minimum = optimum; // minimum was default value
  236. }
  237. }
  238. consistent = true;
  239. }
  240. /**
  241. * @param context Percentage evaluation context
  242. * @return minimum length
  243. */
  244. public Property getMinimum(PercentBaseContext context) {
  245. checkConsistency(context);
  246. return this.minimum;
  247. }
  248. /**
  249. * @param context Percentage evaluation context
  250. * @return maximum length
  251. */
  252. public Property getMaximum(PercentBaseContext context) {
  253. checkConsistency(context);
  254. return this.maximum;
  255. }
  256. /**
  257. * @param context Percentage evaluation context
  258. * @return optimum length
  259. */
  260. public Property getOptimum(PercentBaseContext context) {
  261. checkConsistency(context);
  262. return this.optimum;
  263. }
  264. /** {@inheritDoc} */
  265. public String toString() {
  266. return "LengthRange["
  267. + "min:" + getMinimum(null).getObject()
  268. + ", max:" + getMaximum(null).getObject()
  269. + ", opt:" + getOptimum(null).getObject() + "]";
  270. }
  271. /**
  272. * @return this.lengthRange
  273. */
  274. public LengthRangeProperty getLengthRange() {
  275. return this;
  276. }
  277. /**
  278. * @return this.lengthRange cast as an Object
  279. */
  280. public Object getObject() {
  281. return this;
  282. }
  283. @Override
  284. public int hashCode() {
  285. final int prime = 31;
  286. int result = 1;
  287. result = prime * result + bfSet;
  288. result = prime * result + (consistent ? 1231 : 1237);
  289. result = prime * result + CompareUtil.getHashCode(minimum);
  290. result = prime * result + CompareUtil.getHashCode(optimum);
  291. result = prime * result + CompareUtil.getHashCode(maximum);
  292. return result;
  293. }
  294. @Override
  295. public boolean equals(Object obj) {
  296. if (this == obj) {
  297. return true;
  298. }
  299. if (!(obj instanceof LengthRangeProperty)) {
  300. return false;
  301. }
  302. LengthRangeProperty other = (LengthRangeProperty) obj;
  303. return bfSet == other.bfSet
  304. && consistent == other.consistent
  305. && CompareUtil.equal(minimum, other.minimum)
  306. && CompareUtil.equal(optimum, other.optimum)
  307. && CompareUtil.equal(maximum, other.maximum);
  308. }
  309. }