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.

CommonBorderPaddingBackground.java 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  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 java.awt.Color;
  20. import java.io.FileNotFoundException;
  21. import java.io.IOException;
  22. import java.util.Arrays;
  23. import org.apache.xmlgraphics.image.loader.ImageException;
  24. import org.apache.xmlgraphics.image.loader.ImageInfo;
  25. import org.apache.xmlgraphics.image.loader.ImageManager;
  26. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  27. import org.apache.fop.ResourceEventProducer;
  28. import org.apache.fop.apps.FOUserAgent;
  29. import org.apache.fop.datatypes.Length;
  30. import org.apache.fop.datatypes.PercentBaseContext;
  31. import org.apache.fop.datatypes.URISpecification;
  32. import org.apache.fop.fo.Constants;
  33. import org.apache.fop.fo.FObj;
  34. import org.apache.fop.fo.PropertyList;
  35. import org.apache.fop.fo.expr.PropertyException;
  36. /**
  37. * Stores all common border and padding properties.
  38. * See Sec. 7.7 of the XSL-FO Standard.
  39. */
  40. public class CommonBorderPaddingBackground {
  41. /**
  42. * cache holding all canonical instances
  43. * (w/ absolute background-position-* and padding-*)
  44. */
  45. private static final PropertyCache<CommonBorderPaddingBackground> CACHE
  46. = new PropertyCache<CommonBorderPaddingBackground>();
  47. private int hash = -1;
  48. /**
  49. * The "background-attachment" property.
  50. */
  51. public final int backgroundAttachment;
  52. /**
  53. * The "background-color" property.
  54. */
  55. public final Color backgroundColor;
  56. /**
  57. * The "background-image" property.
  58. */
  59. public final String backgroundImage;
  60. /**
  61. * The "background-repeat" property.
  62. */
  63. public final int backgroundRepeat;
  64. /**
  65. * The "background-position-horizontal" property.
  66. */
  67. public final Length backgroundPositionHorizontal;
  68. /**
  69. * The "background-position-vertical" property.
  70. */
  71. public final Length backgroundPositionVertical;
  72. public final Length backgroungImageTargetWidth;
  73. public final Length backgroungImageTargetHeight;
  74. private ImageInfo backgroundImageInfo;
  75. /** the "before" edge */
  76. public static final int BEFORE = 0;
  77. /** the "after" edge */
  78. public static final int AFTER = 1;
  79. /** the "start" edge */
  80. public static final int START = 2;
  81. /** the "end" edge */
  82. public static final int END = 3;
  83. /**
  84. * Utility class to express border info.
  85. */
  86. public static final class BorderInfo {
  87. /** cache holding all canonical instances */
  88. private static final PropertyCache<BorderInfo> CACHE
  89. = new PropertyCache<BorderInfo>();
  90. private int mStyle; // Enum for border style
  91. private Color mColor; // Border color
  92. private CondLengthProperty mWidth;
  93. private CondLengthProperty radiusStart;
  94. private CondLengthProperty radiusEnd;
  95. private int hash = -1;
  96. /**
  97. * Hidden constructor
  98. */
  99. private BorderInfo(int style, CondLengthProperty width, Color color,
  100. CondLengthProperty radiusStart, CondLengthProperty radiusEnd) {
  101. mStyle = style;
  102. mWidth = width;
  103. mColor = color;
  104. this.radiusStart = radiusStart;
  105. this.radiusEnd = radiusEnd;
  106. }
  107. /**
  108. * Returns a BorderInfo instance corresponding to the given values.
  109. *
  110. * @param style the border-style
  111. * @param width the border-width
  112. * @param color the border-color
  113. * @param radiusStart the start radius for rounded borders
  114. * @param radiusEnd the end radius for rounded borders
  115. * @return a cached BorderInfo instance
  116. */
  117. public static BorderInfo getInstance(int style, CondLengthProperty width, Color color,
  118. CondLengthProperty radiusStart, CondLengthProperty radiusEnd) {
  119. return CACHE.fetch(new BorderInfo(style, width, color, radiusStart, radiusEnd));
  120. }
  121. /**
  122. * @return the border-style
  123. */
  124. public int getStyle() {
  125. return this.mStyle;
  126. }
  127. /**
  128. * @return the border-color
  129. */
  130. public Color getColor() {
  131. return this.mColor;
  132. }
  133. /**
  134. * @return the border-width
  135. */
  136. public CondLengthProperty getWidth() {
  137. return this.mWidth;
  138. }
  139. /**
  140. * Convenience method returning the border-width,
  141. * taking into account values of "none" and "hidden"
  142. *
  143. * @return the retained border-width
  144. */
  145. public int getRetainedWidth() {
  146. if ((mStyle == Constants.EN_NONE)
  147. || (mStyle == Constants.EN_HIDDEN)) {
  148. return 0;
  149. } else {
  150. return mWidth.getLengthValue();
  151. }
  152. }
  153. /**
  154. * @return the border-*-start-radius
  155. */
  156. public CondLengthProperty getRadiusStart() {
  157. return this.radiusStart;
  158. }
  159. /**
  160. * @return the border-*-end-radius
  161. */
  162. public CondLengthProperty getRadiusEnd() {
  163. return this.radiusEnd;
  164. }
  165. @Override
  166. public String toString() {
  167. StringBuffer sb = new StringBuffer("BorderInfo");
  168. sb.append(" {");
  169. sb.append(mStyle);
  170. sb.append(", ");
  171. sb.append(mColor);
  172. sb.append(", ");
  173. sb.append(mWidth);
  174. sb.append(", ");
  175. sb.append(radiusStart);
  176. sb.append(", ");
  177. sb.append(radiusEnd);
  178. sb.append("}");
  179. return sb.toString();
  180. }
  181. @Override
  182. public boolean equals(Object obj) {
  183. if (this == obj) {
  184. return true;
  185. }
  186. if (!(obj instanceof BorderInfo)) {
  187. return false;
  188. }
  189. BorderInfo bi = (BorderInfo)obj;
  190. return (this.mColor == bi.mColor
  191. && this.mStyle == bi.mStyle
  192. && this.mWidth == bi.mWidth
  193. && this.radiusStart == bi.radiusStart
  194. && this.radiusEnd == bi.radiusEnd);
  195. }
  196. @Override
  197. public int hashCode() {
  198. if (this.hash == -1) {
  199. int hash = 17;
  200. hash = 37 * hash + (mColor == null ? 0 : mColor.hashCode());
  201. hash = 37 * hash + mStyle;
  202. hash = 37 * hash + (mWidth == null ? 0 : mWidth.hashCode());
  203. hash = 37 * hash + (radiusStart == null ? 0 : radiusStart.hashCode());
  204. hash = 37 * hash + (radiusEnd == null ? 0 : radiusEnd.hashCode());
  205. this.hash = hash;
  206. }
  207. return this.hash;
  208. }
  209. }
  210. /**
  211. * A border info with style "none". Used as a singleton, in the collapsing-border model,
  212. * for elements which don't specify any border on some of their sides.
  213. */
  214. private static final BorderInfo DEFAULT_BORDER_INFO = BorderInfo.getInstance(
  215. Constants.EN_NONE, new ConditionalNullLength(), null, new ConditionalNullLength(),
  216. new ConditionalNullLength());
  217. /**
  218. * A conditional length of value 0. Returned by the
  219. * {@link CommonBorderPaddingBackground#getBorderInfo(int)} method when the
  220. * corresponding border isn't specified, to avoid to callers painful checks for null.
  221. */
  222. private static class ConditionalNullLength extends CondLengthProperty {
  223. @Override
  224. public Property getComponent(int cmpId) {
  225. throw new UnsupportedOperationException();
  226. }
  227. @Override
  228. public Property getConditionality() {
  229. throw new UnsupportedOperationException();
  230. }
  231. @Override
  232. public Length getLength() {
  233. throw new UnsupportedOperationException();
  234. }
  235. @Override
  236. public Property getLengthComponent() {
  237. throw new UnsupportedOperationException();
  238. }
  239. @Override
  240. public int getLengthValue() {
  241. return 0;
  242. }
  243. @Override
  244. public int getLengthValue(PercentBaseContext context) {
  245. return 0;
  246. }
  247. @Override
  248. public boolean isDiscard() {
  249. return true;
  250. }
  251. @Override
  252. public void setComponent(int cmpId, Property cmpnValue, boolean isDefault) {
  253. throw new UnsupportedOperationException();
  254. }
  255. @Override
  256. public String toString() {
  257. return "CondLength[0mpt, discard]";
  258. }
  259. }
  260. /**
  261. * Returns a default BorderInfo of style none.
  262. *
  263. * @return a BorderInfo instance with style set to {@link Constants#EN_NONE}
  264. */
  265. public static BorderInfo getDefaultBorderInfo() {
  266. return DEFAULT_BORDER_INFO;
  267. }
  268. private BorderInfo[] borderInfo = new BorderInfo[4];
  269. private CondLengthProperty[] padding = new CondLengthProperty[4];
  270. /**
  271. * Construct a CommonBorderPaddingBackground object.
  272. *
  273. * @param pList The PropertyList to get properties from.
  274. * @throws PropertyException if there's an error while binding the properties
  275. */
  276. CommonBorderPaddingBackground(PropertyList pList) throws PropertyException {
  277. backgroundAttachment = pList.get(Constants.PR_BACKGROUND_ATTACHMENT).getEnum();
  278. Color bc = pList.get(Constants.PR_BACKGROUND_COLOR).getColor(
  279. pList.getFObj().getUserAgent());
  280. if (bc.getAlpha() == 0) {
  281. backgroundColor = null;
  282. } else {
  283. backgroundColor = bc;
  284. }
  285. String img = pList.get(Constants.PR_BACKGROUND_IMAGE).getString();
  286. if (img == null || "none".equals(img)) {
  287. backgroundImage = "";
  288. backgroundRepeat = -1;
  289. backgroundPositionHorizontal = null;
  290. backgroundPositionVertical = null;
  291. } else {
  292. backgroundImage = img;
  293. backgroundRepeat = pList.get(Constants.PR_BACKGROUND_REPEAT).getEnum();
  294. backgroundPositionHorizontal = pList.get(
  295. Constants.PR_BACKGROUND_POSITION_HORIZONTAL).getLength();
  296. backgroundPositionVertical = pList.get(
  297. Constants.PR_BACKGROUND_POSITION_VERTICAL).getLength();
  298. }
  299. backgroungImageTargetWidth = pList.get(Constants.PR_X_BACKGROUND_IMAGE_WIDTH).getLength();
  300. backgroungImageTargetHeight = pList.get(Constants.PR_X_BACKGROUND_IMAGE_HEIGHT).getLength();
  301. initBorderInfo(pList, BEFORE,
  302. Constants.PR_BORDER_BEFORE_COLOR,
  303. Constants.PR_BORDER_BEFORE_STYLE,
  304. Constants.PR_BORDER_BEFORE_WIDTH,
  305. Constants.PR_PADDING_BEFORE,
  306. Constants.PR_X_BORDER_BEFORE_RADIUS_START,
  307. Constants.PR_X_BORDER_BEFORE_RADIUS_END);
  308. initBorderInfo(pList, AFTER,
  309. Constants.PR_BORDER_AFTER_COLOR,
  310. Constants.PR_BORDER_AFTER_STYLE,
  311. Constants.PR_BORDER_AFTER_WIDTH,
  312. Constants.PR_PADDING_AFTER,
  313. Constants.PR_X_BORDER_AFTER_RADIUS_START,
  314. Constants.PR_X_BORDER_AFTER_RADIUS_END);
  315. initBorderInfo(pList, START,
  316. Constants.PR_BORDER_START_COLOR,
  317. Constants.PR_BORDER_START_STYLE,
  318. Constants.PR_BORDER_START_WIDTH,
  319. Constants.PR_PADDING_START,
  320. Constants.PR_X_BORDER_START_RADIUS_BEFORE,
  321. Constants.PR_X_BORDER_START_RADIUS_AFTER);
  322. initBorderInfo(pList, END,
  323. Constants.PR_BORDER_END_COLOR,
  324. Constants.PR_BORDER_END_STYLE,
  325. Constants.PR_BORDER_END_WIDTH,
  326. Constants.PR_PADDING_END,
  327. Constants.PR_X_BORDER_END_RADIUS_BEFORE,
  328. Constants.PR_X_BORDER_END_RADIUS_AFTER);
  329. }
  330. /**
  331. * Obtain a CommonBorderPaddingBackground instance based on the
  332. * related property valus in the given {@link PropertyList}
  333. *
  334. * @param pList the {@link PropertyList} to use
  335. * @return a CommonBorderPaddingBackground instance (cached if possible)
  336. * @throws PropertyException in case of an error
  337. */
  338. public static CommonBorderPaddingBackground getInstance(PropertyList pList) throws PropertyException {
  339. CommonBorderPaddingBackground newInstance = new CommonBorderPaddingBackground(pList);
  340. CommonBorderPaddingBackground cachedInstance = null;
  341. /* if padding-* and background-position-* resolve to absolute lengths
  342. * the whole instance can be cached */
  343. if ((newInstance.padding[BEFORE] == null || newInstance.padding[BEFORE].getLength().isAbsolute())
  344. && (newInstance.padding[AFTER] == null || newInstance.padding[AFTER].getLength().isAbsolute())
  345. && (newInstance.padding[START] == null || newInstance.padding[START].getLength().isAbsolute())
  346. && (newInstance.padding[END] == null || newInstance.padding[END].getLength().isAbsolute())
  347. && (newInstance.backgroundPositionHorizontal == null || newInstance.backgroundPositionHorizontal
  348. .isAbsolute())
  349. && (newInstance.backgroundPositionVertical == null || newInstance.backgroundPositionVertical
  350. .isAbsolute())
  351. && (newInstance.backgroungImageTargetHeight == null || newInstance.backgroungImageTargetHeight
  352. .isAbsolute())
  353. && (newInstance.backgroungImageTargetWidth == null || newInstance.backgroungImageTargetWidth
  354. .isAbsolute())) {
  355. cachedInstance = CACHE.fetch(newInstance);
  356. }
  357. synchronized (newInstance.backgroundImage.intern()) {
  358. /* for non-cached, or not-yet-cached instances, preload the image */
  359. if ((cachedInstance == null || cachedInstance == newInstance)
  360. && !("".equals(newInstance.backgroundImage))) {
  361. //Additional processing: preload image
  362. String uri = URISpecification.getURL(newInstance.backgroundImage);
  363. FObj fobj = pList.getFObj();
  364. FOUserAgent userAgent = pList.getFObj().getUserAgent();
  365. ImageManager manager = userAgent.getImageManager();
  366. ImageSessionContext sessionContext = userAgent.getImageSessionContext();
  367. ImageInfo info;
  368. try {
  369. info = manager.getImageInfo(uri, sessionContext);
  370. newInstance.backgroundImageInfo = info;
  371. } catch (ImageException e) {
  372. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  373. fobj.getUserAgent().getEventBroadcaster());
  374. eventProducer.imageError(fobj, uri, e, fobj.getLocator());
  375. } catch (FileNotFoundException fnfe) {
  376. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  377. fobj.getUserAgent().getEventBroadcaster());
  378. eventProducer.imageNotFound(fobj, uri, fnfe, fobj.getLocator());
  379. } catch (IOException ioe) {
  380. ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
  381. fobj.getUserAgent().getEventBroadcaster());
  382. eventProducer.imageIOError(fobj, uri, ioe, fobj.getLocator());
  383. }
  384. }
  385. }
  386. return (cachedInstance != null ? cachedInstance : newInstance);
  387. }
  388. private void initBorderInfo(PropertyList pList, int side,
  389. int colorProp, int styleProp, int widthProp, int paddingProp,
  390. int radiusStartProp, int radiusEndProp)
  391. throws PropertyException {
  392. padding[side] = pList.get(paddingProp).getCondLength();
  393. // If style = none, force width to 0, don't get Color (spec 7.7.20)
  394. int style = pList.get(styleProp).getEnum();
  395. FOUserAgent ua = pList.getFObj().getUserAgent();
  396. setBorderInfo(BorderInfo.getInstance(style,
  397. pList.get(widthProp).getCondLength(),
  398. pList.get(colorProp).getColor(ua),
  399. pList.get(radiusStartProp).getCondLength(),
  400. pList.get(radiusEndProp).getCondLength()), side);
  401. }
  402. /**
  403. * Sets a border.
  404. * @param info the border information
  405. * @param side the side to apply the info to
  406. */
  407. private void setBorderInfo(BorderInfo info, int side) {
  408. this.borderInfo[side] = info;
  409. }
  410. /**
  411. * @param side the side to retrieve
  412. * @return the border info for a side
  413. */
  414. public BorderInfo getBorderInfo(int side) {
  415. if (this.borderInfo[side] == null) {
  416. return getDefaultBorderInfo();
  417. } else {
  418. return this.borderInfo[side];
  419. }
  420. }
  421. /**
  422. * @return the background image info object, null if there is
  423. * no background image.
  424. */
  425. public ImageInfo getImageInfo() {
  426. return this.backgroundImageInfo;
  427. }
  428. /**
  429. * @param discard indicates whether the .conditionality component should be
  430. * considered (start of a reference-area)
  431. * @return the width of the start-border, taking into account the specified conditionality
  432. */
  433. public int getBorderStartWidth(boolean discard) {
  434. return getBorderWidth(START, discard);
  435. }
  436. /**
  437. * @param discard indicates whether the .conditionality component should be
  438. * considered (end of a reference-area)
  439. * @return the width of the end-border, taking into account the specified conditionality
  440. */
  441. public int getBorderEndWidth(boolean discard) {
  442. return getBorderWidth(END, discard);
  443. }
  444. /**
  445. * @param discard indicates whether the .conditionality component should be
  446. * considered (start of a reference-area)
  447. * @return the width of the before-border, taking into account the specified conditionality
  448. */
  449. public int getBorderBeforeWidth(boolean discard) {
  450. return getBorderWidth(BEFORE, discard);
  451. }
  452. /**
  453. * @param discard indicates whether the .conditionality component should be
  454. * considered (end of a reference-area)
  455. * @return the width of the after-border, taking into account the specified conditionality
  456. */
  457. public int getBorderAfterWidth(boolean discard) {
  458. return getBorderWidth(AFTER, discard);
  459. }
  460. /**
  461. * @param discard indicates whether the .conditionality component should be
  462. * considered (start of a reference-area)
  463. * @param context the context to evaluate percentage values
  464. * @return the width of the start-padding, taking into account the specified conditionality
  465. */
  466. public int getPaddingStart(boolean discard, PercentBaseContext context) {
  467. return getPadding(START, discard, context);
  468. }
  469. /**
  470. * @param discard indicates whether the .conditionality component should be
  471. * considered (start of a reference-area)
  472. * @param context the context to evaluate percentage values
  473. * @return the width of the end-padding, taking into account the specified conditionality
  474. */
  475. public int getPaddingEnd(boolean discard, PercentBaseContext context) {
  476. return getPadding(END, discard, context);
  477. }
  478. /**
  479. * @param discard indicates whether the .conditionality component should be
  480. * considered (start of a reference-area)
  481. * @param context the context to evaluate percentage values
  482. * @return the width of the before-padding, taking into account the specified conditionality
  483. */
  484. public int getPaddingBefore(boolean discard, PercentBaseContext context) {
  485. return getPadding(BEFORE, discard, context);
  486. }
  487. /**
  488. * @param discard indicates whether the .conditionality component should be
  489. * considered (start of a reference-area)
  490. * @param context the context to evaluate percentage values
  491. * @return the width of the after-padding, taking into account the specified conditionality
  492. */
  493. public int getPaddingAfter(boolean discard, PercentBaseContext context) {
  494. return getPadding(AFTER, discard, context);
  495. }
  496. /**
  497. * @param side the side of the border
  498. * @param discard indicates whether the .conditionality component should be considered (end of a
  499. * reference-area)
  500. * @return the width of the start-border, taking into account the specified conditionality
  501. */
  502. public int getBorderWidth(int side, boolean discard) {
  503. if ((borderInfo[side] == null)
  504. || (borderInfo[side].mStyle == Constants.EN_NONE)
  505. || (borderInfo[side].mStyle == Constants.EN_HIDDEN)
  506. || (discard && borderInfo[side].mWidth.isDiscard())) {
  507. return 0;
  508. } else {
  509. return borderInfo[side].mWidth.getLengthValue();
  510. }
  511. }
  512. /**
  513. * Returns the border corner radius of the starting edge
  514. * i.e. the edge either adjacent to the before or start border.
  515. * @param side the border side
  516. * @param discard indicates whether the .conditionality component should be
  517. * considered (end of a reference-area)
  518. * @param context the context for percentage calculations
  519. * @return the border radius of the of the starting corner
  520. */
  521. public int getBorderRadiusStart(int side, boolean discard, PercentBaseContext context) {
  522. if (borderInfo[side] == null) {
  523. return 0;
  524. } else {
  525. return borderInfo[side].radiusStart.getLengthValue(context);
  526. }
  527. }
  528. /**
  529. * Returns the border corner radius of the ending edge
  530. * i.e. the edge either adjacent to the after or end border
  531. * @param side the border side
  532. * @param discard indicates whether the .conditionality component should be
  533. * considered (end of a reference-area)
  534. * @param context the context for percentage calculations
  535. * @return the border radius of the of the ending corner
  536. */
  537. public int getBorderRadiusEnd(int side, boolean discard, PercentBaseContext context) {
  538. if (borderInfo[side] == null) {
  539. return 0;
  540. } else {
  541. return borderInfo[side].radiusEnd.getLengthValue(context);
  542. }
  543. }
  544. /**
  545. * The border-color for the given side
  546. *
  547. * @param side one of {@link #BEFORE}, {@link #AFTER}, {@link #START}, {@link #END}
  548. * @return the border-color for the given side
  549. */
  550. public Color getBorderColor(int side) {
  551. if (borderInfo[side] != null) {
  552. return borderInfo[side].getColor();
  553. } else {
  554. return null;
  555. }
  556. }
  557. /**
  558. * The border-style for the given side
  559. *
  560. * @param side one of {@link #BEFORE}, {@link #AFTER}, {@link #START}, {@link #END}
  561. * @return the border-style for the given side
  562. */
  563. public int getBorderStyle(int side) {
  564. if (borderInfo[side] != null) {
  565. return borderInfo[side].mStyle;
  566. } else {
  567. return Constants.EN_NONE;
  568. }
  569. }
  570. /**
  571. * Return the padding for the given side, taking into account
  572. * the conditionality and evaluating any percentages in the given
  573. * context.
  574. *
  575. * @param side one of {@link #BEFORE}, {@link #AFTER}, {@link #START}, {@link #END}
  576. * @param discard true if the conditionality component should be considered
  577. * @param context the context for percentage-resolution
  578. * @return the computed padding for the given side
  579. */
  580. public int getPadding(int side, boolean discard, PercentBaseContext context) {
  581. if ((padding[side] == null) || (discard && padding[side].isDiscard())) {
  582. return 0;
  583. } else {
  584. return padding[side].getLengthValue(context);
  585. }
  586. }
  587. /**
  588. * Returns the CondLengthProperty for the padding on one side.
  589. * @param side the side
  590. * @return the requested CondLengthProperty
  591. */
  592. public CondLengthProperty getPaddingLengthProperty(int side) {
  593. return padding[side];
  594. }
  595. /**
  596. * Return all the border and padding width in the inline progression
  597. * dimension.
  598. * @param discard the discard flag.
  599. * @param context for percentage evaluation.
  600. * @return all the padding and border width.
  601. */
  602. public int getIPPaddingAndBorder(boolean discard, PercentBaseContext context) {
  603. return getPaddingStart(discard, context)
  604. + getPaddingEnd(discard, context)
  605. + getBorderStartWidth(discard)
  606. + getBorderEndWidth(discard);
  607. }
  608. /**
  609. * Return all the border and padding height in the block progression
  610. * dimension.
  611. * @param discard the discard flag.
  612. * @param context for percentage evaluation
  613. * @return all the padding and border height.
  614. */
  615. public int getBPPaddingAndBorder(boolean discard, PercentBaseContext context) {
  616. return getPaddingBefore(discard, context) + getPaddingAfter(discard, context)
  617. + getBorderBeforeWidth(discard) + getBorderAfterWidth(discard);
  618. }
  619. @Override
  620. public String toString() {
  621. return "CommonBordersAndPadding (Before, After, Start, End):\n"
  622. + "Borders: (" + getBorderBeforeWidth(false) + ", " + getBorderAfterWidth(false) + ", "
  623. + getBorderStartWidth(false) + ", " + getBorderEndWidth(false) + ")\n"
  624. + "Border Colors: (" + getBorderColor(BEFORE) + ", " + getBorderColor(AFTER) + ", "
  625. + getBorderColor(START) + ", " + getBorderColor(END) + ")\n"
  626. + "Padding: (" + getPaddingBefore(false, null) + ", " + getPaddingAfter(false, null)
  627. + ", " + getPaddingStart(false, null) + ", " + getPaddingEnd(false, null) + ")\n";
  628. }
  629. /**
  630. * @return true if there is any kind of background to be painted
  631. */
  632. public boolean hasBackground() {
  633. return ((backgroundColor != null || getImageInfo() != null));
  634. }
  635. /** @return true if border is non-zero. */
  636. public boolean hasBorder() {
  637. return ((getBorderBeforeWidth(false) + getBorderAfterWidth(false)
  638. + getBorderStartWidth(false) + getBorderEndWidth(false)) > 0);
  639. }
  640. /**
  641. * @param context for percentage based evaluation.
  642. * @return true if padding is non-zero.
  643. */
  644. public boolean hasPadding(PercentBaseContext context) {
  645. return ((getPaddingBefore(false, context) + getPaddingAfter(false, context)
  646. + getPaddingStart(false, context) + getPaddingEnd(false, context)) > 0);
  647. }
  648. /** @return true if there are any borders defined. */
  649. public boolean hasBorderInfo() {
  650. return (borderInfo[BEFORE] != null || borderInfo[AFTER] != null
  651. || borderInfo[START] != null || borderInfo[END] != null);
  652. }
  653. /**
  654. * Returns the "background-color" property.
  655. * @return the "background-color" property.
  656. */
  657. public Color getBackgroundColor() {
  658. return backgroundColor;
  659. }
  660. /**
  661. * Returns the "background-attachment" property.
  662. * @return the "background-attachment" property.
  663. */
  664. public int getBackgroundAttachment() {
  665. return backgroundAttachment;
  666. }
  667. /**
  668. * Returns the "background-image" property.
  669. * @return the "background-image" property.
  670. */
  671. public String getBackgroundImage() {
  672. return backgroundImage;
  673. }
  674. /**
  675. * Returns the "background-repeat" property.
  676. * @return the "background-repeat" property.
  677. */
  678. public int getBackgroundRepeat() {
  679. return backgroundRepeat;
  680. }
  681. /**
  682. * Returns the "background-position-horizontal" property.
  683. * @return the "background-position-horizontal" property.
  684. */
  685. public Length getBackgroundPositionHorizontal() {
  686. return backgroundPositionHorizontal;
  687. }
  688. /**
  689. * Returns the "background-position-vertical" property.
  690. * @return the "background-position-vertical" property.
  691. */
  692. public Length getBackgroundPositionVertical() {
  693. return backgroundPositionVertical;
  694. }
  695. /**
  696. * Returns the background image info
  697. * @return the background image info
  698. */
  699. public ImageInfo getBackgroundImageInfo() {
  700. return backgroundImageInfo;
  701. }
  702. /**
  703. * Returns the border info
  704. * @return the border info
  705. */
  706. public BorderInfo[] getBorderInfo() {
  707. return borderInfo;
  708. }
  709. /**
  710. * Returns the padding
  711. * @return the padding
  712. */
  713. public CondLengthProperty[] getPadding() {
  714. return padding;
  715. }
  716. @Override
  717. public boolean equals(Object obj) {
  718. if (this == obj) {
  719. return true;
  720. }
  721. if (obj instanceof CommonBorderPaddingBackground) {
  722. CommonBorderPaddingBackground cbpb = (CommonBorderPaddingBackground)obj;
  723. return (this.backgroundAttachment == cbpb.backgroundAttachment
  724. && this.backgroundColor == cbpb.backgroundColor
  725. && this.backgroundImage.equals(cbpb.backgroundImage)
  726. && this.backgroundPositionHorizontal == cbpb.backgroundPositionHorizontal
  727. && this.backgroundPositionVertical == cbpb.backgroundPositionVertical
  728. && this.backgroundRepeat == cbpb.backgroundRepeat
  729. && Arrays.equals(borderInfo, cbpb.borderInfo)
  730. && Arrays.equals(padding, cbpb.padding));
  731. } else {
  732. return false;
  733. }
  734. }
  735. @Override
  736. public int hashCode() {
  737. if (this.hash == -1) {
  738. int hash = getHashCode(backgroundColor,
  739. backgroundImage,
  740. backgroundPositionHorizontal,
  741. backgroundPositionVertical,
  742. backgroungImageTargetWidth,
  743. backgroungImageTargetHeight,
  744. borderInfo[BEFORE],
  745. borderInfo[AFTER],
  746. borderInfo[START],
  747. borderInfo[END],
  748. padding[BEFORE],
  749. padding[AFTER],
  750. padding[START],
  751. padding[END]);
  752. hash = 37 * hash + backgroundAttachment;
  753. hash = 37 * hash + backgroundRepeat;
  754. this.hash = hash;
  755. }
  756. return this.hash;
  757. }
  758. private int getHashCode(Object... objects) {
  759. int hash = 17;
  760. for (Object o : objects) {
  761. hash = 37 * hash + (o == null ? 0 : o.hashCode());
  762. }
  763. return hash;
  764. }
  765. }