| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed 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.layoutmgr; |
| |
| import org.apache.fop.traits.SpaceVal; |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.apache.fop.traits.MinOptMax; |
| |
| /** |
| * Accumulate a sequence of space-specifiers (XSL space type) on |
| * areas with a stacking constraint. Provide a way to resolve these into |
| * a single MinOptMax value. |
| */ |
| public class SpaceSpecifier implements Cloneable { |
| |
| |
| private boolean bStartsReferenceArea; |
| private boolean bHasForcing = false; |
| private List vecSpaceVals = new java.util.ArrayList(); |
| |
| |
| /** |
| * Creates a new SpaceSpecifier. |
| * @param bStarts true if it starts a new reference area |
| */ |
| public SpaceSpecifier(boolean bStarts) { |
| bStartsReferenceArea = bStarts; |
| } |
| |
| /** |
| * @see java.lang.Object#clone() |
| */ |
| public Object clone() { |
| try { |
| SpaceSpecifier ss = (SpaceSpecifier) super.clone(); |
| ss.bStartsReferenceArea = this.bStartsReferenceArea; |
| ss.bHasForcing = this.bHasForcing; |
| // Clone the vector, but share the objects in it! |
| ss.vecSpaceVals = new ArrayList(); |
| ss.vecSpaceVals.addAll(this.vecSpaceVals); |
| return ss; |
| } catch (CloneNotSupportedException cnse) { |
| return null; |
| } |
| |
| } |
| |
| /** |
| * Clear all space specifiers |
| */ |
| public void clear() { |
| bHasForcing = false; |
| vecSpaceVals.clear(); |
| } |
| |
| /** |
| * Indicates whether any space-specifiers have been added. |
| * @return true if any space-specifiers have been added. |
| */ |
| public boolean hasSpaces() { |
| return (vecSpaceVals.size() > 0); |
| } |
| |
| /** |
| * Add a new space to the sequence. If this sequence starts a reference |
| * area, and the added space is conditional, and there are no |
| * non-conditional values in the sequence yet, then ignore it. Otherwise |
| * add it to the sequence. |
| */ |
| public void addSpace(SpaceVal moreSpace) { |
| if (!bStartsReferenceArea |
| || !moreSpace.isConditional() |
| || !vecSpaceVals.isEmpty()) { |
| if (moreSpace.isForcing()) { |
| if (bHasForcing == false) { |
| // Remove all other values (must all be non-forcing) |
| vecSpaceVals.clear(); |
| bHasForcing = true; |
| } |
| vecSpaceVals.add(moreSpace); |
| } else if (bHasForcing == false) { |
| // Don't bother adding all 0 space-specifier if not forcing |
| if (moreSpace.getSpace().min != 0 |
| || moreSpace.getSpace().opt != 0 |
| || moreSpace.getSpace().max != 0) { |
| vecSpaceVals.add(moreSpace); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Resolve the current sequence of space-specifiers, accounting for |
| * forcing values. |
| * @param bEndsReferenceArea True if the sequence should be resolved |
| * at the trailing edge of reference area. |
| * @return The resolved value as a min/opt/max triple. |
| */ |
| public MinOptMax resolve(boolean bEndsReferenceArea) { |
| int lastIndex = vecSpaceVals.size(); |
| if (bEndsReferenceArea) { |
| // Start from the end and count conditional specifiers |
| // Stop at first non-conditional |
| for (; lastIndex > 0; --lastIndex) { |
| SpaceVal sval = (SpaceVal) vecSpaceVals.get( |
| lastIndex - 1); |
| if (!sval.isConditional()) { |
| break; |
| } |
| } |
| } |
| MinOptMax resSpace = new MinOptMax(0); |
| int iMaxPrec = -1; |
| for (int index = 0; index < lastIndex; index++) { |
| SpaceVal sval = (SpaceVal) vecSpaceVals.get(index); |
| if (bHasForcing) { |
| resSpace.add(sval.getSpace()); |
| } else if (sval.getPrecedence() > iMaxPrec) { |
| iMaxPrec = sval.getPrecedence(); |
| resSpace = sval.getSpace(); |
| } else if (sval.getPrecedence() == iMaxPrec) { |
| if (sval.getSpace().opt > resSpace.opt) { |
| resSpace = sval.getSpace(); |
| } else if (sval.getSpace().opt == resSpace.opt) { |
| if (resSpace.min < sval.getSpace().min) { |
| resSpace.min = sval.getSpace().min; |
| } |
| if (resSpace.max > sval.getSpace().max) { |
| resSpace.max = sval.getSpace().max; |
| } |
| } |
| } |
| |
| } |
| return resSpace; |
| } |
| |
| public String toString() { |
| return "Space Specifier (resolved at begin/end of ref. area:):\n" + |
| resolve(false).toString() + "\n" + |
| resolve(true).toString(); |
| } |
| } |