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: ElementListUtils.java 538849 2007-05-17 09:36:24Z jeremias $ */
019:
020: package org.apache.fop.layoutmgr;
021:
022: import java.util.LinkedList;
023: import java.util.List;
024: import java.util.ListIterator;
025:
026: import org.apache.fop.traits.MinOptMax;
027:
028: /**
029: * Utilities for Knuth element lists.
030: */
031: public class ElementListUtils {
032:
033: /**
034: * Removes all legal breaks in an element list.
035: * @param elements the element list
036: */
037: public static void removeLegalBreaks(LinkedList elements) {
038: ListIterator i = elements.listIterator();
039: while (i.hasNext()) {
040: ListElement el = (ListElement) i.next();
041: if (el.isPenalty()) {
042: BreakElement breakPoss = (BreakElement) el;
043: //Convert all penalties no break inhibitors
044: if (breakPoss.getPenaltyValue() < KnuthPenalty.INFINITE) {
045: breakPoss.setPenaltyValue(KnuthPenalty.INFINITE);
046: }
047: } else if (el.isGlue()) {
048: i.previous();
049: if (el.isBox()) {
050: i.next();
051: i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE,
052: false, null, false));
053: }
054: }
055: }
056: }
057:
058: /**
059: * Removes legal breaks in an element list. A constraint can be specified to limit the
060: * range in which the breaks are removed. Legal breaks occuring before at least
061: * constraint.opt space is filled will be removed.
062: * @param elements the element list
063: * @param constraint min/opt/max value to restrict the range in which the breaks are removed.
064: * @return true if the opt constraint is bigger than the list contents
065: */
066: public static boolean removeLegalBreaks(LinkedList elements,
067: MinOptMax constraint) {
068: return removeLegalBreaks(elements, constraint.opt);
069: }
070:
071: /**
072: * Removes legal breaks in an element list. A constraint can be specified to limit the
073: * range in which the breaks are removed. Legal breaks occuring before at least
074: * constraint space is filled will be removed.
075: * @param elements the element list
076: * @param constraint value to restrict the range in which the breaks are removed.
077: * @return true if the constraint is bigger than the list contents
078: */
079: public static boolean removeLegalBreaks(LinkedList elements,
080: int constraint) {
081: int len = 0;
082: ListIterator iter = elements.listIterator();
083: while (iter.hasNext()) {
084: ListElement el = (ListElement) iter.next();
085: if (el.isPenalty()) {
086: KnuthPenalty penalty = (KnuthPenalty) el;
087: //Convert all penalties to break inhibitors
088: if (penalty.getP() < KnuthPenalty.INFINITE) {
089: iter.set(new KnuthPenalty(penalty.getW(),
090: KnuthPenalty.INFINITE, penalty.isFlagged(),
091: penalty.getPosition(), penalty
092: .isAuxiliary()));
093: }
094: } else if (el.isGlue()) {
095: KnuthGlue glue = (KnuthGlue) el;
096: len += glue.getW();
097: iter.previous();
098: el = (ListElement) iter.previous();
099: iter.next();
100: if (el.isBox()) {
101: iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE,
102: false, null, false));
103: }
104: iter.next();
105: } else if (el instanceof BreakElement) {
106: BreakElement breakEl = (BreakElement) el;
107: if (breakEl.getPenaltyValue() < KnuthPenalty.INFINITE) {
108: breakEl.setPenaltyValue(KnuthPenalty.INFINITE);
109: }
110: } else {
111: KnuthElement kel = (KnuthElement) el;
112: len += kel.getW();
113: }
114: if (len >= constraint) {
115: return false;
116: }
117: }
118: return true;
119: }
120:
121: /**
122: * Removes legal breaks in an element list. A constraint can be specified to limit the
123: * range in which the breaks are removed. Legal breaks within the space specified through the
124: * constraint (starting from the end of the element list) will be removed.
125: * @param elements the element list
126: * @param constraint value to restrict the range in which the breaks are removed.
127: * @return true if the constraint is bigger than the list contents
128: */
129: public static boolean removeLegalBreaksFromEnd(LinkedList elements,
130: int constraint) {
131: int len = 0;
132: ListIterator i = elements.listIterator(elements.size());
133: while (i.hasPrevious()) {
134: ListElement el = (ListElement) i.previous();
135: if (el.isPenalty()) {
136: KnuthPenalty penalty = (KnuthPenalty) el;
137: //Convert all penalties to break inhibitors
138: if (penalty.getP() < KnuthPenalty.INFINITE) {
139: i.set(new KnuthPenalty(penalty.getW(),
140: KnuthPenalty.INFINITE, penalty.isFlagged(),
141: penalty.getPosition(), penalty
142: .isAuxiliary()));
143: }
144: } else if (el.isGlue()) {
145: KnuthGlue glue = (KnuthGlue) el;
146: len += glue.getW();
147: el = (ListElement) i.previous();
148: i.next();
149: if (el.isBox()) {
150: i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE,
151: false, null, false));
152: }
153: } else if (el.isUnresolvedElement()) {
154: if (el instanceof BreakElement) {
155: BreakElement breakEl = (BreakElement) el;
156: if (breakEl.getPenaltyValue() < KnuthPenalty.INFINITE) {
157: breakEl.setPenaltyValue(KnuthPenalty.INFINITE);
158: }
159: } else if (el instanceof UnresolvedListElementWithLength) {
160: UnresolvedListElementWithLength uel = (UnresolvedListElementWithLength) el;
161: len += uel.getLength().opt;
162: }
163: } else {
164: KnuthElement kel = (KnuthElement) el;
165: len += kel.getW();
166: }
167: if (len >= constraint) {
168: return false;
169: }
170: }
171: return true;
172: }
173:
174: /**
175: * Calculates the content length of the given element list. Warning: It doesn't take any
176: * stretch and shrink possibilities into account.
177: * @param elems the element list
178: * @param start element at which to start
179: * @param end element at which to stop
180: * @return the content length
181: */
182: public static int calcContentLength(List elems, int start, int end) {
183: ListIterator iter = elems.listIterator(start);
184: int count = end - start + 1;
185: int len = 0;
186: while (iter.hasNext()) {
187: ListElement el = (ListElement) iter.next();
188: if (el.isBox()) {
189: len += ((KnuthElement) el).getW();
190: } else if (el.isGlue()) {
191: len += ((KnuthElement) el).getW();
192: } else {
193: //log.debug("Ignoring penalty: " + el);
194: //ignore penalties
195: }
196: count--;
197: if (count == 0) {
198: break;
199: }
200: }
201: return len;
202: }
203:
204: /**
205: * Calculates the content length of the given element list. Warning: It doesn't take any
206: * stretch and shrink possibilities into account.
207: * @param elems the element list
208: * @return the content length
209: */
210: public static int calcContentLength(List elems) {
211: return calcContentLength(elems, 0, elems.size() - 1);
212: }
213:
214: /**
215: * Indicates whether the given element list ends with a forced break.
216: * @param elems the element list
217: * @return true if the list ends with a forced break
218: */
219: public static boolean endsWithForcedBreak(LinkedList elems) {
220: ListElement last = (ListElement) elems.getLast();
221: return last.isForcedBreak();
222: }
223:
224: /**
225: * Determines the position of the previous break before the start index on an
226: * element list.
227: * @param elems the element list
228: * @param startIndex the start index
229: * @return the position of the previous break, or -1 if there was no previous break
230: */
231: public static int determinePreviousBreak(List elems, int startIndex) {
232: int prevBreak = startIndex - 1;
233: while (prevBreak >= 0) {
234: KnuthElement el = (KnuthElement) elems.get(prevBreak);
235: if (el.isPenalty() && el.getP() < KnuthElement.INFINITE) {
236: break;
237: }
238: prevBreak--;
239: }
240: return prevBreak;
241: }
242:
243: }
|