/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.fo.properties; import java.awt.Color; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.PercentBaseContext; import org.apache.fop.fo.Constants; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.image.FopImage; import org.apache.fop.image.ImageFactory; /** * Stores all common border and padding properties. * See Sec. 7.7 of the XSL-FO Standard. */ public class CommonBorderPaddingBackground { /** * The "background-attachment" property. */ public int backgroundAttachment; /** * The "background-color" property. */ public Color backgroundColor; /** * The "background-image" property. */ public String backgroundImage; /** * The "background-repeat" property. */ public int backgroundRepeat; /** * The "background-position-horizontal" property. */ public Length backgroundPositionHorizontal; /** * The "background-position-vertical" property. */ public Length backgroundPositionVertical; private FopImage fopimage; /** the "before" edge */ public static final int BEFORE = 0; /** the "after" edge */ public static final int AFTER = 1; /** the "start" edge */ public static final int START = 2; /** the "end" edge */ public static final int END = 3; public static class BorderInfo { private int mStyle; // Enum for border style private Color mColor; // Border color private CondLengthProperty mWidth; BorderInfo(int style, CondLengthProperty width, Color color) { mStyle = style; mWidth = width; mColor = color; } public int getStyle() { return this.mStyle; } public Color getColor() { return this.mColor; } public CondLengthProperty getWidth() { return this.mWidth; } public int getRetainedWidth() { if ((mStyle == Constants.EN_NONE) || (mStyle == Constants.EN_HIDDEN)) { return 0; } else { return mWidth.getLengthValue(); } } /** {@inheritDoc} */ public String toString() { StringBuffer sb = new StringBuffer("BorderInfo"); sb.append(" {"); sb.append(mStyle); sb.append(", "); sb.append(mColor); sb.append(", "); sb.append(mWidth); sb.append("}"); return sb.toString(); } } /** * A border info with style none. Used as a singleton, in the collapsing-border model, * for elements which don't specify any border on some of their sides. */ private static BorderInfo defaultBorderInfo; /** * Returns a default BorderInfo of style none. * * @return a BorderInfo instance with style set to {@link Constants#EN_NONE} */ public static synchronized BorderInfo getDefaultBorderInfo() { if (defaultBorderInfo == null) { /* It is enough to set color and width to null, as they should never be consulted */ defaultBorderInfo = new BorderInfo(Constants.EN_NONE, null, null); } return defaultBorderInfo; } private BorderInfo[] borderInfo = new BorderInfo[4]; private CondLengthProperty[] padding = new CondLengthProperty[4]; /** * Construct a CommonBorderPaddingBackground object. */ public CommonBorderPaddingBackground() { } /** * Construct a CommonBorderPaddingBackground object. * * @param pList The PropertyList to get properties from. * @throws PropertyException if there's an error while binding the properties */ public CommonBorderPaddingBackground(PropertyList pList) throws PropertyException { backgroundAttachment = pList.get(Constants.PR_BACKGROUND_ATTACHMENT).getEnum(); backgroundColor = pList.get(Constants.PR_BACKGROUND_COLOR).getColor( pList.getFObj().getUserAgent()); if (backgroundColor.getAlpha() == 0) { backgroundColor = null; } backgroundImage = pList.get(Constants.PR_BACKGROUND_IMAGE).getString(); if (backgroundImage == null || "none".equals(backgroundImage)) { backgroundImage = null; } else { backgroundRepeat = pList.get(Constants.PR_BACKGROUND_REPEAT).getEnum(); backgroundPositionHorizontal = pList.get( Constants.PR_BACKGROUND_POSITION_HORIZONTAL).getLength(); backgroundPositionVertical = pList.get( Constants.PR_BACKGROUND_POSITION_VERTICAL).getLength(); //Additional processing: preload image String url = ImageFactory.getURL(backgroundImage); FOUserAgent userAgent = pList.getFObj().getUserAgent(); ImageFactory fact = userAgent.getFactory().getImageFactory(); fopimage = fact.getImage(url, userAgent); if (fopimage == null) { Property.log.error("Background image not available: " + backgroundImage); } else { // load dimensions if (!fopimage.load(FopImage.DIMENSIONS)) { Property.log.error("Cannot read background image dimensions: " + backgroundImage); } } //TODO Report to caller so he can decide to throw an exception } initBorderInfo(pList, BEFORE, Constants.PR_BORDER_BEFORE_COLOR, Constants.PR_BORDER_BEFORE_STYLE, Constants.PR_BORDER_BEFORE_WIDTH, Constants.PR_PADDING_BEFORE); initBorderInfo(pList, AFTER, Constants.PR_BORDER_AFTER_COLOR, Constants.PR_BORDER_AFTER_STYLE, Constants.PR_BORDER_AFTER_WIDTH, Constants.PR_PADDING_AFTER); initBorderInfo(pList, START, Constants.PR_BORDER_START_COLOR, Constants.PR_BORDER_START_STYLE, Constants.PR_BORDER_START_WIDTH, Constants.PR_PADDING_START); initBorderInfo(pList, END, Constants.PR_BORDER_END_COLOR, Constants.PR_BORDER_END_STYLE, Constants.PR_BORDER_END_WIDTH, Constants.PR_PADDING_END); } private void initBorderInfo(PropertyList pList, int side, int colorProp, int styleProp, int widthProp, int paddingProp) throws PropertyException { padding[side] = pList.get(paddingProp).getCondLength(); // If style = none, force width to 0, don't get Color (spec 7.7.20) int style = pList.get(styleProp).getEnum(); if (style != Constants.EN_NONE) { FOUserAgent ua = pList.getFObj().getUserAgent(); setBorderInfo(new BorderInfo(style, pList.get(widthProp).getCondLength(), pList.get(colorProp).getColor(ua)), side); } } /** * Sets a border. * @param info the border information * @param side the side to apply the info to */ public void setBorderInfo(BorderInfo info, int side) { this.borderInfo[side] = info; } /** * @param side the side to retrieve * @return the border info for a side */ public BorderInfo getBorderInfo(int side) { if (this.borderInfo[side] == null) { return getDefaultBorderInfo(); } else { return this.borderInfo[side]; } } /** * Set padding. * @param source the padding info to copy from */ public void setPadding(CommonBorderPaddingBackground source) { this.padding = source.padding; } /** * @return the background image as a preloaded FopImage, null if there is * no background image. */ public FopImage getFopImage() { return this.fopimage; } /** * @param bDiscard indicates whether the .conditionality component should be * considered (start of a reference-area) */ public int getBorderStartWidth(boolean bDiscard) { return getBorderWidth(START, bDiscard); } /** * @param bDiscard indicates whether the .conditionality component should be * considered (end of a reference-area) */ public int getBorderEndWidth(boolean bDiscard) { return getBorderWidth(END, bDiscard); } /** * @param bDiscard indicates whether the .conditionality component should be * considered (start of a reference-area) */ public int getBorderBeforeWidth(boolean bDiscard) { return getBorderWidth(BEFORE, bDiscard); } /** * @param bDiscard indicates whether the .conditionality component should be * considered (end of a reference-area) */ public int getBorderAfterWidth(boolean bDiscard) { return getBorderWidth(AFTER, bDiscard); } public int getPaddingStart(boolean bDiscard, PercentBaseContext context) { return getPadding(START, bDiscard, context); } public int getPaddingEnd(boolean bDiscard, PercentBaseContext context) { return getPadding(END, bDiscard, context); } public int getPaddingBefore(boolean bDiscard, PercentBaseContext context) { return getPadding(BEFORE, bDiscard, context); } public int getPaddingAfter(boolean bDiscard, PercentBaseContext context) { return getPadding(AFTER, bDiscard, context); } public int getBorderWidth(int side, boolean bDiscard) { if ((borderInfo[side] == null) || (borderInfo[side].mStyle == Constants.EN_NONE) || (borderInfo[side].mStyle == Constants.EN_HIDDEN) || (bDiscard && borderInfo[side].mWidth.isDiscard())) { return 0; } else { return borderInfo[side].mWidth.getLengthValue(); } } public Color getBorderColor(int side) { if (borderInfo[side] != null) { return borderInfo[side].getColor(); } else { return null; } } public int getBorderStyle(int side) { if (borderInfo[side] != null) { return borderInfo[side].mStyle; } else { return Constants.EN_NONE; } } public int getPadding(int side, boolean bDiscard, PercentBaseContext context) { if ((padding[side] == null) || (bDiscard && padding[side].isDiscard())) { return 0; } else { return padding[side].getLengthValue(context); } } /** * Returns the CondLengthProperty for the padding on one side. * @param side the side * @return the requested CondLengthProperty */ public CondLengthProperty getPaddingLengthProperty(int side) { return padding[side]; } /** * Return all the border and padding width in the inline progression * dimension. * @param bDiscard the discard flag. * @param context for percentage evaluation. * @return all the padding and border width. */ public int getIPPaddingAndBorder(boolean bDiscard, PercentBaseContext context) { return getPaddingStart(bDiscard, context) + getPaddingEnd(bDiscard, context) + getBorderStartWidth(bDiscard) + getBorderEndWidth(bDiscard); } /** * Return all the border and padding height in the block progression * dimension. * @param bDiscard the discard flag. * @param context for percentage evaluation * @return all the padding and border height. */ public int getBPPaddingAndBorder(boolean bDiscard, PercentBaseContext context) { return getPaddingBefore(bDiscard, context) + getPaddingAfter(bDiscard, context) + getBorderBeforeWidth(bDiscard) + getBorderAfterWidth(bDiscard); } /** {@inheritDoc} */ public String toString() { return "CommonBordersAndPadding (Before, After, Start, End):\n" + "Borders: (" + getBorderBeforeWidth(false) + ", " + getBorderAfterWidth(false) + ", " + getBorderStartWidth(false) + ", " + getBorderEndWidth(false) + ")\n" + "Border Colors: (" + getBorderColor(BEFORE) + ", " + getBorderColor(AFTER) + ", " + getBorderColor(START) + ", " + getBorderColor(END) + ")\n" + "Padding: (" + getPaddingBefore(false, null) + ", " + getPaddingAfter(false, null) + ", " + getPaddingStart(false, null) + ", " + getPaddingEnd(false, null) + ")\n"; } /** * @return true if there is any kind of background to be painted */ public boolean hasBackground() { return ((backgroundColor != null || getFopImage() != null)); } /** @return true if border is non-zero. */ public boolean hasBorder() { return ((getBorderBeforeWidth(false) + getBorderAfterWidth(false) + getBorderStartWidth(false) + getBorderEndWidth(false)) > 0); } /** * @param context for percentage based evaluation. * @return true if padding is non-zero. */ public boolean hasPadding(PercentBaseContext context) { return ((getPaddingBefore(false, context) + getPaddingAfter(false, context) + getPaddingStart(false, context) + getPaddingEnd(false, context)) > 0); } /** @return true if there are any borders defined. */ public boolean hasBorderInfo() { return (borderInfo[BEFORE] != null || borderInfo[AFTER] != null || borderInfo[START] != null || borderInfo[END] != null); } }