001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: SpaceSpecifier.java 426576 2006-07-28 15:44:37Z jeremias $ */
019:
020: package org.apache.fop.layoutmgr;
021:
022: import org.apache.fop.traits.SpaceVal;
023: import java.util.ArrayList;
024: import java.util.List;
025: import org.apache.fop.traits.MinOptMax;
026:
027: /**
028: * Accumulate a sequence of space-specifiers (XSL space type) on
029: * areas with a stacking constraint. Provide a way to resolve these into
030: * a single MinOptMax value.
031: */
032: public class SpaceSpecifier implements Cloneable {
033:
034: private boolean startsReferenceArea;
035: private boolean hasForcing = false;
036: private List spaceVals = new ArrayList();
037:
038: /**
039: * Creates a new SpaceSpecifier.
040: * @param startsReferenceArea true if it starts a new reference area
041: */
042: public SpaceSpecifier(boolean startsReferenceArea) {
043: this .startsReferenceArea = startsReferenceArea;
044: }
045:
046: /**
047: * @see java.lang.Object#clone()
048: */
049: public Object clone() {
050: try {
051: SpaceSpecifier ss = (SpaceSpecifier) super .clone();
052: ss.startsReferenceArea = startsReferenceArea;
053: ss.hasForcing = hasForcing;
054: // Clone the vector, but share the objects in it!
055: ss.spaceVals = new ArrayList();
056: ss.spaceVals.addAll(spaceVals);
057: return ss;
058: } catch (CloneNotSupportedException cnse) {
059: return null;
060: }
061:
062: }
063:
064: /**
065: * Clear all space specifiers
066: */
067: public void clear() {
068: hasForcing = false;
069: spaceVals.clear();
070: }
071:
072: /**
073: * Indicates whether any space-specifiers have been added.
074: * @return true if any space-specifiers have been added.
075: */
076: public boolean hasSpaces() {
077: return (spaceVals.size() > 0);
078: }
079:
080: /**
081: * Add a new space to the sequence. If this sequence starts a reference
082: * area, and the added space is conditional, and there are no
083: * non-conditional values in the sequence yet, then ignore it. Otherwise
084: * add it to the sequence.
085: */
086: public void addSpace(SpaceVal moreSpace) {
087: if (!startsReferenceArea || !moreSpace.isConditional()
088: || !spaceVals.isEmpty()) {
089: if (moreSpace.isForcing()) {
090: if (!hasForcing) {
091: // Remove all other values (must all be non-forcing)
092: spaceVals.clear();
093: hasForcing = true;
094: }
095: spaceVals.add(moreSpace);
096: } else if (!hasForcing) {
097: // Don't bother adding all 0 space-specifier if not forcing
098: if (moreSpace.getSpace().min != 0
099: || moreSpace.getSpace().opt != 0
100: || moreSpace.getSpace().max != 0) {
101: spaceVals.add(moreSpace);
102: }
103: }
104: }
105: }
106:
107: /**
108: * Resolve the current sequence of space-specifiers, accounting for
109: * forcing values.
110: * @param endsReferenceArea True if the sequence should be resolved
111: * at the trailing edge of reference area.
112: * @return The resolved value as a min/opt/max triple.
113: */
114: public MinOptMax resolve(boolean endsReferenceArea) {
115: int lastIndex = spaceVals.size();
116: if (endsReferenceArea) {
117: // Start from the end and count conditional specifiers
118: // Stop at first non-conditional
119: for (; lastIndex > 0; --lastIndex) {
120: SpaceVal spaceVal = (SpaceVal) spaceVals
121: .get(lastIndex - 1);
122: if (!spaceVal.isConditional()) {
123: break;
124: }
125: }
126: }
127: MinOptMax resolvedSpace = new MinOptMax(0);
128: int maxPrecedence = -1;
129: for (int index = 0; index < lastIndex; index++) {
130: SpaceVal spaceVal = (SpaceVal) spaceVals.get(index);
131: if (hasForcing) {
132: resolvedSpace.add(spaceVal.getSpace());
133: } else if (spaceVal.getPrecedence() > maxPrecedence) {
134: maxPrecedence = spaceVal.getPrecedence();
135: resolvedSpace = spaceVal.getSpace();
136: } else if (spaceVal.getPrecedence() == maxPrecedence) {
137: if (spaceVal.getSpace().opt > resolvedSpace.opt) {
138: resolvedSpace = spaceVal.getSpace();
139: } else if (spaceVal.getSpace().opt == resolvedSpace.opt) {
140: if (resolvedSpace.min < spaceVal.getSpace().min) {
141: resolvedSpace.min = spaceVal.getSpace().min;
142: }
143: if (resolvedSpace.max > spaceVal.getSpace().max) {
144: resolvedSpace.max = spaceVal.getSpace().max;
145: }
146: }
147: }
148:
149: }
150: return resolvedSpace;
151: }
152:
153: public String toString() {
154: return "Space Specifier (resolved at begin/end of ref. area:):\n"
155: + resolve(false).toString()
156: + "\n"
157: + resolve(true).toString();
158: }
159: }
|