You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ListItemLayoutManager.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.layoutmgr.list;
  19. import java.util.ArrayList;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.ListIterator;
  23. import org.apache.commons.logging.Log;
  24. import org.apache.commons.logging.LogFactory;
  25. import org.apache.fop.area.Area;
  26. import org.apache.fop.area.Block;
  27. import org.apache.fop.fo.flow.ListItem;
  28. import org.apache.fop.fo.flow.ListItemBody;
  29. import org.apache.fop.fo.flow.ListItemLabel;
  30. import org.apache.fop.fo.properties.KeepProperty;
  31. import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
  32. import org.apache.fop.layoutmgr.BreakElement;
  33. import org.apache.fop.layoutmgr.BreakOpportunity;
  34. import org.apache.fop.layoutmgr.BreakOpportunityHelper;
  35. import org.apache.fop.layoutmgr.ConditionalElementListener;
  36. import org.apache.fop.layoutmgr.ElementListObserver;
  37. import org.apache.fop.layoutmgr.ElementListUtils;
  38. import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
  39. import org.apache.fop.layoutmgr.Keep;
  40. import org.apache.fop.layoutmgr.KnuthBlockBox;
  41. import org.apache.fop.layoutmgr.KnuthBox;
  42. import org.apache.fop.layoutmgr.KnuthElement;
  43. import org.apache.fop.layoutmgr.KnuthPenalty;
  44. import org.apache.fop.layoutmgr.KnuthPossPosIter;
  45. import org.apache.fop.layoutmgr.LayoutContext;
  46. import org.apache.fop.layoutmgr.LayoutManager;
  47. import org.apache.fop.layoutmgr.ListElement;
  48. import org.apache.fop.layoutmgr.NonLeafPosition;
  49. import org.apache.fop.layoutmgr.Position;
  50. import org.apache.fop.layoutmgr.PositionIterator;
  51. import org.apache.fop.layoutmgr.RelSide;
  52. import org.apache.fop.layoutmgr.SpaceResolver;
  53. import org.apache.fop.layoutmgr.TraitSetter;
  54. import org.apache.fop.traits.MinOptMax;
  55. import org.apache.fop.traits.SpaceVal;
  56. import org.apache.fop.util.BreakUtil;
  57. /**
  58. * LayoutManager for a list-item FO.
  59. * The list item contains a list item label and a list item body.
  60. */
  61. public class ListItemLayoutManager extends BlockStackingLayoutManager implements ConditionalElementListener,
  62. BreakOpportunity {
  63. /** logging instance */
  64. private static Log log = LogFactory.getLog(ListItemLayoutManager.class);
  65. private ListItemContentLayoutManager label;
  66. private ListItemContentLayoutManager body;
  67. private Block curBlockArea = null;
  68. private List<ListElement> labelList = null;
  69. private List<ListElement> bodyList = null;
  70. private boolean discardBorderBefore;
  71. private boolean discardBorderAfter;
  72. private boolean discardPaddingBefore;
  73. private boolean discardPaddingAfter;
  74. private MinOptMax effSpaceBefore;
  75. private MinOptMax effSpaceAfter;
  76. private Keep keepWithNextPendingOnLabel;
  77. private Keep keepWithNextPendingOnBody;
  78. private class ListItemPosition extends Position {
  79. private int labelFirstIndex;
  80. private int labelLastIndex;
  81. private int bodyFirstIndex;
  82. private int bodyLastIndex;
  83. public ListItemPosition(LayoutManager lm, int labelFirst, int labelLast,
  84. int bodyFirst, int bodyLast) {
  85. super(lm);
  86. labelFirstIndex = labelFirst;
  87. labelLastIndex = labelLast;
  88. bodyFirstIndex = bodyFirst;
  89. bodyLastIndex = bodyLast;
  90. }
  91. public int getLabelFirstIndex() {
  92. return labelFirstIndex;
  93. }
  94. public int getLabelLastIndex() {
  95. return labelLastIndex;
  96. }
  97. public int getBodyFirstIndex() {
  98. return bodyFirstIndex;
  99. }
  100. public int getBodyLastIndex() {
  101. return bodyLastIndex;
  102. }
  103. /** {@inheritDoc} */
  104. public boolean generatesAreas() {
  105. return true;
  106. }
  107. /** {@inheritDoc} */
  108. public String toString() {
  109. StringBuffer sb = new StringBuffer("ListItemPosition:");
  110. sb.append(getIndex()).append("(");
  111. sb.append("label:").append(labelFirstIndex).append("-").append(labelLastIndex);
  112. sb.append(" body:").append(bodyFirstIndex).append("-").append(bodyLastIndex);
  113. sb.append(")");
  114. return sb.toString();
  115. }
  116. }
  117. /**
  118. * Create a new list item layout manager.
  119. * @param node list-item to create the layout manager for
  120. */
  121. public ListItemLayoutManager(ListItem node) {
  122. super(node);
  123. setLabel(node.getLabel());
  124. setBody(node.getBody());
  125. }
  126. /**
  127. * Convenience method.
  128. * @return the ListBlock node
  129. */
  130. protected ListItem getListItemFO() {
  131. return (ListItem)fobj;
  132. }
  133. /**
  134. * Create a LM for the fo:list-item-label object
  135. * @param node the fo:list-item-label FO
  136. */
  137. public void setLabel(ListItemLabel node) {
  138. label = new ListItemContentLayoutManager(node);
  139. label.setParent(this);
  140. }
  141. /**
  142. * Create a LM for the fo:list-item-body object
  143. * @param node the fo:list-item-body FO
  144. */
  145. public void setBody(ListItemBody node) {
  146. body = new ListItemContentLayoutManager(node);
  147. body.setParent(this);
  148. }
  149. /** {@inheritDoc} */
  150. @Override
  151. public void initialize() {
  152. foSpaceBefore = new SpaceVal(
  153. getListItemFO().getCommonMarginBlock().spaceBefore, this).getSpace();
  154. foSpaceAfter = new SpaceVal(
  155. getListItemFO().getCommonMarginBlock().spaceAfter, this).getSpace();
  156. startIndent = getListItemFO().getCommonMarginBlock().startIndent.getValue(this);
  157. endIndent = getListItemFO().getCommonMarginBlock().endIndent.getValue(this);
  158. }
  159. private void resetSpaces() {
  160. this.discardBorderBefore = false;
  161. this.discardBorderAfter = false;
  162. this.discardPaddingBefore = false;
  163. this.discardPaddingAfter = false;
  164. this.effSpaceBefore = null;
  165. this.effSpaceAfter = null;
  166. }
  167. /** {@inheritDoc} */
  168. @Override
  169. public List getNextKnuthElements(LayoutContext context, int alignment) {
  170. referenceIPD = context.getRefIPD();
  171. LayoutContext childLC;
  172. List<ListElement> returnList = new LinkedList<ListElement>();
  173. if (!breakBeforeServed(context, returnList)) {
  174. return returnList;
  175. }
  176. addFirstVisibleMarks(returnList, context, alignment);
  177. // label
  178. childLC = makeChildLayoutContext(context);
  179. childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
  180. label.initialize();
  181. labelList = label.getNextKnuthElements(childLC, alignment);
  182. //Space resolution as if the contents were placed in a new reference area
  183. //(see 6.8.3, XSL 1.0, section on Constraints, last paragraph)
  184. SpaceResolver.resolveElementList(labelList);
  185. ElementListObserver.observe(labelList, "list-item-label", label.getPartFO().getId());
  186. context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
  187. this.keepWithNextPendingOnLabel = childLC.getKeepWithNextPending();
  188. // body
  189. childLC = makeChildLayoutContext(context);
  190. childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
  191. body.initialize();
  192. bodyList = body.getNextKnuthElements(childLC, alignment);
  193. //Space resolution as if the contents were placed in a new reference area
  194. //(see 6.8.3, XSL 1.0, section on Constraints, last paragraph)
  195. SpaceResolver.resolveElementList(bodyList);
  196. ElementListObserver.observe(bodyList, "list-item-body", body.getPartFO().getId());
  197. context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
  198. this.keepWithNextPendingOnBody = childLC.getKeepWithNextPending();
  199. // create a combined list
  200. List returnedList = getCombinedKnuthElementsForListItem(labelList, bodyList, context);
  201. // "wrap" the Position inside each element
  202. wrapPositionElements(returnedList, returnList, true);
  203. addLastVisibleMarks(returnList, context, alignment);
  204. addKnuthElementsForBreakAfter(returnList, context);
  205. context.updateKeepWithNextPending(this.keepWithNextPendingOnLabel);
  206. context.updateKeepWithNextPending(this.keepWithNextPendingOnBody);
  207. context.updateKeepWithNextPending(getKeepWithNext());
  208. context.updateKeepWithPreviousPending(getKeepWithPrevious());
  209. setFinished(true);
  210. resetSpaces();
  211. return returnList;
  212. }
  213. /**
  214. * Overridden to unconditionally add elements for space-before.
  215. * {@inheritDoc}
  216. */
  217. @Override
  218. protected void addFirstVisibleMarks(List<ListElement> elements,
  219. LayoutContext context, int alignment) {
  220. addKnuthElementsForSpaceBefore(elements, alignment);
  221. addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
  222. firstVisibleMarkServed = true;
  223. //Spaces, border and padding to be repeated at each break
  224. addPendingMarks(context);
  225. }
  226. private List getCombinedKnuthElementsForListItem(List<ListElement> labelElements,
  227. List<ListElement> bodyElements, LayoutContext context) {
  228. // Copy elements to array lists to improve element access performance
  229. List[] elementLists = {new ArrayList<ListElement>(labelElements),
  230. new ArrayList<ListElement>(bodyElements)};
  231. int[] fullHeights = {ElementListUtils.calcContentLength(elementLists[0]),
  232. ElementListUtils.calcContentLength(elementLists[1])};
  233. int[] partialHeights = {0, 0};
  234. int[] start = {-1, -1};
  235. int[] end = {-1, -1};
  236. int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
  237. int step;
  238. int addedBoxHeight = 0;
  239. Keep keepWithNextActive = Keep.KEEP_AUTO;
  240. LinkedList<ListElement> returnList = new LinkedList<ListElement>();
  241. while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {
  242. if (end[0] + 1 == elementLists[0].size()) {
  243. keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnLabel);
  244. }
  245. if (end[1] + 1 == elementLists[1].size()) {
  246. keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnBody);
  247. }
  248. // compute penalty height and box height
  249. int penaltyHeight = step
  250. + getMaxRemainingHeight(fullHeights, partialHeights)
  251. - totalHeight;
  252. //Additional penalty height from penalties in the source lists
  253. int additionalPenaltyHeight = 0;
  254. int stepPenalty = 0;
  255. int breakClass = EN_AUTO;
  256. KnuthElement endEl = (KnuthElement)elementLists[0].get(end[0]);
  257. if (endEl instanceof KnuthPenalty) {
  258. additionalPenaltyHeight = endEl.getWidth();
  259. stepPenalty = endEl.getPenalty() == -KnuthElement.INFINITE ? -KnuthElement.INFINITE : Math
  260. .max(stepPenalty, endEl.getPenalty());
  261. breakClass = BreakUtil.compareBreakClasses(breakClass,
  262. ((KnuthPenalty) endEl).getBreakClass());
  263. }
  264. endEl = (KnuthElement)elementLists[1].get(end[1]);
  265. if (endEl instanceof KnuthPenalty) {
  266. additionalPenaltyHeight = Math.max(
  267. additionalPenaltyHeight, endEl.getWidth());
  268. stepPenalty = endEl.getPenalty() == -KnuthElement.INFINITE ? -KnuthElement.INFINITE : Math
  269. .max(stepPenalty, endEl.getPenalty());
  270. breakClass = BreakUtil.compareBreakClasses(breakClass,
  271. ((KnuthPenalty) endEl).getBreakClass());
  272. }
  273. int boxHeight = step - addedBoxHeight - penaltyHeight;
  274. penaltyHeight += additionalPenaltyHeight; //Add AFTER calculating boxHeight!
  275. // collect footnote information
  276. // TODO this should really not be done like this. ListItemLM should remain as
  277. // footnote-agnostic as possible
  278. LinkedList<FootnoteBodyLayoutManager> footnoteList = null;
  279. ListElement el;
  280. for (int i = 0; i < elementLists.length; i++) {
  281. for (int j = start[i]; j <= end[i]; j++) {
  282. el = (ListElement) elementLists[i].get(j);
  283. if (el instanceof KnuthBlockBox && ((KnuthBlockBox) el).hasAnchors()) {
  284. if (footnoteList == null) {
  285. footnoteList = new LinkedList<FootnoteBodyLayoutManager>();
  286. }
  287. footnoteList.addAll(((KnuthBlockBox) el).getFootnoteBodyLMs());
  288. }
  289. }
  290. }
  291. // add the new elements
  292. addedBoxHeight += boxHeight;
  293. ListItemPosition stepPosition = new ListItemPosition(this,
  294. start[0], end[0], start[1], end[1]);
  295. if (footnoteList == null) {
  296. returnList.add(new KnuthBox(boxHeight, stepPosition, false));
  297. } else {
  298. returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
  299. }
  300. if (addedBoxHeight < totalHeight) {
  301. Keep keep = keepWithNextActive.compare(getKeepTogether());
  302. int p = stepPenalty;
  303. if (p > -KnuthElement.INFINITE) {
  304. p = Math.max(p, keep.getPenalty());
  305. breakClass = keep.getContext();
  306. }
  307. returnList.add(new BreakElement(stepPosition, penaltyHeight, p, breakClass, context));
  308. }
  309. }
  310. return returnList;
  311. }
  312. private int getNextStep(List[] elementLists, int[] start, int[] end, int[] partialHeights) {
  313. // backup of partial heights
  314. int[] backupHeights = {partialHeights[0], partialHeights[1]};
  315. // set starting points
  316. start[0] = end[0] + 1;
  317. start[1] = end[1] + 1;
  318. // get next possible sequence for label and body
  319. int seqCount = 0;
  320. for (int i = 0; i < start.length; i++) {
  321. while (end[i] + 1 < elementLists[i].size()) {
  322. end[i]++;
  323. KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
  324. if (el.isPenalty()) {
  325. if (el.getPenalty() < KnuthElement.INFINITE) {
  326. //First legal break point
  327. break;
  328. }
  329. } else if (el.isGlue()) {
  330. if (end[i] > 0) {
  331. KnuthElement prev = (KnuthElement)elementLists[i].get(end[i] - 1);
  332. if (prev.isBox()) {
  333. //Second legal break point
  334. break;
  335. }
  336. }
  337. partialHeights[i] += el.getWidth();
  338. } else {
  339. partialHeights[i] += el.getWidth();
  340. }
  341. }
  342. if (end[i] < start[i]) {
  343. partialHeights[i] = backupHeights[i];
  344. } else {
  345. seqCount++;
  346. }
  347. }
  348. if (seqCount == 0) {
  349. return 0;
  350. }
  351. // determine next step
  352. int step;
  353. if (backupHeights[0] == 0 && backupHeights[1] == 0) {
  354. // this is the first step: choose the maximum increase, so that
  355. // the smallest area in the first page will contain at least
  356. // a label area and a body area
  357. step = Math.max((end[0] >= start[0] ? partialHeights[0] : Integer.MIN_VALUE),
  358. (end[1] >= start[1] ? partialHeights[1] : Integer.MIN_VALUE));
  359. } else {
  360. // this is not the first step: choose the minimum increase
  361. step = Math.min((end[0] >= start[0] ? partialHeights[0] : Integer.MAX_VALUE),
  362. (end[1] >= start[1] ? partialHeights[1] : Integer.MAX_VALUE));
  363. }
  364. // reset bigger-than-step sequences
  365. for (int i = 0; i < partialHeights.length; i++) {
  366. if (partialHeights[i] > step) {
  367. partialHeights[i] = backupHeights[i];
  368. end[i] = start[i] - 1;
  369. }
  370. }
  371. return step;
  372. }
  373. private int getMaxRemainingHeight(int[] fullHeights, int[] partialHeights) {
  374. return Math.max(fullHeights[0] - partialHeights[0],
  375. fullHeights[1] - partialHeights[1]);
  376. }
  377. /** {@inheritDoc} */
  378. @Override
  379. public List getChangedKnuthElements(List oldList, int alignment) {
  380. // label
  381. labelList = label.getChangedKnuthElements(labelList, alignment);
  382. // body
  383. // "unwrap" the Positions stored in the elements
  384. ListIterator oldListIterator = oldList.listIterator();
  385. KnuthElement oldElement;
  386. while (oldListIterator.hasNext()) {
  387. oldElement = (KnuthElement)oldListIterator.next();
  388. Position innerPosition = oldElement.getPosition().getPosition();
  389. if (innerPosition != null) {
  390. // oldElement was created by a descendant of this BlockLM
  391. oldElement.setPosition(innerPosition);
  392. } else {
  393. // thisElement was created by this BlockLM
  394. // modify its position in order to recognize it was not created
  395. // by a child
  396. oldElement.setPosition(new Position(this));
  397. }
  398. }
  399. List returnedList = body.getChangedKnuthElements(oldList, alignment);
  400. // "wrap" the Position inside each element
  401. List tempList = returnedList;
  402. KnuthElement tempElement;
  403. returnedList = new LinkedList();
  404. ListIterator listIter = tempList.listIterator();
  405. while (listIter.hasNext()) {
  406. tempElement = (KnuthElement)listIter.next();
  407. tempElement.setPosition(new NonLeafPosition(this, tempElement.getPosition()));
  408. returnedList.add(tempElement);
  409. }
  410. return returnedList;
  411. }
  412. /**
  413. * Add the areas for the break points.
  414. *
  415. * @param parentIter the position iterator
  416. * @param layoutContext the layout context for adding areas
  417. */
  418. @Override
  419. public void addAreas(PositionIterator parentIter,
  420. LayoutContext layoutContext) {
  421. getParentArea(null);
  422. addId();
  423. LayoutContext lc = LayoutContext.offspringOf(layoutContext);
  424. Position firstPos = null;
  425. Position lastPos = null;
  426. // "unwrap" the NonLeafPositions stored in parentIter
  427. LinkedList<Position> positionList = new LinkedList<Position>();
  428. Position pos;
  429. while (parentIter.hasNext()) {
  430. pos = parentIter.next();
  431. if (pos.getIndex() >= 0) {
  432. if (firstPos == null) {
  433. firstPos = pos;
  434. }
  435. lastPos = pos;
  436. }
  437. if (pos instanceof NonLeafPosition && pos.getPosition() != null) {
  438. // pos contains a ListItemPosition created by this ListBlockLM
  439. positionList.add(pos.getPosition());
  440. }
  441. }
  442. registerMarkers(true, isFirst(firstPos), isLast(lastPos));
  443. // use the first and the last ListItemPosition to determine the
  444. // corresponding indexes in the original labelList and bodyList
  445. int labelFirstIndex = ((ListItemPosition) positionList.getFirst()).getLabelFirstIndex();
  446. int labelLastIndex = ((ListItemPosition) positionList.getLast()).getLabelLastIndex();
  447. int bodyFirstIndex = ((ListItemPosition) positionList.getFirst()).getBodyFirstIndex();
  448. int bodyLastIndex = ((ListItemPosition) positionList.getLast()).getBodyLastIndex();
  449. //Determine previous break if any (in item label list)
  450. int previousBreak = ElementListUtils.determinePreviousBreak(labelList, labelFirstIndex);
  451. SpaceResolver.performConditionalsNotification(labelList,
  452. labelFirstIndex, labelLastIndex, previousBreak);
  453. //Determine previous break if any (in item body list)
  454. previousBreak = ElementListUtils.determinePreviousBreak(bodyList, bodyFirstIndex);
  455. SpaceResolver.performConditionalsNotification(bodyList,
  456. bodyFirstIndex, bodyLastIndex, previousBreak);
  457. // add label areas
  458. if (labelFirstIndex <= labelLastIndex) {
  459. KnuthPossPosIter labelIter = new KnuthPossPosIter(labelList,
  460. labelFirstIndex, labelLastIndex + 1);
  461. lc.setFlags(LayoutContext.FIRST_AREA, layoutContext.isFirstArea());
  462. lc.setFlags(LayoutContext.LAST_AREA, layoutContext.isLastArea());
  463. // set the space adjustment ratio
  464. lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
  465. // TO DO: use the right stack limit for the label
  466. lc.setStackLimitBP(layoutContext.getStackLimitBP());
  467. label.addAreas(labelIter, lc);
  468. }
  469. // add body areas
  470. if (bodyFirstIndex <= bodyLastIndex) {
  471. KnuthPossPosIter bodyIter = new KnuthPossPosIter(bodyList,
  472. bodyFirstIndex, bodyLastIndex + 1);
  473. lc.setFlags(LayoutContext.FIRST_AREA, layoutContext.isFirstArea());
  474. lc.setFlags(LayoutContext.LAST_AREA, layoutContext.isLastArea());
  475. // set the space adjustment ratio
  476. lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
  477. // TO DO: use the right stack limit for the body
  478. lc.setStackLimitBP(layoutContext.getStackLimitBP());
  479. body.addAreas(bodyIter, lc);
  480. }
  481. // after adding body areas, set the maximum area bpd
  482. int childCount = curBlockArea.getChildAreas().size();
  483. assert childCount >= 1 && childCount <= 2;
  484. int itemBPD = ((Block)curBlockArea.getChildAreas().get(0)).getAllocBPD();
  485. if (childCount == 2) {
  486. itemBPD = Math.max(itemBPD, ((Block)curBlockArea.getChildAreas().get(1)).getAllocBPD());
  487. }
  488. curBlockArea.setBPD(itemBPD);
  489. registerMarkers(false, isFirst(firstPos), isLast(lastPos));
  490. // We are done with this area add the background
  491. TraitSetter.addBackground(curBlockArea,
  492. getListItemFO().getCommonBorderPaddingBackground(),
  493. this);
  494. TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
  495. effSpaceBefore, effSpaceAfter);
  496. flush();
  497. curBlockArea = null;
  498. resetSpaces();
  499. checkEndOfLayout(lastPos);
  500. }
  501. /**
  502. * Return an Area which can contain the passed childArea. The childArea
  503. * may not yet have any content, but it has essential traits set.
  504. * In general, if the LayoutManager already has an Area it simply returns
  505. * it. Otherwise, it makes a new Area of the appropriate class.
  506. * It gets a parent area for its area by calling its parent LM.
  507. * Finally, based on the dimensions of the parent area, it initializes
  508. * its own area. This includes setting the content IPD and the maximum
  509. * BPD.
  510. *
  511. * @param childArea the child area
  512. * @return the parent are for the child
  513. */
  514. @Override
  515. public Area getParentArea(Area childArea) {
  516. if (curBlockArea == null) {
  517. curBlockArea = new Block();
  518. // Set up dimensions
  519. /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
  520. // set traits
  521. ListItem fo = getListItemFO();
  522. TraitSetter.setProducerID(curBlockArea, fo.getId());
  523. TraitSetter.addBorders(curBlockArea, fo.getCommonBorderPaddingBackground(),
  524. discardBorderBefore, discardBorderAfter, false, false, this);
  525. TraitSetter.addPadding(curBlockArea, fo.getCommonBorderPaddingBackground(),
  526. discardPaddingBefore, discardPaddingAfter, false, false, this);
  527. TraitSetter.addMargins(curBlockArea, fo.getCommonBorderPaddingBackground(),
  528. fo.getCommonMarginBlock(), this);
  529. TraitSetter.addBreaks(curBlockArea, fo.getBreakBefore(), fo.getBreakAfter());
  530. int contentIPD = referenceIPD - getIPIndents();
  531. curBlockArea.setIPD(contentIPD);
  532. setCurrentArea(curBlockArea);
  533. }
  534. return curBlockArea;
  535. }
  536. /**
  537. * Add the child.
  538. * Rows return the areas returned by the child elements.
  539. * This simply adds the area to the parent layout manager.
  540. *
  541. * @param childArea the child area
  542. */
  543. @Override
  544. public void addChildArea(Area childArea) {
  545. if (curBlockArea != null) {
  546. curBlockArea.addBlock((Block) childArea);
  547. }
  548. }
  549. /** {@inheritDoc} */
  550. @Override
  551. public KeepProperty getKeepTogetherProperty() {
  552. return getListItemFO().getKeepTogether();
  553. }
  554. /** {@inheritDoc} */
  555. @Override
  556. public KeepProperty getKeepWithPreviousProperty() {
  557. return getListItemFO().getKeepWithPrevious();
  558. }
  559. /** {@inheritDoc} */
  560. @Override
  561. public KeepProperty getKeepWithNextProperty() {
  562. return getListItemFO().getKeepWithNext();
  563. }
  564. /** {@inheritDoc} */
  565. public void notifySpace(RelSide side, MinOptMax effectiveLength) {
  566. if (RelSide.BEFORE == side) {
  567. if (log.isDebugEnabled()) {
  568. log.debug(this + ": Space " + side + ", "
  569. + this.effSpaceBefore + "-> " + effectiveLength);
  570. }
  571. this.effSpaceBefore = effectiveLength;
  572. } else {
  573. if (log.isDebugEnabled()) {
  574. log.debug(this + ": Space " + side + ", "
  575. + this.effSpaceAfter + "-> " + effectiveLength);
  576. }
  577. this.effSpaceAfter = effectiveLength;
  578. }
  579. }
  580. /** {@inheritDoc} */
  581. public void notifyBorder(RelSide side, MinOptMax effectiveLength) {
  582. if (effectiveLength == null) {
  583. if (RelSide.BEFORE == side) {
  584. this.discardBorderBefore = true;
  585. } else {
  586. this.discardBorderAfter = true;
  587. }
  588. }
  589. if (log.isDebugEnabled()) {
  590. log.debug(this + ": Border " + side + " -> " + effectiveLength);
  591. }
  592. }
  593. /** {@inheritDoc} */
  594. public void notifyPadding(RelSide side, MinOptMax effectiveLength) {
  595. if (effectiveLength == null) {
  596. if (RelSide.BEFORE == side) {
  597. this.discardPaddingBefore = true;
  598. } else {
  599. this.discardPaddingAfter = true;
  600. }
  601. }
  602. if (log.isDebugEnabled()) {
  603. log.debug(this + ": Padding " + side + " -> " + effectiveLength);
  604. }
  605. }
  606. /** {@inheritDoc} */
  607. @Override
  608. public void reset() {
  609. super.reset();
  610. label.reset();
  611. body.reset();
  612. }
  613. @Override
  614. public int getBreakBefore() {
  615. int breakBefore = BreakOpportunityHelper.getBreakBefore(this);
  616. breakBefore = BreakUtil.compareBreakClasses(breakBefore, label.getBreakBefore());
  617. breakBefore = BreakUtil.compareBreakClasses(breakBefore, body.getBreakBefore());
  618. return breakBefore;
  619. }
  620. }