--- /dev/null
+/*
+ * Copyright 2005 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.area.inline;
+
+import org.apache.fop.area.Area;
+import org.apache.fop.area.Block;
+
+
+/**
+ * Inline block parent area.
+ * This is an inline area that can have one block area as a child
+ */
+public class InlineBlockParent extends InlineArea {
+
+ /**
+ * The list of inline areas added to this inline parent.
+ */
+ protected Block child = null;
+
+ /**
+ * Create a new inline block parent to add areas to.
+ */
+ public InlineBlockParent() {
+ }
+
+ /**
+ * Override generic Area method.
+ *
+ * @param childArea the child area to add
+ */
+ public void addChildArea(Area childArea) {
+ if (childArea instanceof Block && child == null) {
+ child = (Block) childArea;
+ } else {
+ // TODO: log error, raise exception?
+ }
+ }
+
+ /**
+ * Get the child areas for this inline parent.
+ *
+ * @return the list of child areas
+ */
+ public Block getChildArea() {
+ return child;
+ }
+
+}
*/
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
- return ((BlockLevelLayoutManager)getParent()).mustKeepTogether()
+ // TODO This is a quick fix for the fact that the parent is not always a BlockLevelLM;
+ // eventually mustKeepTogether() must be moved up to the LM interface
+ return (getParent() instanceof BlockLevelLayoutManager
+ && ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
|| !getBlockFO().getKeepTogether().getWithinPage().isAuto()
|| !getBlockFO().getKeepTogether().getWithinColumn().isAuto();
}
splitLength += element.getW();
lastLM = element.getLayoutManager();
}
- }
+ }
//System.out.println("addAreas riferito a storedList da " +
// iFirst + " a " + iLast);
//System.out.println("splitLength= " + splitLength
public int ignoreAtStart = 0;
/** Number of elements to ignore at the end of the list. */
public int ignoreAtEnd = 0;
+ // Is this an inline or a block sequence?
+ private boolean isInlineSequence = false;
/**
* Creates a new and empty list.
super();
}
+ /**
+ * Creates a new and empty list, and sets isInlineSequence.
+ */
+ public KnuthSequence(boolean isInlineSequence) {
+ super();
+ this.isInlineSequence = isInlineSequence;
+ }
+
/**
* Marks the start of the sequence.
*/
public KnuthElement getElement(int index) {
return (KnuthElement) get(index);
}
+
+ /**
+ * Is this an inline or a block sequence?
+ * @return true if this is an inline sequence
+ */
+ public boolean isInlineSequence() {
+ return isInlineSequence;
+ }
}
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.Trait;
import org.apache.fop.area.LinkResolver;
fobj = node;
}
- protected InlineParent createArea() {
- InlineParent area = super.createArea();
+ protected InlineArea createArea(boolean bInlineParent) {
+ InlineArea area = super.createArea(bInlineParent);
setupBasicLinkArea(parentLM, area);
return area;
}
private void setupBasicLinkArea(LayoutManager parentLM,
- InlineParent area) {
+ InlineArea area) {
if (fobj.getExternalDestination() != null) {
area.addTrait(Trait.EXTERNAL_LINK, fobj.getExternalDestination());
} else {
import java.util.ListIterator;
import java.util.LinkedList;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.InlineLevel;
import org.apache.fop.fo.properties.CommonMarginInline;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthSequence;
+import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
private CommonMarginInline inlineProps = null;
private CommonBorderPaddingBackground borderProps = null;
+ private boolean bAreaCreated = false;
+ private LayoutManager lastChildLM = null; // Set when return last breakposs;
+
/**
* Create an inline layout manager.
* This is used for fo's that create areas that
}
/** @see org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager#createArea() */
- protected InlineParent createArea() {
- InlineParent area = super.createArea();
+ protected InlineArea createArea(boolean bInlineParent) {
+ InlineArea area;
+ if (bInlineParent) {
+ area = new InlineParent();
+ area.setOffset(0);
+ } else {
+ area = new InlineBlockParent();
+ }
TraitSetter.setProducerID(area, getInlineFO().getId());
return area;
}
/** @see org.apache.fop.layoutmgr.LayoutManager */
public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) {
- InlineLevelLayoutManager curLM;
+ InlineLevelLayoutManager curILM;
+ LayoutManager curLM, lastLM = null;
// the list returned by child LM
LinkedList returnedList;
// the list which will be returned to the parent LM
LinkedList returnList = new LinkedList();
+ KnuthSequence lastSequence = null;
SpaceSpecifier leadingSpace = lc.getLeadingSpace();
clearPrevIPD(); // Clear stored prev content dimensions
}
- while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
+ StringBuffer trace = new StringBuffer("InlineLM:");
+
+ while ((curLM = (LayoutManager) getChildLM()) != null) {
// get KnuthElements from curLM
returnedList = curLM.getNextKnuthElements(lc, alignment);
- if (returnedList != null) {
+ if (returnedList == null) {
+ // curLM returned null because it finished;
+ // just iterate once more to see if there is another child
+ continue;
+ }
+ if (curLM instanceof InlineLevelLayoutManager) {
+ // close the last block sequence
+ if (lastSequence != null && !lastSequence.isInlineSequence()) {
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
// "wrap" the Position stored in each element of returnedList
- ListIterator listIter = returnedList.listIterator();
- while (listIter.hasNext()) {
- returnedElement = (KnuthElement) listIter.next();
- returnedElement.setPosition
+ ListIterator seqIter = returnedList.listIterator();
+ while (seqIter.hasNext()) {
+ KnuthSequence sequence = (KnuthSequence) seqIter.next();
+ ListIterator listIter = sequence.listIterator();
+ while (listIter.hasNext()) {
+ returnedElement = (KnuthElement) listIter.next();
+ returnedElement.setPosition
(new NonLeafPosition(this,
- returnedElement.getPosition()));
- returnList.add(returnedElement);
+ returnedElement.getPosition()));
+ }
+ if (!sequence.isInlineSequence()) {
+ if (lastSequence != null && lastSequence.isInlineSequence()) {
+ // log.error("Last inline sequence should be closed before a block sequence");
+ lastSequence.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+ false, null, false));
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ returnList.add(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" B");
+ }
+ } else {
+ if (lastSequence == null) {
+ lastSequence = new KnuthSequence(true);
+ returnList.add(lastSequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" [");
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ trace.append(" +");
+ }
+ }
+ lastSequence.addAll(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" I");
+ }
+ // finish last paragraph if it was closed with a linefeed
+ KnuthElement lastElement = (KnuthElement) sequence.getLast();
+ if (lastElement.isPenalty()
+ && ((KnuthPenalty) lastElement).getP()
+ == -KnuthPenalty.INFINITE) {
+ // a penalty item whose value is -inf
+ // represents a preserved linefeed,
+ // wich forces a line break
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ }
+ }
+ } else { // A block LM
+ // close the last inline sequence
+ if (lastSequence != null && lastSequence.isInlineSequence()) {
+ lastSequence.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+ false, null, false));
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ if (curLM != lastLM) {
+ // close the last block sequence
+ if (lastSequence != null && !lastSequence.isInlineSequence()) {
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ lastLM = curLM;
+ }
+ if (lastSequence == null) {
+ lastSequence = new KnuthSequence(false);
+ returnList.add(lastSequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" [");
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ trace.append(" +");
+ }
+ }
+ ListIterator iter = returnedList.listIterator();
+ while (iter.hasNext()) {
+ KnuthElement element = (KnuthElement) iter.next();
+ element.setPosition
+ (new NonLeafPosition(this,
+ element.getPosition()));
+ }
+ lastSequence.addAll(returnedList);
+ if (log.isTraceEnabled()) {
+ trace.append(" L");
}
- return returnList;
- } else {
- // curLM returned null because it finished;
- // just iterate once more to see if there is another child
}
}
setFinished(true);
- return null;
+ log.trace(trace);
+ return returnList.size() == 0 ? null : returnList;
+ }
+
+ /**
+ * Generate and add areas to parent area.
+ * Set size of each area. This should only create and return one
+ * inline area for any inline parent area.
+ *
+ * @param parentIter Iterator over Position information returned
+ * by this LayoutManager.
+ * @param dSpaceAdjust Factor controlling how much extra space to add
+ * in order to justify the line.
+ */
+ public void addAreas(PositionIterator parentIter,
+ LayoutContext context) {
+ addId();
+
+ setChildContext(new LayoutContext(context)); // Store current value
+
+ // If has fence, make a new leadingSS
+ /* How to know if first area created by this LM? Keep a count and
+ * reset it if getNextBreakPoss() is called again.
+ */
+ if (hasLeadingFence(bAreaCreated)) {
+ getContext().setLeadingSpace(new SpaceSpecifier(false));
+ getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
+ true);
+ } else {
+ getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
+ false);
+ }
+
+ if (getSpaceStart() != null) {
+ context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
+ }
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ // also set lastLM to be the LayoutManager which created
+ // the last Position: if the LAST_AREA flag is set in context,
+ // it must be also set in the LayoutContext given to lastLM,
+ // but unset in the LayoutContext given to the other LMs
+ LinkedList positionList = new LinkedList();
+ NonLeafPosition pos = null;
+ LayoutManager lastLM = null; // last child LM in this iterator
+ while (parentIter.hasNext()) {
+ pos = (NonLeafPosition) parentIter.next();
+ positionList.add(pos.getPosition());
+ }
+ if (pos != null) {
+ lastLM = pos.getPosition().getLM();
+ }
+
+ InlineArea parent = createArea(lastLM == null || lastLM instanceof InlineLevelLayoutManager);
+ parent.setBPD(context.getLineHeight());
+ setCurrentArea(parent);
+
+ StackingIter childPosIter
+ = new StackingIter(positionList.listIterator());
+
+ LayoutManager prevLM = null;
+ LayoutManager childLM;
+ while ((childLM = childPosIter.getNextChildLM())
+ != null) {
+ getContext().setFlags(LayoutContext.LAST_AREA,
+ context.isLastArea() && childLM == lastLM);
+ childLM.addAreas(childPosIter, getContext());
+ getContext().setLeadingSpace(getContext().getTrailingSpace());
+ getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+ prevLM = childLM;
+ }
+
+ /* If has trailing fence,
+ * resolve trailing space specs from descendants.
+ * Otherwise, propagate any trailing space specs to parent LM via
+ * the context object.
+ * If the last child LM called return ISLAST in the context object
+ * and it is the last child LM for this LM, then this must be
+ * the last area for the current LM also.
+ */
+ boolean bIsLast =
+ (getContext().isLastArea() && prevLM == lastChildLM);
+ if (hasTrailingFence(bIsLast)) {
+ addSpace(getCurrentArea(),
+ getContext().getTrailingSpace().resolve(false),
+ getContext().getSpaceAdjust());
+ context.setTrailingSpace(new SpaceSpecifier(false));
+ } else {
+ // Propagate trailing space-spec sequence to parent LM in context
+ context.setTrailingSpace(getContext().getTrailingSpace());
+ }
+ // Add own trailing space to parent context (or set on area?)
+ if (context.getTrailingSpace() != null && getSpaceEnd() != null) {
+ context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd()));
+ }
+ setTraits(bAreaCreated, !bIsLast);
+
+ parentLM.addChildArea(getCurrentArea());
+ context.setFlags(LayoutContext.LAST_AREA, bIsLast);
+ bAreaCreated = true;
+ }
+
+ public void addChildArea(Area childArea) {
+ Area parent = getCurrentArea();
+ if (getContext().resolveLeadingSpace()) {
+ addSpace(parent,
+ getContext().getLeadingSpace().resolve(false),
+ getContext().getSpaceAdjust());
+ }
+ parent.addChildArea(childArea);
}
/*
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
-import org.apache.fop.traits.SpaceVal;
import org.apache.fop.area.Area;
-import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Space;
import org.apache.fop.traits.MinOptMax;
implements InlineLevelLayoutManager {
- private static class StackingIter extends PositionIterator {
+ protected static class StackingIter extends PositionIterator {
StackingIter(Iterator parentIter) {
super(parentIter);
//private BreakPoss prevBP;
protected LayoutContext childLC;
- private LayoutManager lastChildLM = null; // Set when return last breakposs
private boolean bAreaCreated = false;
//private LayoutManager currentLM = null;
hmPrevIPD.clear();
}
- protected InlineParent createArea() {
- return new InlineParent();
- }
-
/**
* This method is called by addAreas() so IDs can be added to a page for FOs that
* support the 'id' property.
// Do nothing here, overriden in subclasses that have an 'id' property.
}
- /**
- * Generate and add areas to parent area.
- * Set size of each area. This should only create and return one
- * inline area for any inline parent area.
- *
- * @param parentIter Iterator over Position information returned
- * by this LayoutManager.
- * @param dSpaceAdjust Factor controlling how much extra space to add
- * in order to justify the line.
- */
- public void addAreas(PositionIterator parentIter,
- LayoutContext context) {
- addId();
- InlineParent parent = createArea();
- parent.setBPD(context.getLineHeight());
- parent.setOffset(0);
- setCurrentArea(parent);
-
- setChildContext(new LayoutContext(context)); // Store current value
-
- // If has fence, make a new leadingSS
- /* How to know if first area created by this LM? Keep a count and
- * reset it if getNextBreakPoss() is called again.
- */
- if (hasLeadingFence(bAreaCreated)) {
- getContext().setLeadingSpace(new SpaceSpecifier(false));
- getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
- true);
- } else {
- getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
- false);
- }
-
- if (getSpaceStart() != null) {
- context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
- }
-
- // "unwrap" the NonLeafPositions stored in parentIter
- // and put them in a new list;
- // also set lastLM to be the LayoutManager which created
- // the last Position: if the LAST_AREA flag is set in context,
- // it must be also set in the LayoutContext given to lastLM,
- // but unset in the LayoutContext given to the other LMs
- LinkedList positionList = new LinkedList();
- NonLeafPosition pos;
- LayoutManager lastLM = null; // last child LM in this iterator
- while (parentIter.hasNext()) {
- pos = (NonLeafPosition) parentIter.next();
- lastLM = pos.getPosition().getLM();
- positionList.add(pos.getPosition());
- }
-
- StackingIter childPosIter
- = new StackingIter(positionList.listIterator());
-
- LayoutManager prevLM = null;
- InlineLevelLayoutManager childLM;
- while ((childLM = (InlineLevelLayoutManager) childPosIter.getNextChildLM())
- != null) {
- getContext().setFlags(LayoutContext.LAST_AREA,
- context.isLastArea() && childLM == lastLM);
- childLM.addAreas(childPosIter, getContext());
- getContext().setLeadingSpace(getContext().getTrailingSpace());
- getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
- prevLM = childLM;
- }
-
- /* If has trailing fence,
- * resolve trailing space specs from descendants.
- * Otherwise, propagate any trailing space specs to parent LM via
- * the context object.
- * If the last child LM called return ISLAST in the context object
- * and it is the last child LM for this LM, then this must be
- * the last area for the current LM also.
- */
- boolean bIsLast =
- (getContext().isLastArea() && prevLM == lastChildLM);
- if (hasTrailingFence(bIsLast)) {
- addSpace(getCurrentArea(),
- getContext().getTrailingSpace().resolve(false),
- getContext().getSpaceAdjust());
- context.setTrailingSpace(new SpaceSpecifier(false));
- } else {
- // Propagate trailing space-spec sequence to parent LM in context
- context.setTrailingSpace(getContext().getTrailingSpace());
- }
- // Add own trailing space to parent context (or set on area?)
- if (context.getTrailingSpace() != null && getSpaceEnd() != null) {
- context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd()));
- }
- setTraits(bAreaCreated, !bIsLast);
-
- parentLM.addChildArea(getCurrentArea());
- context.setFlags(LayoutContext.LAST_AREA, bIsLast);
- bAreaCreated = true;
- }
-
protected Area getCurrentArea() {
return currentArea;
}
}
- public void addChildArea(Area childArea) {
- // Make sure childArea is inline area
- if (childArea instanceof InlineArea) {
- Area parent = getCurrentArea();
- if (getContext().resolveLeadingSpace()) {
- addSpace(parent,
- getContext().getLeadingSpace().resolve(false),
- getContext().getSpaceAdjust());
- }
- parent.addChildArea(childArea);
- }
- }
-
protected void setChildContext(LayoutContext lc) {
childLC = lc;
}
}
}
- public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) {
- InlineLevelLayoutManager curLM;
-
- // the list returned by child LM
- LinkedList returnedList;
- KnuthElement returnedElement;
-
- // the list which will be returned to the parent LM
- LinkedList returnList = new LinkedList();
-
- SpaceSpecifier leadingSpace = lc.getLeadingSpace();
-
- if (lc.startsNewArea()) {
- // First call to this LM in new parent "area", but this may
- // not be the first area created by this inline
- childLC = new LayoutContext(lc);
- lc.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
-
- // Check for "fence"
- if (hasLeadingFence(!lc.isFirstArea())) {
- // Reset leading space sequence for child areas
- leadingSpace = new SpaceSpecifier(false);
- }
- // Reset state variables
- clearPrevIPD(); // Clear stored prev content dimensions
- }
-
- while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
- // get KnuthElements from curLM
- returnedList = curLM.getNextKnuthElements(lc, alignment);
- if (returnedList != null) {
- // "wrap" the Position stored in each element of returnedList
- ListIterator listIter = returnedList.listIterator();
- while (listIter.hasNext()) {
- returnedElement = (KnuthElement) listIter.next();
- returnedElement.setPosition
- (new NonLeafPosition(this,
- returnedElement.getPosition()));
- returnList.add(returnedElement);
- }
- setFinished(curLM.isFinished() && (getChildLM() == null));
- return returnList;
- } else {
- // curLM returned null because it finished;
- // just iterate once more to see if there is another child
- }
- }
- setFinished(true);
- return null;
- }
-
public List addALetterSpaceTo(List oldList) {
// old list contains only a box, or the sequence: box penalty glue box
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
+import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
+import org.apache.fop.area.inline.InlineArea;
import java.util.ListIterator;
import java.util.List;
public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
int indent) {
- super();
+ super(true);
layoutManager = llm;
textAlignment = alignment;
textAlignmentLast = alignmentLast;
}
}
+ private void addALetterSpace() {
+ KnuthBox prevBox = (KnuthBox) removeLast();
+ LinkedList oldList = new LinkedList();
+ // if there are two consecutive KnuthBoxes the
+ // first one does not represent a whole word,
+ // so it must be given one more letter space
+ if (!prevBox.isAuxiliary()) {
+ // if letter spacing is constant,
+ // only prevBox needs to be replaced;
+ oldList.add(prevBox);
+ } else {
+ // prevBox is the last element
+ // in the sub-sequence
+ // <box> <aux penalty> <aux glue> <aux box>
+ // the letter space is added to <aux glue>,
+ // while the other elements are not changed
+ oldList.add(prevBox);
+ // TODO check if this is the correct place; merge was not correct
+ oldList.addFirst((KnuthBox) removeLast());
+ oldList.addFirst((KnuthGlue) removeLast());
+ oldList.addFirst((KnuthPenalty) removeLast());
+ }
+ // adding a letter space could involve, according to the text
+ // represented by oldList, replacing a glue element or adding
+ // new elements
+ addAll(((InlineLevelLayoutManager)
+ prevBox.getLayoutManager())
+ .addALetterSpaceTo(oldList));
+ if (((KnuthInlineBox) prevBox).isAnchor()) {
+ // prevBox represents a footnote citation: copy footnote info
+ // from prevBox to the new box
+ KnuthInlineBox newBox = (KnuthInlineBox) getLast();
+ newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+ }
+ }
}
private class LineBreakingAlgorithm extends BreakingAlgorithm {
}
//PHASE 2: Create line breaks
- return findOptimalLineBreakingPoints(alignment);
+ return createLineBreaks(alignment);
/*
LineBreakPosition lbp = null;
if (breakpoints == null) {
LayoutContext inlineLC = new LayoutContext(context);
InlineLevelLayoutManager curLM;
- KnuthElement thisElement = null;
LinkedList returnedList = null;
iLineWidth = context.getStackLimit().opt;
// convert all the text in a sequence of paragraphs made
// of KnuthBox, KnuthGlue and KnuthPenalty objects
boolean bPrevWasKnuthBox = false;
- KnuthBox prevBox = null;
- Paragraph knuthPar = new Paragraph(this,
- bTextAlignment, bTextAlignmentLast,
- textIndent.getValue());
- knuthPar.startParagraph(availIPD.opt);
+ StringBuffer trace = new StringBuffer("LineLM:");
+
+ Paragraph lastPar = null;
+
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
if ((returnedList
= curLM.getNextKnuthElements(inlineLC,
if (returnedList.size() == 0) {
continue;
}
- // look at the first element
- thisElement = (KnuthElement) returnedList.getFirst();
- if (thisElement.isBox() && !thisElement.isAuxiliary()
- && bPrevWasKnuthBox) {
- prevBox = (KnuthBox) knuthPar.removeLast();
- LinkedList oldList = new LinkedList();
- // if there are two consecutive KnuthBoxes the
- // first one does not represent a whole word,
- // so it must be given one more letter space
- if (!prevBox.isAuxiliary()) {
- // if letter spacing is constant,
- // only prevBox needs to be replaced;
- oldList.add(prevBox);
- } else {
- // prevBox is the last element
- // in the sub-sequence
- // <box> <aux penalty> <aux glue> <aux box>
- // the letter space is added to <aux glue>,
- // while the other elements are not changed
- oldList.add(prevBox);
- oldList.addFirst((KnuthGlue) knuthPar.removeLast());
- oldList.addFirst((KnuthPenalty) knuthPar.removeLast());
- oldList.addFirst((KnuthBox) knuthPar.removeLast());
+ // does the first element of the first paragraph add to an existing word?
+ if (lastPar != null) {
+ KnuthSequence firstSeq = (KnuthSequence) returnedList.getFirst();
+ if (!firstSeq.isInlineSequence()) {
+ log.error("Expect inline sequence as first sequence when last paragraph is not null");
}
- // adding a letter space could involve, according to the text
- // represented by oldList, replacing a glue element or adding
- // new elements
- knuthPar.addAll(((InlineLevelLayoutManager)
- prevBox.getLayoutManager())
- .addALetterSpaceTo(oldList));
- if (((KnuthInlineBox) prevBox).isAnchor()) {
- // prevBox represents a footnote citation: copy footnote info
- // from prevBox to the new box
- KnuthInlineBox newBox = (KnuthInlineBox) knuthPar.getLast();
- newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+ KnuthElement thisElement = (KnuthElement) firstSeq.get(0);
+ if (thisElement.isBox() && !thisElement.isAuxiliary()
+ && bPrevWasKnuthBox) {
+ lastPar.addALetterSpace();
}
}
- // look at the last element
- KnuthElement lastElement = (KnuthElement) returnedList.getLast();
- boolean bForceLinefeed = false;
- if (lastElement.isBox()) {
- bPrevWasKnuthBox = true;
- } else {
- bPrevWasKnuthBox = false;
- if (lastElement.isPenalty()
- && ((KnuthPenalty) lastElement).getP()
- == -KnuthPenalty.INFINITE) {
- // a penalty item whose value is -inf
- // represents a preserved linefeed,
- // wich forces a line break
- bForceLinefeed = true;
- returnedList.removeLast();
- }
- }
+ // loop over the KnuthSequences in returnedList
+ ListIterator iter = returnedList.listIterator();
+ while (iter.hasNext()) {
+ KnuthSequence sequence = (KnuthSequence) iter.next();
+ // the sequence contains inline Knuth elements
+ if (sequence.isInlineSequence()) {
+ // look at the last element
+ KnuthElement lastElement = (KnuthElement) sequence.getLast();
+ bPrevWasKnuthBox = lastElement.isBox();
+
+ // if last paragraph is open, add the new elements to the paragraph
+ // else this is the last paragraph
+ if (lastPar == null) {
+ lastPar = new Paragraph(this,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue());
+ lastPar.startParagraph(availIPD.opt);
+ if (log.isTraceEnabled()) {
+ trace.append(" [");
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ trace.append(" +");
+ }
+ }
+ lastPar.addAll(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" I");
+ }
- // add the new elements to the paragraph
- knuthPar.addAll(returnedList);
- if (bForceLinefeed) {
- if (knuthPar.size() == 0) {
- //only a forced linefeed on this line
- //-> compensate with a zero width box
- knuthPar.add(new KnuthInlineBox(0, 0, 0, 0,
- null, false));
+ // finish last paragraph if it was closed with a linefeed
+ if (lastElement.isPenalty()
+ && ((KnuthPenalty) lastElement).getP()
+ == -KnuthPenalty.INFINITE) {
+ // a penalty item whose value is -inf
+ // represents a preserved linefeed,
+ // wich forces a line break
+ lastPar.removeLast();
+ if (lastPar.size() == 0) {
+ //only a forced linefeed on this line
+ //-> compensate with a zero width box
+ lastPar.add(new KnuthInlineBox(0, 0, 0, 0,
+ null, false));
+ }
+ lastPar.endParagraph();
+ lastPar = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ bPrevWasKnuthBox = false;
+ }
+ } else { // the sequence is a block sequence
+/* // "wrap" the Position stored in each element of returnedList
+ ListIterator listIter = sequence.listIterator();
+ while (listIter.hasNext()) {
+ KnuthElement returnedElement = (KnuthElement) listIter.next();
+ returnedElement.setPosition
+ (new NonLeafPosition(this,
+ returnedElement.getPosition()));
+ }
+*/ knuthParagraphs.add(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" B");
+ }
}
- knuthPar.endParagraph();
- knuthPar = new Paragraph(this,
- bTextAlignment, bTextAlignmentLast,
- textIndent.getValue());
- knuthPar.startParagraph(availIPD.opt);
- bPrevWasKnuthBox = false;
- }
+ } // end of loop over returnedList
} else {
// curLM returned null; this can happen
// if it has nothing more to layout,
// if there are other children
}
}
- knuthPar.endParagraph();
- ElementListObserver.observe(knuthPar, "line", null);
+ if (lastPar != null) {
+ lastPar.endParagraph();
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ log.trace(trace);
+ // TODO Do we need more of these lines?
+ ElementListObserver.observe(lastPar, "line", null);
}
/**
/**
* Phase 2 of Knuth algorithm: find optimal break points.
- * @param alignment alignmenr of the paragraph
+ * @param alignment alignment of the paragraph
* @return a list of Knuth elements representing broken lines
*/
- private LinkedList findOptimalLineBreakingPoints(int alignment) {
+ private LinkedList createLineBreaks(int alignment) {
// find the optimal line breaking points for each paragraph
ListIterator paragraphsIterator
= knuthParagraphs.listIterator(knuthParagraphs.size());
- Paragraph currPar = null;
- LineBreakingAlgorithm alg;
lineLayoutsList = new ArrayList(knuthParagraphs.size());
while (paragraphsIterator.hasPrevious()) {
- lineLayouts = new LineLayoutPossibilities();
- currPar = (Paragraph) paragraphsIterator.previous();
- double maxAdjustment = 1;
- int iBPcount = 0;
- alg = new LineBreakingAlgorithm(alignment,
- bTextAlignment, bTextAlignmentLast,
- textIndent.getValue(), currPar.lineFiller.opt,
- lineHeight, lead, follow, middleShift,
- (knuthParagraphs.indexOf(currPar) == 0),
- this);
-
- if (hyphProps.hyphenate == EN_TRUE) {
- findHyphenationPoints(currPar);
- }
-
- // first try
- boolean bHyphenationAllowed = false;
- alg.setConstantLineWidth(iLineWidth);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, false, bHyphenationAllowed);
- if (iBPcount == 0 || alignment == EN_JUSTIFY) {
- // if the first try found a set of breaking points, save them
- if (iBPcount > 0) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(false);
- } else {
- // the first try failed
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
- }
-
- // now try something different
- log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
- if (hyphProps.hyphenate == EN_TRUE) {
- // consider every hyphenation point as a legal break
- bHyphenationAllowed = true;
- } else {
- // try with a higher threshold
- maxAdjustment = 5;
- }
-
- if ((iBPcount
- = alg.findBreakingPoints(currPar,
- maxAdjustment, false, bHyphenationAllowed)) == 0) {
- // the second try failed too, try with a huge threshold
- // and force the algorithm to find
- // a set of breaking points
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
- + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
- maxAdjustment = 20;
- iBPcount
- = alg.findBreakingPoints(currPar,
- maxAdjustment, true, bHyphenationAllowed);
- }
-
- // use non-hyphenated breaks, when possible
- lineLayouts.restorePossibilities();
-
- /* extension (not in the XSL FO recommendation): if vertical alignment
- is justify and the paragraph has only one layout, try using
- shorter or longer lines */
- //TODO This code snippet is disabled. Reenable?
- if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
- //System.out.println("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
- //System.out.println(" layouts with fewer lines? " + lineLayouts.canUseLessLines());
- if (!lineLayouts.canUseMoreLines()) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(true);
- // try with shorter lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 0.95);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, bHyphenationAllowed);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
- }
- if (!lineLayouts.canUseLessLines()) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(true);
- // try with longer lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 1.05);
- alg.setConstantLineWidth(iLineWidth);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, bHyphenationAllowed);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
- }
- //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
- //System.out.println(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
- }
+ KnuthSequence seq = (KnuthSequence) paragraphsIterator.previous();
+ if (!seq.isInlineSequence()) {
+ lineLayouts = createBlockLineBreak(seq);
+ } else {
+ lineLayouts = findOptimalBreakingPoints(alignment, (Paragraph) seq);
}
lineLayoutsList.add(0, lineLayouts);
}
-
setFinished(true);
//Post-process the line breaks found
return postProcessLineBreaks(alignment);
}
+ /**
+ * create a single line layout possibility with a single linebreak
+ * for a block sequence
+ * @param seq the Knuth sequence for which the linebreak is created
+ * @return the line layout possibilities for the paragraph
+ */
+ private LineLayoutPossibilities createBlockLineBreak(KnuthSequence seq) {
+ lineLayouts = new LineLayoutPossibilities();
+ lineLayouts.addPossibility(1,0);
+ int lineHeight = 0, lineStretch = 0, lineShrink = 0;
+ ListIterator seqIterator = seq.listIterator();
+ while (seqIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) seqIterator.next();
+ lineHeight += element.getW();
+ if (element.isGlue()) {
+ lineStretch += element.getY();
+ lineShrink += element.getZ();
+ }
+ }
+ LineBreakPosition lbp = new LineBreakPosition(this,
+ knuthParagraphs.indexOf(seq), seq.size() - 1,
+ lineShrink, lineStretch, 0, 0, 0, 0, lineHeight,
+ 0, 0, 0, 0);
+ lineLayouts.addBreakPosition(lbp, 0);
+ return lineLayouts;
+ }
+
+ /**
+ * Fint the optimal linebreaks for a paragraph
+ * @param alignment alignment of the paragraph
+ * @param currPar the Paragraph for which the linebreaks are found
+ * @return the line layout possibilities for the paragraph
+ */
+ private LineLayoutPossibilities findOptimalBreakingPoints(int alignment, Paragraph currPar) {
+ lineLayouts = new LineLayoutPossibilities();
+ double maxAdjustment = 1;
+ int iBPcount = 0;
+ LineBreakingAlgorithm alg = new LineBreakingAlgorithm(alignment,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue(), currPar.lineFiller.opt,
+ lineHeight, lead, follow, middleShift,
+ (knuthParagraphs.indexOf(currPar) == 0),
+ this);
+
+ if (hyphProps.hyphenate == EN_TRUE) {
+ findHyphenationPoints(currPar);
+ }
+
+ // first try
+ boolean bHyphenationAllowed = false;
+ alg.setConstantLineWidth(iLineWidth);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, false, bHyphenationAllowed);
+ if (iBPcount == 0 || alignment == EN_JUSTIFY) {
+ // if the first try found a set of breaking points, save them
+ if (iBPcount > 0) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(false);
+ } else {
+ // the first try failed
+ log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
+ }
+
+ // now try something different
+ log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
+ if (hyphProps.hyphenate == EN_TRUE) {
+ // consider every hyphenation point as a legal break
+ bHyphenationAllowed = true;
+ } else {
+ // try with a higher threshold
+ maxAdjustment = 5;
+ }
+
+ if ((iBPcount
+ = alg.findBreakingPoints(currPar,
+ maxAdjustment, false, bHyphenationAllowed)) == 0) {
+ // the second try failed too, try with a huge threshold
+ // and force the algorithm to find
+ // a set of breaking points
+ log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
+ + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
+ maxAdjustment = 20;
+ iBPcount
+ = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ }
+
+ // use non-hyphenated breaks, when possible
+ lineLayouts.restorePossibilities();
+
+ /* extension (not in the XSL FO recommendation): if vertical alignment
+ is justify and the paragraph has only one layout, try using
+ shorter or longer lines */
+ //TODO This code snippet is disabled. Reenable?
+ if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
+ //System.out.println("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
+ //System.out.println(" layouts with fewer lines? " + lineLayouts.canUseLessLines());
+ if (!lineLayouts.canUseMoreLines()) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(true);
+ // try with shorter lines
+ int savedLineWidth = iLineWidth;
+ iLineWidth = (int) (iLineWidth * 0.95);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
+ }
+ if (!lineLayouts.canUseLessLines()) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(true);
+ // try with longer lines
+ int savedLineWidth = iLineWidth;
+ iLineWidth = (int) (iLineWidth * 1.05);
+ alg.setConstantLineWidth(iLineWidth);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
+ }
+ //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
+ //System.out.println(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
+ }
+ }
+ return lineLayouts;
+ }
+
private LinkedList postProcessLineBreaks(int alignment) {
LinkedList returnList = new LinkedList();
}
lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
-
- if (alignment == EN_JUSTIFY) {
+ KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(p);
+
+ if (seq.isInlineSequence() && alignment == EN_JUSTIFY) {
/* justified vertical alignment (not in the XSL FO recommendation):
create a multi-layout sequence whose elements will contain
a conventional Position */
// create a list of the FootnoteBodyLM handling footnotes
// whose citations are in this line
LinkedList footnoteList = new LinkedList();
- ListIterator elementIterator = ((Paragraph) knuthParagraphs.get(p)).listIterator(startIndex);
+ ListIterator elementIterator = seq.listIterator(startIndex);
while (elementIterator.nextIndex() <= endIndex) {
KnuthElement element = (KnuthElement) elementIterator.next();
if (element instanceof KnuthInlineBox
&& ((KnuthInlineBox) element).isAnchor()) {
footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
+ } else if (element instanceof KnuthBlockBox) {
+ footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs());
}
}
startIndex = endIndex + 1;
- returnList.add(new KnuthBlockBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
- footnoteList, lineLayouts.getChosenPosition(i), false));
+ LineBreakPosition lbp = (LineBreakPosition) lineLayouts.getChosenPosition(i);
+ returnList.add(new KnuthBlockBox(lbp.lineHeight, footnoteList, lbp, false));
+ /* // add stretch and shrink to the returnlist
+ if (!seq.isInlineSequence()
+ && lbp.availableStretch != 0 || lbp.availableShrink != 0) {
+ returnList.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+ false, new Position(this), false));
+ returnList.add(new KnuthGlue(0, lbp.availableStretch, lbp.availableShrink,
+ new Position(this), false));
+ }
+ */
}
}
}
while (parentIter.hasNext()) {
Position pos = (Position) parentIter.next();
if (pos instanceof LineBreakPosition) {
- ListIterator paragraphIterator = null;
+ ListIterator seqIterator = null;
KnuthElement tempElement = null;
// the TLM which created the last KnuthElement in this line
LayoutManager lastLM = null;
lc.setBottomShift(lbp.bottomShift);
iCurrParIndex = lbp.iParIndex;
- Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex);
+ KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex);
iEndElement = lbp.getLeafPos();
- // ignore the first elements added by the LineLayoutManager
- iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
-
- // ignore the last elements added by the LineLayoutManager
- iEndElement -= (iEndElement == (currPar.size() - 1))
+ if (seq instanceof Paragraph) {
+ Paragraph currPar = (Paragraph) seq;
+ // ignore the first elements added by the LineLayoutManager
+ iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
+
+ // ignore the last elements added by the LineLayoutManager
+ iEndElement -= (iEndElement == (currPar.size() - 1))
? currPar.ignoreAtEnd : 0;
-
+ }
+
// ignore the last element in the line if it is a KnuthGlue object
- paragraphIterator = currPar.listIterator(iEndElement);
- tempElement = (KnuthElement) paragraphIterator.next();
+ seqIterator = seq.listIterator(iEndElement);
+ tempElement = (KnuthElement) seqIterator.next();
if (tempElement.isGlue()) {
iEndElement --;
// this returns the same KnuthElement
- paragraphIterator.previous();
- tempElement = (KnuthElement) paragraphIterator.previous();
+ seqIterator.previous();
+ tempElement = (KnuthElement) seqIterator.previous();
}
lastLM = tempElement.getLayoutManager();
// ignore KnuthGlue and KnuthPenalty objects
// at the beginning of the line
- paragraphIterator = currPar.listIterator(iStartElement);
- tempElement = (KnuthElement) paragraphIterator.next();
- while (!tempElement.isBox() && paragraphIterator.hasNext()) {
- tempElement = (KnuthElement) paragraphIterator.next();
+ seqIterator = seq.listIterator(iStartElement);
+ tempElement = (KnuthElement) seqIterator.next();
+ while (!tempElement.isBox() && seqIterator.hasNext()) {
+ tempElement = (KnuthElement) seqIterator.next();
iStartElement ++;
}
// Add the inline areas to lineArea
PositionIterator inlinePosIter
- = new KnuthPossPosIter(currPar, iStartElement,
+ = new KnuthPossPosIter(seq, iStartElement,
iEndElement + 1);
iStartElement = lbp.getLeafPos() + 1;
- if (iStartElement == currPar.size()) {
+ if (iStartElement == seq.size()) {
// advance to next paragraph
iStartElement = 0;
}
lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
}
parentLM.addChildArea(lineArea);
- } else {
+/* } else if (pos instanceof NonLeafPosition) {
+ // LineBreakPosition inside a nested block;
+ // go down the LM stack again;
+ // collect all consecutive NonLeafPosition objects,
+ // "unwrap" them and put the child positions in a new list.
+ LinkedList positionList = new LinkedList();
+ Position innerPosition;
+ innerPosition = ((NonLeafPosition) pos).getPosition();
+ positionList.add(innerPosition);
+ while (parentIter.hasNext()) {
+ pos = (Position) parentIter.getPos(parentIter.peekNext());
+ if (!(pos instanceof NonLeafPosition)) {
+ break;
+ }
+ pos = (Position) parentIter.next();
+ innerPosition = ((NonLeafPosition) pos).getPosition();
+ positionList.add(innerPosition);
+ }
+
+ // do we have the last LM?
+ LayoutManager lastLM = null;
+ if (!parentIter.hasNext()) {
+ lastLM = innerPosition.getLM();
+ }
+
+ // this may be wrong; not all areas belong inside a single line area
+ // see InlineStackingLM.addChildArea
+ LineArea lineArea = new LineArea();
+ setCurrentArea(lineArea);
+ setChildContext(lc);
+
+ PositionIterator childPosIter = new StackingIter(positionList.listIterator());
+ LayoutContext blocklc = new LayoutContext(0);
+ blocklc.setLeadingSpace(new SpaceSpecifier(true));
+ blocklc.setTrailingSpace(new SpaceSpecifier(false));
+ blocklc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+ while ((childLM = childPosIter.getNextChildLM()) != null) {
+ // set last area flag
+ blocklc.setFlags(LayoutContext.LAST_AREA,
+ (context.isLastArea() && childLM == lastLM));
+ blocklc.setStackLimit(context.getStackLimit());
+ // Add the line areas to Area
+ childLM.addAreas(childPosIter, blocklc);
+ blocklc.setLeadingSpace(blocklc.getTrailingSpace());
+ blocklc.setTrailingSpace(new SpaceSpecifier(false));
+ }
+ parentLM.addChildArea(lineArea);
+*/ } else {
// pos was the Position inside a penalty item, nothing to do
}
}
setCurrentArea(null); // ?? necessary
}
+
+ public void addChildArea(Area childArea) {
+ // Make sure childArea is inline area
+ if (childArea instanceof InlineArea) {
+ Area parent = getCurrentArea();
+ if (getContext().resolveLeadingSpace()) {
+ addSpace(parent,
+ getContext().getLeadingSpace().resolve(false),
+ getContext().getSpaceAdjust());
+ }
+ parent.addChildArea(childArea);
+ }
+ }
+
}
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
public LinkedList getNextKnuthElements(LayoutContext context,
int alignment) {
LinkedList returnList = new LinkedList();
+ KnuthSequence sequence = new KnuthSequence(true);
+ returnList.add(sequence);
while (iNextStart < textArray.length) {
if (textArray[iNextStart] == SPACE
// normal, breaking space
// or non-breaking space
if (textArray[iNextStart] == NBSPACE) {
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, vecAreaInfo.size() - 1),
false));
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
- 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), true));
iNextStart ++;
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
- 3 * wordSpaceIPD.opt, 0,
new LeafPosition(this, -1), true));
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
wordSpaceIPD.max - wordSpaceIPD.opt,
wordSpaceIPD.opt - wordSpaceIPD.min,
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
wordSpaceIPD.max - wordSpaceIPD.opt, 0,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
wordSpaceIPD.max - wordSpaceIPD.opt,
wordSpaceIPD.opt - wordSpaceIPD.min,
iNextStart ++;
} else if (textArray[iNextStart] == NEWLINE) {
// linefeed; this can happen when linefeed-treatment="preserve"
- // add a penalty item to the list and return
- returnList.add
+ // add a penalty item to the list and start a new sequence
+ sequence.add
(new KnuthPenalty(0, -KnuthElement.INFINITE,
false, null, false));
+ sequence = new KnuthSequence(true);
+ returnList.add(sequence);
iNextStart ++;
- return returnList;
} else {
// the beginning of a word
iThisStart = iNextStart;
if (letterSpaceIPD.min == letterSpaceIPD.max) {
// constant letter space; simply return a box
// whose width includes letter spaces
- returnList.add
+ sequence.add
(new KnuthInlineBox(wordIPD.opt, lead, total, middle,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
} else {
// adjustable letter space;
// some other KnuthElements are needed
- returnList.add
+ sequence.add
(new KnuthInlineBox(wordIPD.opt - iLetterSpaces * letterSpaceIPD.opt,
lead, total, middle,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(iLetterSpaces * letterSpaceIPD.opt,
iLetterSpaces * (letterSpaceIPD.max - letterSpaceIPD.opt),
iLetterSpaces * (letterSpaceIPD.opt - letterSpaceIPD.min),
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthInlineBox(0, lead, total, middle,
new LeafPosition(this, -1), true));
}
&& iTempStart < textArray.length
&& textArray[iTempStart] != SPACE
&& textArray[iTempStart] != NBSPACE) {
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
new LeafPosition(this, -1), false));
- returnList.add
+ sequence.add
(new KnuthGlue(letterSpaceIPD.opt,
letterSpaceIPD.max - letterSpaceIPD.opt,
letterSpaceIPD.opt - letterSpaceIPD.min,
}
} // end of while
setFinished(true);
- if (returnList.size() > 0) {
+ if (sequence.size() > 0) {
return returnList;
} else {
return null;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
}
/**
- * @see org.apache.fop.render.Renderer
+ * @see org.apache.fop.render.Renderer#setupFontInfo(FontInfo)
*/
public abstract void setupFontInfo(FontInfo fontInfo);
/**
- * @see org.apache.fop.render.Renderer
+ * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
*/
public void setUserAgent(FOUserAgent agent) {
userAgent = agent;
}
- /** @see org.apache.fop.render.Renderer */
+ /** @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */
public void startRenderer(OutputStream outputStream)
throws IOException { }
- /** @see org.apache.fop.render.Renderer */
+ /** @see org.apache.fop.render.Renderer#stopRenderer() */
public void stopRenderer()
throws IOException { }
}
/**
- * @see org.apache.fop.render.Renderer
+ * @see org.apache.fop.render.Renderer#processOffDocumentItem(OffDocumentItem)
*/
public void processOffDocumentItem(OffDocumentItem oDI) { }
* page should not be rendered. The page will be rendered at a later time
* by the call to render page.
*
- * @see org.apache.fop.render.Renderer
+ * @see org.apache.fop.render.Renderer#preparePage(PageViewport)
*/
public void preparePage(PageViewport page) { }
return sb.toString();
}
- /** @see org.apache.fop.render.Renderer */
+ /** @see org.apache.fop.render.Renderer#startPageSequence(LineArea) */
public void startPageSequence(LineArea seqTitle) {
//do nothing
}
// normally this would be overriden to create a page in the
// output
- /** @see org.apache.fop.render.Renderer */
+ /** @see org.apache.fop.render.Renderer#renderPage(PageViewport) */
public void renderPage(PageViewport page)
throws IOException, FOPException {
+ parent.getStartIndent()
+ line.getStartIndent();
renderLineArea(line);
+ InlineArea child = (InlineArea) line.getInlineAreas().get(0);
currentBPPosition += line.getAllocBPD();
}
currentIPPosition = saveIP;
renderText((TextArea) inlineArea);
} else if (inlineArea instanceof InlineParent) {
renderInlineParent((InlineParent) inlineArea);
+ } else if (inlineArea instanceof InlineBlockParent) {
+ renderInlineBlockParent((InlineBlockParent) inlineArea);
} else if (inlineArea instanceof Space) {
renderInlineSpace((Space) inlineArea);
} else if (inlineArea instanceof Character) {
}
- /** @see org.apache.fop.render.Renderer */
protected void renderCharacter(Character ch) {
currentIPPosition += ch.getAllocIPD();
}
- /** @see org.apache.fop.render.Renderer */
protected void renderInlineSpace(Space space) {
// an inline space moves the inline progression position
// for the current block by the width or height of the space
currentIPPosition += space.getAllocIPD();
}
- /** @see org.apache.fop.render.Renderer */
protected void renderLeader(Leader area) {
currentIPPosition += area.getAllocIPD();
}
- /** @see org.apache.fop.render.Renderer */
protected void renderText(TextArea text) {
currentIPPosition += text.getAllocIPD();
}
- /** @see org.apache.fop.render.Renderer */
protected void renderInlineParent(InlineParent ip) {
int saveIP = currentIPPosition;
Iterator iter = ip.getChildAreas().iterator();
currentIPPosition = saveIP + ip.getAllocIPD();
}
- /** @see org.apache.fop.render.Renderer */
+ protected void renderInlineBlockParent(InlineBlockParent ibp) {
+ // For inline content the BP position is updated by the enclosing line area
+ int saveBP = currentBPPosition;
+ renderBlock(ibp.getChildArea());
+ currentBPPosition = saveBP;
+ }
+
protected void renderViewport(Viewport viewport) {
Area content = viewport.getContent();
int saveBP = currentBPPosition;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
atts.clear();
addAreaAttributes(line);
addTraitAttributes(line);
+ addAttribute("vpos", currentBPPosition);
startElement("lineArea", atts);
super.renderLineArea(line);
endElement("lineArea");
}
/**
- * @see org.apache.fop.render.Renderer#renderViewport(Viewport)
+ * @see org.apache.fop.render.AbstractRenderer#renderViewport(Viewport)
*/
protected void renderViewport(Viewport viewport) {
atts.clear();
}
/**
- * @see org.apache.fop.render.Renderer#renderContainer(Container)
+ * @see org.apache.fop.render.AbstractRenderer#renderContainer(Container)
*/
public void renderContainer(Container cont) {
startElement("container");
}
/**
- * @see org.apache.fop.render.Renderer#renderCharacter(Character)
+ * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
*/
protected void renderCharacter(org.apache.fop.area.inline.Character ch) {
atts.clear();
}
/**
- * @see org.apache.fop.render.Renderer#renderInlineSpace(Space)
+ * @see org.apache.fop.render.AbstractRenderer#renderInlineSpace(Space)
*/
protected void renderInlineSpace(Space space) {
atts.clear();
}
/**
- * @see org.apache.fop.render.Renderer#renderText(TextArea)
+ * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
*/
protected void renderText(TextArea text) {
atts.clear();
}
/**
- * @see org.apache.fop.render.Renderer#renderInlineParent(InlineParent)
+ * @see org.apache.fop.render.AbstractRenderer#renderInlineParent(InlineParent)
*/
protected void renderInlineParent(InlineParent ip) {
atts.clear();
endElement("inlineparent");
}
+ protected void renderInlineBlockParent(InlineBlockParent ibp) {
+ atts.clear();
+ addTraitAttributes(ibp);
+ startElement("inlineblockparent", atts);
+ super.renderInlineBlockParent(ibp);
+ endElement("inlineblockparent");
+ }
+
/**
- * @see org.apache.fop.render.Renderer#renderLeader(Leader)
+ * @see org.apache.fop.render.AbstractRenderer#renderLeader(Leader)
*/
protected void renderLeader(Leader area) {
String style = "solid";
super.renderLeader(area);
}
- /** @see org.apache.fop.render.AbstractRenderer */
+ /** @see org.apache.fop.render.AbstractRenderer#getMimeType() */
public String getMimeType() {
return XML_MIME_TYPE;
}
table-fixed2.xml
font-size-absolute.xml
font-size-relative.xml
+inline-block1.xml
+inline-block2.xml
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2005 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$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks block content in fo:inline. It stresses the nesting by letting the fo:inline have a background color.
+ </p>
+ </info>
+ <fo>
+ <fo:root
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simpleA4"
+ page-height="29.7cm" page-width="21cm"
+ margin-top="2cm" margin-bottom="2cm"
+ margin-left="2cm" margin-right="2cm">
+ <fo:region-body
+ margin-top="1.2in" margin-bottom="1in"
+ margin-left="1in" margin-right="1in"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="simpleA4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block language="en" country="US"
+ hyphenate="true" text-align="justify">
+ The appropriate values of the parameters can be obtained from <fo:inline background-color="lightgray">the following equations:
+ <fo:block>
+ w1 + w2 + w3 = W,
+ </fo:block>
+ <fo:block>
+ y1 + y2 + y3 = Y,
+ </fo:block>where W and Y follow from the previous rule</fo:inline>. This completes our argument.
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ </checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2005 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$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks block content in fo:inline. It stresses the nesting by letting the fo:inline have a background color.
+ </p>
+ </info>
+ <fo>
+ <fo:root
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simpleA4"
+ page-height="29.7cm" page-width="21cm"
+ margin-top="2cm" margin-bottom="2cm"
+ margin-left="2cm" margin-right="2cm">
+ <fo:region-body
+ margin-top="1.2in" margin-bottom="1in"
+ margin-left="1in" margin-right="1in"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="simpleA4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block language="en" country="US"
+ hyphenate="true" text-align="justify">
+ The appropriate values of the parameters can be obtained from <fo:inline background-color="lightgray">the following table:
+ <fo:block>
+ <fo:table table-layout="fixed" border-collapse="separate" margin="0pt" border="solid 5pt" padding="5pt" width="4in + 10pt + 10pt" background-color="lightgray">
+ <fo:table-column column-width="2in"/>
+ <fo:table-column column-width="2in"/>
+ <fo:table-body start-indent="0pt" end-indent="0pt">
+ <fo:table-row>
+ <fo:table-cell>
+ <fo:block>w1 + w2 + w3</fo:block>
+ </fo:table-cell>
+ <fo:table-cell background-color="yellow">
+ <fo:block>W</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell background-color="orange">
+ <fo:block>y1 + y2 + y3</fo:block>
+ </fo:table-cell>
+ <fo:table-cell>
+ <fo:block>Y</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ </fo:block>where W and Y follow from the previous rule</fo:inline>. This completes our argument.
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ </checks>
+</testcase>