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: LayoutContext.java 563951 2007-08-08 17:37:33Z vhennebert $ */
019:
020: package org.apache.fop.layoutmgr;
021:
022: import java.util.Collections;
023: import java.util.List;
024:
025: import org.apache.fop.fo.Constants;
026: import org.apache.fop.layoutmgr.inline.HyphContext;
027: import org.apache.fop.traits.MinOptMax;
028: import org.apache.fop.layoutmgr.inline.AlignmentContext;
029:
030: /**
031: * This class is used to pass information to the getNextKnuthElements()
032: * method. It is set up by higher level LM and used by lower level LM.
033: */
034: public class LayoutContext {
035: /**
036: * Values for flags.
037: */
038: public static final int LINEBREAK_AT_LF_ONLY = 0x01;
039: /** Generated break possibility is first in a new area */
040: public static final int NEW_AREA = 0x02;
041: public static final int IPD_UNKNOWN = 0x04;
042: /** Signal to a Line LM that a higher level LM may provoke a change
043: * in the reference area, thus ref area IPD. The LineLM should return
044: * without looking for a line break.
045: */
046: public static final int CHECK_REF_AREA = 0x08;
047:
048: /**
049: * If this flag is set, it indicates that any leading fo:character
050: * objects with suppress-at-line-break="suppress" should not generate
051: * areas. This is the case at the beginning of each new LineArea
052: * except the first.
053: */
054: public static final int SUPPRESS_LEADING_SPACE = 0x10;
055: public static final int FIRST_AREA = 0x20;
056: public static final int TRY_HYPHENATE = 0x40;
057: public static final int LAST_AREA = 0x80;
058:
059: public static final int RESOLVE_LEADING_SPACE = 0x100;
060:
061: /**
062: * This flag indicates that there's a keep-with-next that hasn't
063: * been processed, yet.
064: */
065: public static final int KEEP_WITH_NEXT_PENDING = 0x200;
066: /**
067: * This flag indicates that there's a keep-with-previous that hasn't
068: * been processed, yet.
069: */
070: public static final int KEEP_WITH_PREVIOUS_PENDING = 0x400;
071:
072: private int flags; // Contains some set of flags defined above
073: /**
074: * Total available stacking dimension for a "galley-level" layout
075: * manager (Line or Flow). It is passed by the parent LM. For LineLM,
076: * the block LM determines this based on indent properties.
077: * These LM <b>may</b> wish to pass this information down to lower
078: * level LM to allow them to optimize returned break possibilities.
079: */
080: private MinOptMax stackLimit;
081:
082: /** True if current element list is spanning in multi-column layout. */
083: private int nextSpan = Constants.NOT_SET;
084:
085: /** inline-progression-dimension of nearest ancestor reference area */
086: private int refIPD;
087:
088: /** the writing mode established by the nearest ancestor reference area */
089: private int writingMode = Constants.EN_LR_TB;
090:
091: /** Current pending space-after or space-end from preceding area */
092: private SpaceSpecifier trailingSpace;
093:
094: /** Current pending space-before or space-start from ancestor areas */
095: private SpaceSpecifier leadingSpace;
096:
097: /**
098: * A list of pending marks (border and padding) on the after edge when a page break occurs.
099: * May be null.
100: */
101: private List pendingAfterMarks;
102:
103: /**
104: * A list of pending marks (border and padding) on the before edge when a page break occurs.
105: * May be null.
106: */
107: private List pendingBeforeMarks;
108:
109: /** Current hyphenation context. May be null. */
110: private HyphContext hyphContext = null;
111:
112: /** Alignment in BP direction */
113: private int bpAlignment = Constants.EN_START;
114:
115: /** Stretch or shrink value when making areas. */
116: private double ipdAdjust = 0.0;
117:
118: /** Stretch or shrink value when adding spaces. */
119: private double dSpaceAdjust = 0.0;
120:
121: private AlignmentContext alignmentContext = null;
122:
123: /** Amount of space before / start */
124: private int spaceBefore = 0;
125:
126: /** Amount of space after / end */
127: private int spaceAfter = 0;
128:
129: /** Amount of space to reserve at the beginning of each line */
130: private int lineStartBorderAndPaddingWidth = 0;
131: /** Amount of space to reserve at the end of each line */
132: private int lineEndBorderAndPaddingWidth = 0;
133:
134: /**
135: * Copy constructor for creating child layout contexts.
136: * @param parentLC the parent layout context to copy from
137: */
138: public LayoutContext(LayoutContext parentLC) {
139: this .flags = parentLC.flags;
140: this .refIPD = parentLC.refIPD;
141: this .writingMode = parentLC.writingMode;
142: this .stackLimit = null; // Don't reference parent MinOptMax!
143: this .leadingSpace = parentLC.leadingSpace; //???
144: this .trailingSpace = parentLC.trailingSpace; //???
145: this .hyphContext = parentLC.hyphContext;
146: this .bpAlignment = parentLC.bpAlignment;
147: this .dSpaceAdjust = parentLC.dSpaceAdjust;
148: this .ipdAdjust = parentLC.ipdAdjust;
149: this .alignmentContext = parentLC.alignmentContext;
150: this .lineStartBorderAndPaddingWidth = parentLC.lineStartBorderAndPaddingWidth;
151: this .lineEndBorderAndPaddingWidth = parentLC.lineEndBorderAndPaddingWidth;
152: copyPendingMarksFrom(parentLC);
153: // Copy other fields as necessary.
154: }
155:
156: /**
157: * Main constructor.
158: * @param flags the initial flags
159: */
160: public LayoutContext(int flags) {
161: this .flags = flags;
162: this .refIPD = 0;
163: stackLimit = new MinOptMax(0);
164: leadingSpace = null;
165: trailingSpace = null;
166: }
167:
168: public void copyPendingMarksFrom(LayoutContext source) {
169: if (source.pendingAfterMarks != null) {
170: this .pendingAfterMarks = new java.util.ArrayList(
171: source.pendingAfterMarks);
172: }
173: if (source.pendingBeforeMarks != null) {
174: this .pendingBeforeMarks = new java.util.ArrayList(
175: source.pendingBeforeMarks);
176: }
177: }
178:
179: public void setFlags(int flags) {
180: setFlags(flags, true);
181: }
182:
183: public void setFlags(int flags, boolean bSet) {
184: if (bSet) {
185: this .flags |= flags;
186: } else {
187: this .flags &= ~flags;
188: }
189: }
190:
191: public void unsetFlags(int flags) {
192: setFlags(flags, false);
193: }
194:
195: public boolean isStart() {
196: return ((this .flags & NEW_AREA) != 0);
197: }
198:
199: public boolean startsNewArea() {
200: return ((this .flags & NEW_AREA) != 0 && leadingSpace != null);
201: }
202:
203: public boolean isFirstArea() {
204: return ((this .flags & FIRST_AREA) != 0);
205: }
206:
207: public boolean isLastArea() {
208: return ((this .flags & LAST_AREA) != 0);
209: }
210:
211: public boolean suppressLeadingSpace() {
212: return ((this .flags & SUPPRESS_LEADING_SPACE) != 0);
213: }
214:
215: public boolean isKeepWithNextPending() {
216: return ((this .flags & KEEP_WITH_NEXT_PENDING) != 0);
217: }
218:
219: public boolean isKeepWithPreviousPending() {
220: return ((this .flags & KEEP_WITH_PREVIOUS_PENDING) != 0);
221: }
222:
223: public void setLeadingSpace(SpaceSpecifier space) {
224: leadingSpace = space;
225: }
226:
227: public SpaceSpecifier getLeadingSpace() {
228: return leadingSpace;
229: }
230:
231: public boolean resolveLeadingSpace() {
232: return ((this .flags & RESOLVE_LEADING_SPACE) != 0);
233: }
234:
235: public void setTrailingSpace(SpaceSpecifier space) {
236: trailingSpace = space;
237: }
238:
239: public SpaceSpecifier getTrailingSpace() {
240: return trailingSpace;
241: }
242:
243: /**
244: * Adds a border or padding element to the pending list which will be used to generate
245: * the right element list for break possibilities. Conditionality resolution will be done
246: * elsewhere.
247: * @param element the border, padding or space element
248: */
249: public void addPendingAfterMark(
250: UnresolvedListElementWithLength element) {
251: if (this .pendingAfterMarks == null) {
252: this .pendingAfterMarks = new java.util.ArrayList();
253: }
254: this .pendingAfterMarks.add(element);
255: }
256:
257: /**
258: * @return the pending border and padding elements at the after edge
259: * @see #addPendingAfterMark(UnresolvedListElementWithLength)
260: */
261: public List getPendingAfterMarks() {
262: if (this .pendingAfterMarks != null) {
263: return Collections.unmodifiableList(this .pendingAfterMarks);
264: } else {
265: return null;
266: }
267: }
268:
269: /**
270: * Adds a border or padding element to the pending list which will be used to generate
271: * the right element list for break possibilities. Conditionality resolution will be done
272: * elsewhere.
273: * @param element the border, padding or space element
274: */
275: public void addPendingBeforeMark(
276: UnresolvedListElementWithLength element) {
277: if (this .pendingBeforeMarks == null) {
278: this .pendingBeforeMarks = new java.util.ArrayList();
279: }
280: this .pendingBeforeMarks.add(element);
281: }
282:
283: /**
284: * @return the pending border and padding elements at the before edge
285: * @see #addPendingBeforeMark(UnresolvedListElementWithLength)
286: */
287: public List getPendingBeforeMarks() {
288: if (this .pendingBeforeMarks != null) {
289: return Collections
290: .unmodifiableList(this .pendingBeforeMarks);
291: } else {
292: return null;
293: }
294: }
295:
296: public void setStackLimit(MinOptMax limit) {
297: stackLimit = limit;
298: }
299:
300: public MinOptMax getStackLimit() {
301: return stackLimit;
302: }
303:
304: /**
305: * Sets the inline-progression-dimension of the nearest ancestor reference area.
306: */
307: public void setRefIPD(int ipd) {
308: refIPD = ipd;
309: }
310:
311: /**
312: * Returns the inline-progression-dimension of the nearest ancestor reference area.
313: *
314: * @return the inline-progression-dimension of the nearest ancestor reference area
315: */
316: public int getRefIPD() {
317: return refIPD;
318: }
319:
320: public void setHyphContext(HyphContext hyph) {
321: hyphContext = hyph;
322: }
323:
324: public HyphContext getHyphContext() {
325: return hyphContext;
326: }
327:
328: public boolean tryHyphenate() {
329: return ((this .flags & TRY_HYPHENATE) != 0);
330: }
331:
332: /**
333: * Sets the currently applicable alignment in BP direction.
334: * @param alignment one of EN_START, EN_JUSTIFY etc.
335: */
336: public void setBPAlignment(int alignment) {
337: this .bpAlignment = alignment;
338: }
339:
340: /** @return the currently applicable alignment in BP direction (EN_START, EN_JUSTIFY...) */
341: public int getBPAlignment() {
342: return this .bpAlignment;
343: }
344:
345: public void setSpaceAdjust(double adjust) {
346: dSpaceAdjust = adjust;
347: }
348:
349: public double getSpaceAdjust() {
350: return dSpaceAdjust;
351: }
352:
353: public void setIPDAdjust(double ipdA) {
354: ipdAdjust = ipdA;
355: }
356:
357: public double getIPDAdjust() {
358: return ipdAdjust;
359: }
360:
361: public void setAlignmentContext(AlignmentContext alignmentContext) {
362: this .alignmentContext = alignmentContext;
363: }
364:
365: public AlignmentContext getAlignmentContext() {
366: return this .alignmentContext;
367: }
368:
369: public void resetAlignmentContext() {
370: if (this .alignmentContext != null) {
371: this .alignmentContext = this .alignmentContext
372: .getParentAlignmentContext();
373: }
374: }
375:
376: /**
377: * Get the width to be reserved for border and padding at the start of the line.
378: * @return the width to be reserved
379: */
380: public int getLineStartBorderAndPaddingWidth() {
381: return lineStartBorderAndPaddingWidth;
382: }
383:
384: /**
385: * Set the width to be reserved for border and padding at the start of the line.
386: * @param lineStartBorderAndPaddingWidth the width to be reserved
387: */
388: public void setLineStartBorderAndPaddingWidth(
389: int lineStartBorderAndPaddingWidth) {
390: this .lineStartBorderAndPaddingWidth = lineStartBorderAndPaddingWidth;
391: }
392:
393: /**
394: * Get the width to be reserved for border and padding at the end of the line.
395: * @return the width to be reserved
396: */
397: public int getLineEndBorderAndPaddingWidth() {
398: return lineEndBorderAndPaddingWidth;
399: }
400:
401: /**
402: * Set the width to be reserved for border and padding at the end of the line.
403: * @param lineEndBorderAndPaddingWidth the width to be reserved
404: */
405: public void setLineEndBorderAndPaddingWidth(
406: int lineEndBorderAndPaddingWidth) {
407: this .lineEndBorderAndPaddingWidth = lineEndBorderAndPaddingWidth;
408: }
409:
410: /**
411: * @return true if the current element list ends early because of a span change
412: * in multi-column layout.
413: */
414: public int getNextSpan() {
415: return nextSpan;
416: }
417:
418: /**
419: * Used to signal the PSLM that the element list ends early because of a span change in
420: * multi-column layout.
421: * @param span the new span value (legal values: NOT_SET, EN_NONE, EN_ALL)
422: */
423: public void signalSpanChange(int span) {
424: if (span == Constants.NOT_SET || span == Constants.EN_NONE
425: || span == Constants.EN_ALL) {
426: this .nextSpan = span;
427: } else {
428: throw new IllegalArgumentException(
429: "Illegal value on signalSpanChange() for span: "
430: + span);
431: }
432: }
433:
434: /**
435: * Get the writing mode of the relevant reference area.
436: * @return the applicable writing mode
437: */
438: public int getWritingMode() {
439: return writingMode;
440: }
441:
442: /**
443: * Set the writing mode.
444: * @param writingMode the writing mode
445: */
446: public void setWritingMode(int writingMode) {
447: this .writingMode = writingMode;
448: }
449:
450: /**
451: * Get the current amount of space before / start
452: * @return the space before / start amount
453: */
454: public int getSpaceBefore() {
455: return spaceBefore;
456: }
457:
458: /**
459: * Set the amount of space before / start
460: * @param spaceBefore the amount of space before / start
461: */
462: public void setSpaceBefore(int spaceBefore) {
463: this .spaceBefore = spaceBefore;
464: }
465:
466: /**
467: * Get the current amount of space after / end
468: * @return the space after / end amount
469: */
470: public int getSpaceAfter() {
471: return spaceAfter;
472: }
473:
474: /**
475: * Set the amount of space after / end
476: * @param spaceAfter the amount of space after / end
477: */
478: public void setSpaceAfter(int spaceAfter) {
479: this .spaceAfter = spaceAfter;
480: }
481:
482: /** @see java.lang.Object#toString() */
483: public String toString() {
484: return "Layout Context:" + "\nStack Limit: \t"
485: + (getStackLimit() == null ? "null" : getStackLimit()
486: .toString())
487: + "\nTrailing Space: \t"
488: + (getTrailingSpace() == null ? "null"
489: : getTrailingSpace().toString())
490: + "\nLeading Space: \t"
491: + (getLeadingSpace() == null ? "null"
492: : getLeadingSpace().toString())
493: + "\nReference IPD: \t"
494: + getRefIPD()
495: + "\nSpace Adjust: \t"
496: + getSpaceAdjust()
497: + "\nIPD Adjust: \t"
498: + getIPDAdjust()
499: + "\nResolve Leading Space: \t"
500: + resolveLeadingSpace()
501: + "\nSuppress Leading Space: \t"
502: + suppressLeadingSpace()
503: + "\nIs First Area: \t"
504: + isFirstArea()
505: + "\nStarts New Area: \t"
506: + startsNewArea()
507: + "\nIs Last Area: \t"
508: + isLastArea()
509: + "\nTry Hyphenate: \t"
510: + tryHyphenate()
511: + "\nKeeps: \t["
512: + (isKeepWithNextPending() ? "keep-with-next" : "")
513: + "]["
514: + (isKeepWithPreviousPending() ? "keep-with-previous"
515: : "") + "] pending";
516: }
517:
518: }
|