/* * 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 org.apache.fop.datatypes.Numeric; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.expr.NumericOp; import org.apache.fop.fo.expr.PropertyException; /** * This property maker handles the calculations described in 5.3.2 which * involves the sizes of the corresponding margin-* properties and the * padding-* and border-*-width properties. */ public class IndentPropertyMaker extends CorrespondingPropertyMaker { /** * The corresponding padding-* propIds */ private int[] paddingCorresponding = null; /** * The corresponding border-*-width propIds */ private int[] borderWidthCorresponding = null; /** * Create a start-indent or end-indent property maker. * @param baseMaker the property maker to use */ public IndentPropertyMaker(PropertyMaker baseMaker) { super(baseMaker); } /** * Set the corresponding values for the padding-* properties. * @param paddingCorresponding the corresping propids. */ public void setPaddingCorresponding(int[] paddingCorresponding) { this.paddingCorresponding = paddingCorresponding; } /** * Set the corresponding values for the border-*-width properties. * @param borderWidthCorresponding the corresping propids. */ public void setBorderWidthCorresponding(int[] borderWidthCorresponding) { this.borderWidthCorresponding = borderWidthCorresponding; } /** * Calculate the corresponding value for start-indent and end-indent. * @param propertyList the property list to use in the computation * @return the computed indent property * @throws PropertyException if a property exception occurs * @see CorrespondingPropertyMaker#compute(PropertyList) */ public Property compute(PropertyList propertyList) throws PropertyException { if (propertyList.getFObj().getUserAgent() .isBreakIndentInheritanceOnReferenceAreaBoundary()) { return computeAlternativeRuleset(propertyList); } else { return computeConforming(propertyList); } } /** * Calculate the corresponding value for start-indent and end-indent. * @param propertyList the property list to use in the computation * @return the computed indent property * @throws PropertyException if a property exception occurs * @see CorrespondingPropertyMaker#compute(PropertyList) */ public Property computeConforming(PropertyList propertyList) throws PropertyException { PropertyList pList = getWMPropertyList(propertyList); if (pList == null) { return null; } // Calculate the values as described in 5.3.2. Numeric padding = getCorresponding(paddingCorresponding, propertyList).getNumeric(); Numeric border = getCorresponding(borderWidthCorresponding, propertyList).getNumeric(); int marginProp = pList.getWritingMode(lrtb, rltb, tbrl); // Calculate the absolute margin. if (propertyList.getExplicitOrShorthand(marginProp) == null) { Property indent = propertyList.getExplicit(baseMaker.propId); if (indent == null) { //Neither indent nor margin is specified, use inherited return null; } else { //Use explicit indent directly return indent; } } else { //Margin is used Numeric margin = propertyList.get(marginProp).getNumeric(); Numeric v = FixedLength.ZERO_FIXED_LENGTH; if (!propertyList.getFObj().generatesReferenceAreas()) { // The inherited_value_of([start|end]-indent) v = NumericOp.addition(v, propertyList.getInherited(baseMaker.propId).getNumeric()); } // The corresponding absolute margin-[right|left}. v = NumericOp.addition(v, margin); v = NumericOp.addition(v, padding); v = NumericOp.addition(v, border); return (Property) v; } } private boolean isInherited(PropertyList pList) { if (pList.getFObj().getUserAgent().isBreakIndentInheritanceOnReferenceAreaBoundary()) { FONode nd = pList.getFObj().getParent(); return !((nd instanceof FObj) && ((FObj)nd).generatesReferenceAreas()); } else { return true; } } /** * Calculate the corresponding value for start-indent and end-indent. * This method calculates indent following an alternative rule set that * tries to mimic many commercial solutions that chose to violate the * XSL specification. * @param propertyList the property list to use in the computation * @return the computed indent property * @throws PropertyException if a property exception occurs * @see CorrespondingPropertyMaker#compute(PropertyList) */ public Property computeAlternativeRuleset(PropertyList propertyList) throws PropertyException { PropertyList pList = getWMPropertyList(propertyList); if (pList == null) { return null; } // Calculate the values as described in 5.3.2. Numeric padding = getCorresponding(paddingCorresponding, propertyList).getNumeric(); Numeric border = getCorresponding(borderWidthCorresponding, propertyList).getNumeric(); int marginProp = pList.getWritingMode(lrtb, rltb, tbrl); //Determine whether the nearest anscestor indent was specified through //start-indent|end-indent or through a margin property. boolean marginNearest = false; PropertyList pl = propertyList.getParentPropertyList(); while (pl != null) { if (pl.getExplicit(baseMaker.propId) != null) { break; } else if (pl.getExplicitOrShorthand(marginProp) != null) { marginNearest = true; break; } pl = pl.getParentPropertyList(); } // Calculate the absolute margin. if (propertyList.getExplicitOrShorthand(marginProp) == null) { Property indent = propertyList.getExplicit(baseMaker.propId); if (indent == null) { //Neither start-indent nor margin is specified, use inherited if (isInherited(propertyList) || !marginNearest) { return null; } else { return FixedLength.ZERO_FIXED_LENGTH; } } else { return indent; } } else { //Margin is used Numeric margin = propertyList.get(marginProp).getNumeric(); Numeric v = FixedLength.ZERO_FIXED_LENGTH; if (isInherited(propertyList)) { // The inherited_value_of([start|end]-indent) v = NumericOp.addition(v, propertyList.getInherited(baseMaker.propId).getNumeric()); } // The corresponding absolute margin-[right|left}. v = NumericOp.addition(v, margin); v = NumericOp.addition(v, padding); v = NumericOp.addition(v, border); return (Property) v; } } private Property getCorresponding(int[] corresponding, PropertyList propertyList) throws PropertyException { PropertyList pList = getWMPropertyList(propertyList); if (pList != null) { int wmcorr = pList.getWritingMode(corresponding[0], corresponding[1], corresponding[2]); return propertyList.get(wmcorr); } else { return null; } } }