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: StaticContentLayoutManager.java 453310 2006-10-05 18:44:15Z spepping $ */
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.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.apache.fop.area.RegionReference;
029: import org.apache.fop.area.Area;
030: import org.apache.fop.area.Block;
031: import org.apache.fop.fo.FONode;
032: import org.apache.fop.fo.pagination.PageSequence;
033: import org.apache.fop.fo.pagination.SideRegion;
034: import org.apache.fop.fo.pagination.StaticContent;
035: import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
036: import org.apache.fop.layoutmgr.inline.TextLayoutManager;
037: import org.apache.fop.traits.MinOptMax;
038:
039: /**
040: * LayoutManager for an fo:flow object.
041: * Its parent LM is the PageSequenceLayoutManager.
042: * This LM is responsible for getting columns of the appropriate size
043: * and filling them with block-level areas generated by its children.
044: */
045: public class StaticContentLayoutManager extends
046: BlockStackingLayoutManager {
047:
048: /**
049: * logging instance
050: */
051: private static Log log = LogFactory
052: .getLog(StaticContentLayoutManager.class);
053:
054: private RegionReference targetRegion;
055: private Block targetBlock;
056: private SideRegion regionFO;
057:
058: private int contentAreaIPD = 0;
059: private int contentAreaBPD = -1;
060:
061: /**
062: * Creates a new StaticContentLayoutManager.
063: * @param pslm PageSequenceLayoutManager this layout manager belongs to
064: * @param node static-content FO
065: * @param reg side region to layout into
066: */
067: public StaticContentLayoutManager(PageSequenceLayoutManager pslm,
068: StaticContent node, SideRegion reg) {
069: super (node);
070: setParent(pslm);
071: regionFO = reg;
072: targetRegion = getCurrentPV().getRegionReference(
073: regionFO.getNameId());
074: }
075:
076: /**
077: * Creates a new StaticContentLayoutManager.
078: * @param pslm PageSequenceLayoutManager this layout manager belongs to
079: * @param node static-content FO
080: * @param block the block to layout into
081: */
082: public StaticContentLayoutManager(PageSequenceLayoutManager pslm,
083: StaticContent node, Block block) {
084: super (node);
085: setParent(pslm);
086: targetBlock = block;
087: }
088:
089: /** @see org.apache.fop.layoutmgr.LayoutManager */
090: public LinkedList getNextKnuthElements(LayoutContext context,
091: int alignment) {
092: if (true) {
093: throw new UnsupportedOperationException(
094: "Shouldn't this method be emptied because it's never called at all?");
095: }
096: //TODO Empty this method?!?
097: // set layout dimensions
098: setContentAreaIPD(context.getRefIPD());
099: setContentAreaBPD(context.getStackLimit().opt);
100:
101: //TODO Copied from elsewhere. May be worthwhile to factor out the common parts.
102: // currently active LM
103: BlockLevelLayoutManager curLM;
104: BlockLevelLayoutManager prevLM = null;
105: MinOptMax stackSize = new MinOptMax();
106: LinkedList returnedList;
107: LinkedList returnList = new LinkedList();
108:
109: while ((curLM = ((BlockLevelLayoutManager) getChildLM())) != null) {
110: if (curLM instanceof InlineLevelLayoutManager) {
111: log
112: .error("inline area not allowed under flow - ignoring");
113: curLM.setFinished(true);
114: continue;
115: }
116:
117: // Set up a LayoutContext
118: MinOptMax bpd = context.getStackLimit();
119:
120: LayoutContext childLC = new LayoutContext(0);
121: childLC.setStackLimit(MinOptMax.subtract(bpd, stackSize));
122: childLC.setRefIPD(context.getRefIPD());
123:
124: // get elements from curLM
125: returnedList = curLM.getNextKnuthElements(childLC,
126: alignment);
127: //log.debug("FLM.getNextKnuthElements> returnedList.size() = "
128: // + returnedList.size());
129:
130: // "wrap" the Position inside each element
131: LinkedList tempList = returnedList;
132: KnuthElement tempElement;
133: returnedList = new LinkedList();
134: ListIterator listIter = tempList.listIterator();
135: while (listIter.hasNext()) {
136: tempElement = (KnuthElement) listIter.next();
137: tempElement.setPosition(new NonLeafPosition(this ,
138: tempElement.getPosition()));
139: returnedList.add(tempElement);
140: }
141:
142: if (returnedList.size() == 1
143: && ((KnuthElement) returnedList.getFirst())
144: .isPenalty()
145: && ((KnuthPenalty) returnedList.getFirst()).getP() == -KnuthElement.INFINITE) {
146: // a descendant of this flow has break-before
147: returnList.addAll(returnedList);
148: return returnList;
149: } else {
150: if (returnList.size() > 0) {
151: // there is a block before this one
152: if (prevLM.mustKeepWithNext()
153: || curLM.mustKeepWithPrevious()) {
154: // add an infinite penalty to forbid a break between blocks
155: returnList.add(new KnuthPenalty(0,
156: KnuthElement.INFINITE, false,
157: new Position(this ), false));
158: } else if (!((KnuthElement) returnList.getLast())
159: .isGlue()) {
160: // add a null penalty to allow a break between blocks
161: returnList.add(new KnuthPenalty(0, 0, false,
162: new Position(this ), false));
163: }
164: }
165: /*LF*/if (returnedList.size() > 0) { // controllare!
166: returnList.addAll(returnedList);
167: if (((KnuthElement) returnedList.getLast())
168: .isPenalty()
169: && ((KnuthPenalty) returnedList.getLast())
170: .getP() == -KnuthElement.INFINITE) {
171: // a descendant of this flow has break-after
172: /*LF*///log.debug("FLM - break after!!");
173: return returnList;
174: }
175: /*LF*/}
176: }
177: prevLM = curLM;
178: }
179:
180: setFinished(true);
181:
182: if (returnList.size() > 0) {
183: return returnList;
184: } else {
185: return null;
186: }
187: }
188:
189: /**
190: * @see org.apache.fop.layoutmgr.LayoutManager#addAreas(PositionIterator, LayoutContext)
191: */
192: public void addAreas(PositionIterator parentIter,
193: LayoutContext layoutContext) {
194: AreaAdditionUtil.addAreas(this , parentIter, layoutContext);
195:
196: flush();
197: targetRegion = null;
198: }
199:
200: /**
201: * Add child area to a the correct container, depending on its
202: * area class. A Flow can fill at most one area container of any class
203: * at any one time. The actual work is done by BlockStackingLM.
204: * @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
205: */
206: public void addChildArea(Area childArea) {
207: if (getStaticContentFO().getFlowName().equals(
208: "xsl-footnote-separator")) {
209: targetBlock.addBlock((Block) childArea);
210: } else {
211: targetRegion.addBlock((Block) childArea);
212: }
213: }
214:
215: /**
216: * @see org.apache.fop.layoutmgr.LayoutManager#getParentArea(Area)
217: */
218: public Area getParentArea(Area childArea) {
219: if (getStaticContentFO().getFlowName().equals(
220: "xsl-footnote-separator")) {
221: return targetBlock;
222: } else {
223: return targetRegion;
224: }
225: }
226:
227: /**
228: * Does the layout for a side region. Called by PageSequenceLayoutManager.
229: */
230: public void doLayout() {
231: int targetIPD = 0;
232: int targetBPD = 0;
233: int targetAlign = EN_AUTO;
234: boolean autoHeight = false;
235: StaticContentBreaker breaker;
236:
237: if (getStaticContentFO().getFlowName().equals(
238: "xsl-footnote-separator")) {
239: targetIPD = targetBlock.getIPD();
240: targetBPD = targetBlock.getBPD();
241: if (targetBPD == 0) {
242: autoHeight = true;
243: }
244: targetAlign = EN_BEFORE;
245: } else {
246: targetIPD = targetRegion.getIPD();
247: targetBPD = targetRegion.getBPD();
248: targetAlign = regionFO.getDisplayAlign();
249: }
250: setContentAreaIPD(targetIPD);
251: setContentAreaBPD(targetBPD);
252: breaker = new StaticContentBreaker(this , targetIPD, targetAlign);
253: breaker.doLayout(targetBPD, autoHeight);
254: if (breaker.isOverflow()) {
255: if (!autoHeight) {
256: //Overflow handling
257: if (regionFO.getOverflow() == EN_ERROR_IF_OVERFLOW) {
258: //TODO throw layout exception
259: }
260: log.warn(FONode.decorateWithContextInfo(
261: "static-content overflows the available area.",
262: fobj));
263: }
264: }
265: }
266:
267: /**
268: * Convenience method that returns the Static Content node.
269: * @return the static content node
270: */
271: protected StaticContent getStaticContentFO() {
272: return (StaticContent) fobj;
273: }
274:
275: private class StaticContentBreaker extends AbstractBreaker {
276: private StaticContentLayoutManager lm;
277: private int displayAlign;
278: private int ipd;
279: private boolean overflow = false;
280:
281: public StaticContentBreaker(StaticContentLayoutManager lm,
282: int ipd, int displayAlign) {
283: this .lm = lm;
284: this .ipd = ipd;
285: this .displayAlign = displayAlign;
286: }
287:
288: /** @see org.apache.fop.layoutmgr.AbstractBreaker#observeElementList(java.util.List) */
289: protected void observeElementList(List elementList) {
290: String elementListID = getStaticContentFO().getFlowName();
291: String pageSequenceID = ((PageSequence) lm.getParent()
292: .getFObj()).getId();
293: if (pageSequenceID != null && pageSequenceID.length() > 0) {
294: elementListID += "-" + pageSequenceID;
295: }
296: ElementListObserver.observe(elementList, "static-content",
297: elementListID);
298: }
299:
300: /** @see org.apache.fop.layoutmgr.AbstractBreaker#isPartOverflowRecoveryActivated() */
301: protected boolean isPartOverflowRecoveryActivated() {
302: //For side regions, this must be disabled because of wanted overflow.
303: return false;
304: }
305:
306: public boolean isOverflow() {
307: return this .overflow;
308: }
309:
310: protected LayoutManager getTopLevelLM() {
311: return lm;
312: }
313:
314: protected LayoutContext createLayoutContext() {
315: LayoutContext lc = super .createLayoutContext();
316: lc.setRefIPD(ipd);
317: return lc;
318: }
319:
320: protected LinkedList getNextKnuthElements(
321: LayoutContext context, int alignment) {
322: LayoutManager curLM; // currently active LM
323: LinkedList returnList = new LinkedList();
324:
325: while ((curLM = getChildLM()) != null) {
326: LayoutContext childLC = new LayoutContext(0);
327: childLC.setStackLimit(context.getStackLimit());
328: childLC.setRefIPD(context.getRefIPD());
329: childLC.setWritingMode(context.getWritingMode());
330:
331: LinkedList returnedList = null;
332: //The following is a HACK! Ignore leading and trailing white space
333: boolean ignore = curLM instanceof TextLayoutManager;
334: if (!curLM.isFinished()) {
335: returnedList = curLM.getNextKnuthElements(childLC,
336: alignment);
337: }
338: if (returnedList != null && !ignore) {
339: lm.wrapPositionElements(returnedList, returnList);
340: }
341: }
342: SpaceResolver.resolveElementList(returnList);
343: setFinished(true);
344: return returnList;
345: }
346:
347: protected int getCurrentDisplayAlign() {
348: return displayAlign;
349: }
350:
351: protected boolean hasMoreContent() {
352: return !lm.isFinished();
353: }
354:
355: protected void addAreas(PositionIterator posIter,
356: LayoutContext context) {
357: AreaAdditionUtil.addAreas(lm, posIter, context);
358: }
359:
360: protected void doPhase3(PageBreakingAlgorithm alg,
361: int partCount, BlockSequence originalList,
362: BlockSequence effectiveList) {
363: //Directly add areas after finding the breaks
364: this .addAreas(alg, partCount, originalList, effectiveList);
365: if (partCount > 1) {
366: overflow = true;
367: }
368: }
369:
370: protected void finishPart(PageBreakingAlgorithm alg,
371: PageBreakPosition pbp) {
372: //nop for static content
373: }
374:
375: protected LayoutManager getCurrentChildLM() {
376: return null; //TODO NYI
377: }
378: }
379:
380: /**
381: * Returns the IPD of the content area
382: * @return the IPD of the content area
383: */
384: public int getContentAreaIPD() {
385: return contentAreaIPD;
386: }
387:
388: /** @see org.apache.fop.layoutmgr.BlockStackingLayoutManager#setContentAreaIPD(int) */
389: protected void setContentAreaIPD(int contentAreaIPD) {
390: this .contentAreaIPD = contentAreaIPD;
391: }
392:
393: /**
394: * Returns the BPD of the content area
395: * @return the BPD of the content area
396: */
397: public int getContentAreaBPD() {
398: return contentAreaBPD;
399: }
400:
401: private void setContentAreaBPD(int contentAreaBPD) {
402: this.contentAreaBPD = contentAreaBPD;
403: }
404:
405: }
|