123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.layoutmgr.list;
-
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.ListIterator;
- import java.util.Stack;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
-
- import org.apache.fop.area.Area;
- import org.apache.fop.area.Block;
- import org.apache.fop.fo.flow.ListItem;
- import org.apache.fop.fo.flow.ListItemBody;
- import org.apache.fop.fo.flow.ListItemLabel;
- import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
- import org.apache.fop.fo.properties.KeepProperty;
- import org.apache.fop.layoutmgr.BlockLayoutManager;
- import org.apache.fop.layoutmgr.BreakElement;
- import org.apache.fop.layoutmgr.BreakOpportunity;
- import org.apache.fop.layoutmgr.BreakOpportunityHelper;
- import org.apache.fop.layoutmgr.ElementListObserver;
- import org.apache.fop.layoutmgr.ElementListUtils;
- import org.apache.fop.layoutmgr.FloatContentLayoutManager;
- import org.apache.fop.layoutmgr.FootenoteUtil;
- import org.apache.fop.layoutmgr.Keep;
- import org.apache.fop.layoutmgr.KnuthBlockBox;
- import org.apache.fop.layoutmgr.KnuthElement;
- import org.apache.fop.layoutmgr.KnuthPenalty;
- import org.apache.fop.layoutmgr.KnuthPossPosIter;
- import org.apache.fop.layoutmgr.LayoutContext;
- import org.apache.fop.layoutmgr.LayoutManager;
- import org.apache.fop.layoutmgr.LeafPosition;
- import org.apache.fop.layoutmgr.ListElement;
- import org.apache.fop.layoutmgr.NonLeafPosition;
- import org.apache.fop.layoutmgr.PageProvider;
- import org.apache.fop.layoutmgr.Position;
- import org.apache.fop.layoutmgr.PositionIterator;
- import org.apache.fop.layoutmgr.SpaceResolver;
- import org.apache.fop.layoutmgr.SpacedBorderedPaddedBlockLayoutManager;
- import org.apache.fop.layoutmgr.TraitSetter;
- import org.apache.fop.traits.SpaceVal;
- import org.apache.fop.util.BreakUtil;
-
- /**
- * LayoutManager for a list-item FO.
- * The list item contains a list item label and a list item body.
- */
- public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManager
- implements BreakOpportunity {
-
- /** logging instance */
- private static Log log = LogFactory.getLog(ListItemLayoutManager.class);
-
- private ListItemContentLayoutManager label;
- private ListItemContentLayoutManager body;
-
- private Block curBlockArea;
-
- private List<ListElement> labelList;
- private List<ListElement> bodyList;
-
- private Keep keepWithNextPendingOnLabel;
- private Keep keepWithNextPendingOnBody;
-
- public class ListItemPosition extends Position {
- private int labelFirstIndex;
- private int labelLastIndex;
- private int bodyFirstIndex;
- private int bodyLastIndex;
- private Position originalLabelPosition;
- private Position originalBodyPosition;
-
- public ListItemPosition(LayoutManager lm, int labelFirst, int labelLast,
- int bodyFirst, int bodyLast) {
- super(lm);
- labelFirstIndex = labelFirst;
- labelLastIndex = labelLast;
- bodyFirstIndex = bodyFirst;
- bodyLastIndex = bodyLast;
- }
-
- public int getLabelFirstIndex() {
- return labelFirstIndex;
- }
-
- public int getLabelLastIndex() {
- return labelLastIndex;
- }
-
- public int getBodyFirstIndex() {
- return bodyFirstIndex;
- }
-
- public int getBodyLastIndex() {
- return bodyLastIndex;
- }
-
- /** {@inheritDoc} */
- public boolean generatesAreas() {
- return true;
- }
-
- /** {@inheritDoc} */
- public String toString() {
- StringBuffer sb = new StringBuffer("ListItemPosition:");
- sb.append(getIndex()).append("(");
- sb.append("label:").append(labelFirstIndex).append("-").append(labelLastIndex);
- sb.append(" body:").append(bodyFirstIndex).append("-").append(bodyLastIndex);
- sb.append(")");
- return sb.toString();
- }
-
- public Position getOriginalLabelPosition() {
- return originalLabelPosition;
- }
-
- public void setOriginalLabelPosition(Position originalLabelPosition) {
- this.originalLabelPosition = originalLabelPosition;
- }
-
- public Position getOriginalBodyPosition() {
- return originalBodyPosition;
- }
-
- public void setOriginalBodyPosition(Position originalBodyPosition) {
- this.originalBodyPosition = originalBodyPosition;
- }
- }
-
- /**
- * Create a new list item layout manager.
- * @param node list-item to create the layout manager for
- */
- public ListItemLayoutManager(ListItem node) {
- super(node);
- setLabel(node.getLabel());
- setBody(node.getBody());
- }
-
- @Override
- protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
- return getListItemFO().getCommonBorderPaddingBackground();
- }
-
- /**
- * Convenience method.
- * @return the ListBlock node
- */
- protected ListItem getListItemFO() {
- return (ListItem)fobj;
- }
-
- /**
- * Create a LM for the fo:list-item-label object
- * @param node the fo:list-item-label FO
- */
- public void setLabel(ListItemLabel node) {
- label = new ListItemContentLayoutManager(node);
- label.setParent(this);
- }
-
- /**
- * Create a LM for the fo:list-item-body object
- * @param node the fo:list-item-body FO
- */
- public void setBody(ListItemBody node) {
- body = new ListItemContentLayoutManager(node);
- body.setParent(this);
- }
-
- /** {@inheritDoc} */
- @Override
- public void initialize() {
- foSpaceBefore = new SpaceVal(
- getListItemFO().getCommonMarginBlock().spaceBefore, this).getSpace();
- foSpaceAfter = new SpaceVal(
- getListItemFO().getCommonMarginBlock().spaceAfter, this).getSpace();
- startIndent = getListItemFO().getCommonMarginBlock().startIndent.getValue(this);
- endIndent = getListItemFO().getCommonMarginBlock().endIndent.getValue(this);
- }
-
- private void resetSpaces() {
- this.discardBorderBefore = false;
- this.discardBorderAfter = false;
- this.discardPaddingBefore = false;
- this.discardPaddingAfter = false;
- this.effSpaceBefore = null;
- this.effSpaceAfter = null;
- }
-
- /** {@inheritDoc} */
- public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
- Position restartPosition, LayoutManager restartAtLM) {
- referenceIPD = context.getRefIPD();
- LayoutContext childLC;
-
- List<ListElement> returnList = new LinkedList<ListElement>();
-
- if (!breakBeforeServed(context, returnList)) {
- return returnList;
- }
-
- addFirstVisibleMarks(returnList, context, alignment);
-
- // label
- childLC = makeChildLayoutContext(context);
- childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
- label.initialize();
- boolean labelDone = false;
- Stack labelLMStack = null;
- Position labelRestartPosition = null;
- LayoutManager labelRestartLM = null;
- if (restartPosition != null && restartPosition instanceof ListItemPosition) {
- ListItemPosition lip = (ListItemPosition) restartPosition;
- if (lip.labelLastIndex <= lip.labelFirstIndex) {
- labelDone = true;
- } else {
- labelRestartPosition = lip.getOriginalLabelPosition();
- labelRestartLM = labelRestartPosition.getLM();
- LayoutManager lm = labelRestartLM;
- labelLMStack = new Stack();
- while (lm != this) {
- labelLMStack.push(lm);
- lm = lm.getParent();
- if (lm instanceof ListItemContentLayoutManager) {
- lm = lm.getParent();
- }
- }
- }
- }
- labelList = !labelDone ? label.getNextKnuthElements(childLC, alignment, labelLMStack,
- labelRestartPosition, labelRestartLM) : (List) new LinkedList<KnuthElement>();
-
- //Space resolution as if the contents were placed in a new reference area
- //(see 6.8.3, XSL 1.0, section on Constraints, last paragraph)
- SpaceResolver.resolveElementList(labelList);
- ElementListObserver.observe(labelList, "list-item-label", label.getPartFO().getId());
-
- context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
- this.keepWithNextPendingOnLabel = childLC.getKeepWithNextPending();
-
- // body
- childLC = makeChildLayoutContext(context);
- childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
- body.initialize();
- boolean bodyDone = false;
- Stack bodyLMStack = null;
- Position bodyRestartPosition = null;
- LayoutManager bodyRestartLM = null;
- if (restartPosition != null && restartPosition instanceof ListItemPosition) {
- ListItemPosition lip = (ListItemPosition) restartPosition;
- if (lip.bodyLastIndex <= lip.bodyFirstIndex) {
- bodyDone = true;
- } else {
- bodyRestartPosition = lip.getOriginalBodyPosition();
- bodyRestartLM = bodyRestartPosition.getLM();
- LayoutManager lm = bodyRestartLM;
- bodyLMStack = new Stack();
- while (lm != this) {
- bodyLMStack.push(lm);
- lm = lm.getParent();
- if (lm instanceof ListItemContentLayoutManager) {
- lm = lm.getParent();
- }
- }
- }
- }
- bodyList = !bodyDone ? body.getNextKnuthElements(childLC, alignment, bodyLMStack,
- bodyRestartPosition, bodyRestartLM) : (List) new LinkedList<KnuthElement>();
-
- //Space resolution as if the contents were placed in a new reference area
- //(see 6.8.3, XSL 1.0, section on Constraints, last paragraph)
- SpaceResolver.resolveElementList(bodyList);
- ElementListObserver.observe(bodyList, "list-item-body", body.getPartFO().getId());
-
- context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
- this.keepWithNextPendingOnBody = childLC.getKeepWithNextPending();
-
- List<ListElement> returnedList = new LinkedList<ListElement>();
- if (!labelList.isEmpty() && labelList.get(0) instanceof KnuthBlockBox) {
- KnuthBlockBox kbb = (KnuthBlockBox) labelList.get(0);
- if (kbb.getWidth() == 0 && kbb.hasFloatAnchors()) {
- List<FloatContentLayoutManager> floats = kbb.getFloatContentLMs();
- returnedList.add(new KnuthBlockBox(0, Collections.emptyList(), null, false, floats));
- Keep keep = getKeepTogether();
- returnedList.add(new BreakElement(new LeafPosition(this, 0), keep.getPenalty(), keep
- .getContext(), context));
- labelList.remove(0);
- labelList.remove(0);
- }
- }
- if (!bodyList.isEmpty() && bodyList.get(0) instanceof KnuthBlockBox) {
- KnuthBlockBox kbb = (KnuthBlockBox) bodyList.get(0);
- if (kbb.getWidth() == 0 && kbb.hasFloatAnchors()) {
- List<FloatContentLayoutManager> floats = kbb.getFloatContentLMs();
- returnedList.add(new KnuthBlockBox(0, Collections.emptyList(), null, false, floats));
- Keep keep = getKeepTogether();
- returnedList.add(new BreakElement(new LeafPosition(this, 0), keep.getPenalty(), keep
- .getContext(), context));
- bodyList.remove(0);
- bodyList.remove(0);
- }
- }
-
- // create a combined list
- returnedList.addAll(getCombinedKnuthElementsForListItem(labelList, bodyList, context));
-
- // "wrap" the Position inside each element
- wrapPositionElements(returnedList, returnList, true);
-
- addLastVisibleMarks(returnList, context, alignment);
-
- addKnuthElementsForBreakAfter(returnList, context);
-
- context.updateKeepWithNextPending(this.keepWithNextPendingOnLabel);
- context.updateKeepWithNextPending(this.keepWithNextPendingOnBody);
- context.updateKeepWithNextPending(getKeepWithNext());
- context.updateKeepWithPreviousPending(getKeepWithPrevious());
-
- setFinished(true);
- resetSpaces();
- return returnList;
- }
-
- /**
- * Overridden to unconditionally add elements for space-before.
- * {@inheritDoc}
- */
- @Override
- protected void addFirstVisibleMarks(List<ListElement> elements,
- LayoutContext context, int alignment) {
- addKnuthElementsForSpaceBefore(elements, alignment);
- addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
- firstVisibleMarkServed = true;
- //Spaces, border and padding to be repeated at each break
- addPendingMarks(context);
- }
-
- private List getCombinedKnuthElementsForListItem(List<ListElement> labelElements,
- List<ListElement> bodyElements, LayoutContext context) {
- // Copy elements to array lists to improve element access performance
- List[] elementLists = {new ArrayList<ListElement>(labelElements),
- new ArrayList<ListElement>(bodyElements)};
- int[] fullHeights = {ElementListUtils.calcContentLength(elementLists[0]),
- ElementListUtils.calcContentLength(elementLists[1])};
- int[] partialHeights = {0, 0};
- int[] start = {-1, -1};
- int[] end = {-1, -1};
-
- int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
- int step;
- int addedBoxHeight = 0;
- Keep keepWithNextActive = Keep.KEEP_AUTO;
-
- LinkedList<ListElement> returnList = new LinkedList<ListElement>();
- while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {
-
- if (end[0] + 1 == elementLists[0].size()) {
- keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnLabel);
- }
- if (end[1] + 1 == elementLists[1].size()) {
- keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnBody);
- }
-
- // compute penalty height and box height
- int penaltyHeight = step
- + getMaxRemainingHeight(fullHeights, partialHeights)
- - totalHeight;
-
- //Additional penalty height from penalties in the source lists
- int additionalPenaltyHeight = 0;
- int stepPenalty = 0;
- int breakClass = EN_AUTO;
- KnuthElement endEl = elementLists[0].size() > 0 ? (KnuthElement) elementLists[0].get(end[0])
- : null;
- Position originalLabelPosition =
- (endEl != null && endEl.getPosition() != null) ? endEl.getPosition().getPosition() : null;
- if (endEl instanceof KnuthPenalty) {
- additionalPenaltyHeight = endEl.getWidth();
- stepPenalty = endEl.getPenalty() == -KnuthElement.INFINITE ? -KnuthElement.INFINITE : Math
- .max(stepPenalty, endEl.getPenalty());
- breakClass = BreakUtil.compareBreakClasses(breakClass,
- ((KnuthPenalty) endEl).getBreakClass());
- }
- endEl = elementLists[1].size() > 0 ? (KnuthElement) elementLists[1].get(end[1]) : null;
- Position originalBodyPosition =
- (endEl != null && endEl.getPosition() != null) ? endEl.getPosition().getPosition() : null;
- if (endEl instanceof KnuthPenalty) {
- additionalPenaltyHeight = Math.max(
- additionalPenaltyHeight, endEl.getWidth());
- stepPenalty = endEl.getPenalty() == -KnuthElement.INFINITE ? -KnuthElement.INFINITE : Math
- .max(stepPenalty, endEl.getPenalty());
- breakClass = BreakUtil.compareBreakClasses(breakClass,
- ((KnuthPenalty) endEl).getBreakClass());
- }
-
- int boxHeight = step - addedBoxHeight - penaltyHeight;
- penaltyHeight += additionalPenaltyHeight; //Add AFTER calculating boxHeight!
-
- // collect footnote information
- // TODO this should really not be done like this. ListItemLM should remain as
- // footnote-agnostic as possible
- LinkedList<LayoutManager> footnoteList = new LinkedList<LayoutManager>();
- for (int i = 0; i < elementLists.length; i++) {
- footnoteList.addAll(FootenoteUtil.getFootnotes(elementLists[i], start[i], end[i]));
- }
-
- LinkedList<FloatContentLayoutManager> floats = new LinkedList<FloatContentLayoutManager>();
- for (int i = 0; i < elementLists.length; i++) {
- floats.addAll(FloatContentLayoutManager.checkForFloats(elementLists[i], start[i], end[i]));
- }
-
- // add the new elements
- addedBoxHeight += boxHeight;
- ListItemPosition stepPosition = new ListItemPosition(this, start[0], end[0], start[1], end[1]);
- stepPosition.setOriginalLabelPosition(originalLabelPosition);
- stepPosition.setOriginalBodyPosition(originalBodyPosition);
-
- if (floats.isEmpty()) {
- returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
- } else {
- // add a line with height zero and no content and attach float to it
- returnList.add(new KnuthBlockBox(0, Collections.emptyList(), stepPosition, false, floats));
- // add a break element to signal that we should restart LB at this break
- Keep keep = getKeepTogether();
- returnList.add(new BreakElement(stepPosition, keep.getPenalty(), keep.getContext(), context));
- // add the original line where the float was but without the float now
- returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
- }
- if (originalBodyPosition != null && getKeepWithPrevious().isAuto()
- && shouldWeAvoidBreak(returnList, originalBodyPosition.getLM())) {
- stepPenalty++;
- }
- if (addedBoxHeight < totalHeight) {
- Keep keep = keepWithNextActive.compare(getKeepTogether());
- int p = stepPenalty;
- if (p > -KnuthElement.INFINITE) {
- p = Math.max(p, keep.getPenalty());
- breakClass = keep.getContext();
- }
- returnList.add(new BreakElement(stepPosition, penaltyHeight, p, breakClass, context));
- }
- }
-
- return returnList;
- }
-
- private boolean shouldWeAvoidBreak(List returnList, LayoutManager lm) {
- if (isChangingIPD(lm)) {
- if (lm instanceof BlockLayoutManager) {
- return true;
- }
- if (lm instanceof ListBlockLayoutManager) {
- int penaltyShootout = 0;
- for (Object o : returnList) {
- if (o instanceof BreakElement) {
- if (((BreakElement) o).getPenaltyValue() > 0) {
- penaltyShootout++;
- } else {
- penaltyShootout--;
- }
- }
- }
- return penaltyShootout > 0;
- }
- }
- return false;
- }
-
- private boolean isChangingIPD(LayoutManager lm) {
- PageProvider pageProvider = lm.getPSLM().getPageProvider();
- int currentIPD = pageProvider.getCurrentIPD();
- if (currentIPD == -1) {
- return false;
- }
- int nextIPD = pageProvider.getNextIPD();
- return nextIPD != currentIPD;
- }
-
- private int getNextStep(List[] elementLists, int[] start, int[] end, int[] partialHeights) {
- // backup of partial heights
- int[] backupHeights = {partialHeights[0], partialHeights[1]};
-
- // set starting points
- start[0] = end[0] + 1;
- start[1] = end[1] + 1;
-
- // get next possible sequence for label and body
- int seqCount = 0;
- for (int i = 0; i < start.length; i++) {
- while (end[i] + 1 < elementLists[i].size()) {
- end[i]++;
- KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
- if (el.isPenalty()) {
- if (el.getPenalty() < KnuthElement.INFINITE) {
- //First legal break point
- break;
- }
- } else if (el.isGlue()) {
- if (end[i] > 0) {
- KnuthElement prev = (KnuthElement)elementLists[i].get(end[i] - 1);
- if (prev.isBox()) {
- //Second legal break point
- break;
- }
- }
- partialHeights[i] += el.getWidth();
- } else {
- partialHeights[i] += el.getWidth();
- }
- }
- if (end[i] < start[i]) {
- partialHeights[i] = backupHeights[i];
- } else {
- seqCount++;
- }
- }
- if (seqCount == 0) {
- return 0;
- }
-
- // determine next step
- int step;
- if (backupHeights[0] == 0 && backupHeights[1] == 0) {
- // this is the first step: choose the maximum increase, so that
- // the smallest area in the first page will contain at least
- // a label area and a body area
- step = Math.max((end[0] >= start[0] ? partialHeights[0] : Integer.MIN_VALUE),
- (end[1] >= start[1] ? partialHeights[1] : Integer.MIN_VALUE));
- } else {
- // this is not the first step: choose the minimum increase
- step = Math.min((end[0] >= start[0] ? partialHeights[0] : Integer.MAX_VALUE),
- (end[1] >= start[1] ? partialHeights[1] : Integer.MAX_VALUE));
- }
-
- // reset bigger-than-step sequences
- for (int i = 0; i < partialHeights.length; i++) {
- if (partialHeights[i] > step) {
- partialHeights[i] = backupHeights[i];
- end[i] = start[i] - 1;
- }
- }
-
- return step;
- }
-
- private int getMaxRemainingHeight(int[] fullHeights, int[] partialHeights) {
- return Math.max(fullHeights[0] - partialHeights[0],
- fullHeights[1] - partialHeights[1]);
- }
-
- /** {@inheritDoc} */
- @Override
- public List getChangedKnuthElements(List oldList, int alignment) {
- // label
- labelList = label.getChangedKnuthElements(labelList, alignment);
-
- // body
- // "unwrap" the Positions stored in the elements
- ListIterator oldListIterator = oldList.listIterator();
- KnuthElement oldElement;
- while (oldListIterator.hasNext()) {
- oldElement = (KnuthElement)oldListIterator.next();
- Position innerPosition = oldElement.getPosition().getPosition();
- if (innerPosition != null) {
- // oldElement was created by a descendant of this BlockLM
- oldElement.setPosition(innerPosition);
- } else {
- // thisElement was created by this BlockLM
- // modify its position in order to recognize it was not created
- // by a child
- oldElement.setPosition(new Position(this));
- }
- }
-
- List returnedList = body.getChangedKnuthElements(oldList, alignment);
- // "wrap" the Position inside each element
- List tempList = returnedList;
- KnuthElement tempElement;
- returnedList = new LinkedList();
- for (Object aTempList : tempList) {
- tempElement = (KnuthElement) aTempList;
- tempElement.setPosition(new NonLeafPosition(this, tempElement.getPosition()));
- returnedList.add(tempElement);
- }
-
- return returnedList;
- }
-
-
- @Override
- public boolean hasLineAreaDescendant() {
- return label.hasLineAreaDescendant() || body.hasLineAreaDescendant();
- }
-
- @Override
- public int getBaselineOffset() {
- if (label.hasLineAreaDescendant()) {
- return label.getBaselineOffset();
- } else if (body.hasLineAreaDescendant()) {
- return body.getBaselineOffset();
- } else {
- throw newNoLineAreaDescendantException();
- }
- }
-
- /**
- * Add the areas for the break points.
- *
- * @param parentIter the position iterator
- * @param layoutContext the layout context for adding areas
- */
- @Override
- public void addAreas(PositionIterator parentIter,
- LayoutContext layoutContext) {
- getParentArea(null);
-
- addId();
-
- LayoutContext lc = LayoutContext.offspringOf(layoutContext);
- Position firstPos = null;
- Position lastPos = null;
-
- // "unwrap" the NonLeafPositions stored in parentIter
- LinkedList<Position> positionList = new LinkedList<Position>();
- Position pos;
- while (parentIter.hasNext()) {
- pos = parentIter.next();
- if (pos.getIndex() >= 0) {
- if (firstPos == null) {
- firstPos = pos;
- }
- lastPos = pos;
- }
- if (pos instanceof NonLeafPosition && pos.getPosition() != null) {
- // pos contains a ListItemPosition created by this ListBlockLM
- positionList.add(pos.getPosition());
- }
- }
- if (positionList.isEmpty()) {
- reset();
- return;
- }
-
- registerMarkers(true, isFirst(firstPos), isLast(lastPos));
-
- // use the first and the last ListItemPosition to determine the
- // corresponding indexes in the original labelList and bodyList
- int labelFirstIndex = ((ListItemPosition) positionList.getFirst()).getLabelFirstIndex();
- int labelLastIndex = ((ListItemPosition) positionList.getLast()).getLabelLastIndex();
- int bodyFirstIndex = ((ListItemPosition) positionList.getFirst()).getBodyFirstIndex();
- int bodyLastIndex = ((ListItemPosition) positionList.getLast()).getBodyLastIndex();
-
- //Determine previous break if any (in item label list)
- int previousBreak = ElementListUtils.determinePreviousBreak(labelList, labelFirstIndex);
- SpaceResolver.performConditionalsNotification(labelList,
- labelFirstIndex, labelLastIndex, previousBreak);
-
- //Determine previous break if any (in item body list)
- previousBreak = ElementListUtils.determinePreviousBreak(bodyList, bodyFirstIndex);
- SpaceResolver.performConditionalsNotification(bodyList,
- bodyFirstIndex, bodyLastIndex, previousBreak);
-
- // add label areas
- if (labelFirstIndex <= labelLastIndex) {
- KnuthPossPosIter labelIter = new KnuthPossPosIter(labelList,
- labelFirstIndex, labelLastIndex + 1);
- lc.setFlags(LayoutContext.FIRST_AREA, layoutContext.isFirstArea());
- lc.setFlags(LayoutContext.LAST_AREA, layoutContext.isLastArea());
- // set the space adjustment ratio
- lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
- // TO DO: use the right stack limit for the label
- lc.setStackLimitBP(layoutContext.getStackLimitBP());
- label.addAreas(labelIter, lc);
- }
-
- // add body areas
- if (bodyFirstIndex <= bodyLastIndex) {
- KnuthPossPosIter bodyIter = new KnuthPossPosIter(bodyList,
- bodyFirstIndex, bodyLastIndex + 1);
- lc.setFlags(LayoutContext.FIRST_AREA, layoutContext.isFirstArea());
- lc.setFlags(LayoutContext.LAST_AREA, layoutContext.isLastArea());
- // set the space adjustment ratio
- lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
- // TO DO: use the right stack limit for the body
- lc.setStackLimitBP(layoutContext.getStackLimitBP());
- body.addAreas(bodyIter, lc);
- }
-
- // after adding body areas, set the maximum area bpd
- int childCount = curBlockArea.getChildAreas().size();
- assert childCount >= 1 && childCount <= 2;
- int itemBPD = ((Block)curBlockArea.getChildAreas().get(0)).getAllocBPD();
- if (childCount == 2) {
- itemBPD = Math.max(itemBPD, ((Block)curBlockArea.getChildAreas().get(1)).getAllocBPD());
- }
- curBlockArea.setBPD(itemBPD);
-
- registerMarkers(false, isFirst(firstPos), isLast(lastPos));
-
- // We are done with this area add the background
- TraitSetter.addBackground(curBlockArea,
- getListItemFO().getCommonBorderPaddingBackground(),
- this);
- TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
- effSpaceBefore, effSpaceAfter);
-
- flush();
-
- curBlockArea = null;
- resetSpaces();
-
- checkEndOfLayout(lastPos);
- }
-
- /**
- * Return an Area which can contain the passed childArea. The childArea
- * may not yet have any content, but it has essential traits set.
- * In general, if the LayoutManager already has an Area it simply returns
- * it. Otherwise, it makes a new Area of the appropriate class.
- * It gets a parent area for its area by calling its parent LM.
- * Finally, based on the dimensions of the parent area, it initializes
- * its own area. This includes setting the content IPD and the maximum
- * BPD.
- *
- * @param childArea the child area
- * @return the parent are for the child
- */
- @Override
- public Area getParentArea(Area childArea) {
- if (curBlockArea == null) {
- curBlockArea = new Block();
- curBlockArea.setChangeBarList(getChangeBarList());
-
- // Set up dimensions
- /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
-
- // set traits
- ListItem fo = getListItemFO();
- TraitSetter.setProducerID(curBlockArea, fo.getId());
- TraitSetter.addBorders(curBlockArea, fo.getCommonBorderPaddingBackground(),
- discardBorderBefore, discardBorderAfter, false, false, this);
- TraitSetter.addPadding(curBlockArea, fo.getCommonBorderPaddingBackground(),
- discardPaddingBefore, discardPaddingAfter, false, false, this);
- TraitSetter.addMargins(curBlockArea, fo.getCommonBorderPaddingBackground(),
- fo.getCommonMarginBlock(), this);
- TraitSetter.addBreaks(curBlockArea, fo.getBreakBefore(), fo.getBreakAfter());
-
- int contentIPD = referenceIPD - getIPIndents();
- curBlockArea.setIPD(contentIPD);
-
- curBlockArea.setBidiLevel(fo.getBidiLevel());
-
- setCurrentArea(curBlockArea);
- }
- return curBlockArea;
- }
-
- /**
- * Add the child.
- * Rows return the areas returned by the child elements.
- * This simply adds the area to the parent layout manager.
- *
- * @param childArea the child area
- */
- @Override
- public void addChildArea(Area childArea) {
- if (curBlockArea != null) {
- curBlockArea.addBlock((Block) childArea);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public KeepProperty getKeepTogetherProperty() {
- return getListItemFO().getKeepTogether();
- }
-
- /** {@inheritDoc} */
- @Override
- public KeepProperty getKeepWithPreviousProperty() {
- return getListItemFO().getKeepWithPrevious();
- }
-
- /** {@inheritDoc} */
- @Override
- public KeepProperty getKeepWithNextProperty() {
- return getListItemFO().getKeepWithNext();
- }
-
- /** {@inheritDoc} */
- @Override
- public void reset() {
- super.reset();
- label.reset();
- body.reset();
- }
-
- @Override
- public int getBreakBefore() {
- int breakBefore = BreakOpportunityHelper.getBreakBefore(this);
- breakBefore = BreakUtil.compareBreakClasses(breakBefore, label.getBreakBefore());
- breakBefore = BreakUtil.compareBreakClasses(breakBefore, body.getBreakBefore());
- return breakBefore;
- }
-
- /** {@inheritDoc} */
- public boolean isRestartable() {
- return true;
- }
- }
|