Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

BlockStackingLayoutManager.java 51KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  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;
  19. import java.util.LinkedList;
  20. import java.util.List;
  21. import java.util.ListIterator;
  22. import java.util.Stack;
  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.area.BlockParent;
  28. import org.apache.fop.fo.Constants;
  29. import org.apache.fop.fo.FObj;
  30. import org.apache.fop.fo.properties.BreakPropertySet;
  31. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  32. import org.apache.fop.fo.properties.KeepProperty;
  33. import org.apache.fop.fo.properties.SpaceProperty;
  34. import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
  35. import org.apache.fop.traits.MinOptMax;
  36. import org.apache.fop.util.ListUtil;
  37. /**
  38. * Base LayoutManager class for all areas which stack their child
  39. * areas in the block-progression direction, such as Flow, Block, ListBlock.
  40. */
  41. public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
  42. implements BlockLevelLayoutManager {
  43. /** logging instance */
  44. private static Log log = LogFactory.getLog(BlockStackingLayoutManager.class);
  45. /** parent area */
  46. protected BlockParent parentArea;
  47. /** Value of the block-progression-unit (non-standard property) */
  48. protected int bpUnit;
  49. /** space-before value adjusted for block-progression-unit handling */
  50. protected int adjustedSpaceBefore;
  51. /** space-after value adjusted for block-progression-unit handling */
  52. protected int adjustedSpaceAfter;
  53. /** Only used to store the original list when createUnitElements is called */
  54. protected List<KnuthElement> storedList;
  55. /** Indicates whether break before has been served or not */
  56. protected boolean breakBeforeServed;
  57. /** Indicates whether the first visible mark has been returned by this LM, yet */
  58. protected boolean firstVisibleMarkServed;
  59. /** Reference IPD available */
  60. protected int referenceIPD;
  61. /** the effective start-indent value */
  62. protected int startIndent;
  63. /** the effective end-indent value */
  64. protected int endIndent;
  65. /**
  66. * Holds the (one-time use) fo:block space-before
  67. * and -after properties. Large fo:blocks are split
  68. * into multiple Area. Blocks to accomodate the subsequent
  69. * regions (pages) they are placed on. space-before
  70. * is applied at the beginning of the first
  71. * Block and space-after at the end of the last Block
  72. * used in rendering the fo:block.
  73. */
  74. protected MinOptMax foSpaceBefore;
  75. /** see foSpaceBefore */
  76. protected MinOptMax foSpaceAfter;
  77. private Position auxiliaryPosition;
  78. private int contentAreaIPD;
  79. /**
  80. * @param node the fo this LM deals with
  81. */
  82. public BlockStackingLayoutManager(FObj node) {
  83. super(node);
  84. setGeneratesBlockArea(true);
  85. }
  86. /**
  87. * @return current area being filled
  88. */
  89. protected BlockParent getCurrentArea() {
  90. return this.parentArea;
  91. }
  92. /**
  93. * Set the current area being filled.
  94. * @param parentArea the current area to be filled
  95. */
  96. protected void setCurrentArea(BlockParent parentArea) {
  97. this.parentArea = parentArea;
  98. }
  99. /**
  100. * Add a block spacer for space before and space after a block.
  101. * This adds an empty Block area that acts as a block space.
  102. *
  103. * @param adjust the adjustment value
  104. * @param minoptmax the min/opt/max value of the spacing
  105. */
  106. public void addBlockSpacing(double adjust, MinOptMax minoptmax) {
  107. int sp = TraitSetter.getEffectiveSpace(adjust, minoptmax);
  108. if (sp != 0) {
  109. Block spacer = new Block();
  110. spacer.setBPD(sp);
  111. parentLayoutManager.addChildArea(spacer);
  112. }
  113. }
  114. /**
  115. * Add the childArea to the passed area.
  116. * Called by child LayoutManager when it has filled one of its areas.
  117. * The LM should already have an Area in which to put the child.
  118. * See if the area will fit in the current area.
  119. * If so, add it. Otherwise initiate breaking.
  120. * @param childArea the area to add: will be some block-stacked Area.
  121. * @param parentArea the area in which to add the childArea
  122. */
  123. protected void addChildToArea(Area childArea,
  124. BlockParent parentArea) {
  125. // This should be a block-level Area (Block in the generic sense)
  126. if (!(childArea instanceof Block)) {
  127. //log.error("Child not a Block in BlockStackingLM!");
  128. }
  129. parentArea.addBlock((Block) childArea);
  130. flush(); // hand off current area to parent
  131. }
  132. /**
  133. * Add the childArea to the current area.
  134. * Called by child LayoutManager when it has filled one of its areas.
  135. * The LM should already have an Area in which to put the child.
  136. * See if the area will fit in the current area.
  137. * If so, add it. Otherwise initiate breaking.
  138. * @param childArea the area to add: will be some block-stacked Area.
  139. */
  140. @Override
  141. public void addChildArea(Area childArea) {
  142. addChildToArea(childArea, getCurrentArea());
  143. }
  144. /**
  145. * Force current area to be added to parent area.
  146. */
  147. protected void flush() {
  148. if (getCurrentArea() != null) {
  149. parentLayoutManager.addChildArea(getCurrentArea());
  150. }
  151. }
  152. /** @return a cached auxiliary Position instance used for things like spaces. */
  153. protected Position getAuxiliaryPosition() {
  154. if (this.auxiliaryPosition == null) {
  155. this.auxiliaryPosition = new NonLeafPosition(this, null);
  156. }
  157. return this.auxiliaryPosition;
  158. }
  159. /**
  160. * @param len length in millipoints to span with bp units
  161. * @return the minimum integer n such that n * bpUnit >= len
  162. */
  163. protected int neededUnits(int len) {
  164. return (int) Math.ceil((float)len / bpUnit);
  165. }
  166. /**
  167. * Determines and sets the content area IPD based on available reference area IPD, start- and
  168. * end-indent properties.
  169. * end-indent is adjusted based on overconstrained geometry rules, if necessary.
  170. *
  171. * @return the resulting content area IPD
  172. */
  173. protected int updateContentAreaIPDwithOverconstrainedAdjust() {
  174. int ipd = referenceIPD - (startIndent + endIndent);
  175. if (ipd < 0) {
  176. //5.3.4, XSL 1.0, Overconstrained Geometry
  177. log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj);
  178. BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
  179. getFObj().getUserAgent().getEventBroadcaster());
  180. eventProducer.overconstrainedAdjustEndIndent(this,
  181. getFObj().getName(), ipd, getFObj().getLocator());
  182. endIndent += ipd;
  183. ipd = 0;
  184. //TODO Should we skip layout for a block that has ipd=0?
  185. }
  186. setContentAreaIPD(ipd);
  187. return ipd;
  188. }
  189. /**
  190. * Sets the content area IPD by directly supplying the value.
  191. * end-indent is adjusted based on overconstrained geometry rules, if necessary.
  192. * @param contentIPD the IPD of the content
  193. * @return the resulting content area IPD
  194. */
  195. protected int updateContentAreaIPDwithOverconstrainedAdjust(int contentIPD) {
  196. int ipd = referenceIPD - (contentIPD + (startIndent + endIndent));
  197. if (ipd < 0) {
  198. //5.3.4, XSL 1.0, Overconstrained Geometry
  199. log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj);
  200. BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
  201. getFObj().getUserAgent().getEventBroadcaster());
  202. eventProducer.overconstrainedAdjustEndIndent(this,
  203. getFObj().getName(), ipd, getFObj().getLocator());
  204. endIndent += ipd;
  205. }
  206. setContentAreaIPD(contentIPD);
  207. return contentIPD;
  208. }
  209. /** {@inheritDoc} */
  210. @Override
  211. public List getNextKnuthElements(LayoutContext context, int alignment) {
  212. return getNextKnuthElements(context, alignment, null, null, null);
  213. }
  214. /** {@inheritDoc} */
  215. @Override
  216. public List getNextKnuthElements(LayoutContext context, int alignment,
  217. Stack lmStack, Position restartPosition, LayoutManager restartAtLM) {
  218. referenceIPD = context.getRefIPD();
  219. updateContentAreaIPDwithOverconstrainedAdjust();
  220. boolean isRestart = (lmStack != null);
  221. boolean emptyStack = (!isRestart || lmStack.isEmpty());
  222. List<ListElement> contentList = new LinkedList<ListElement>();
  223. List<ListElement> elements = new LinkedList<ListElement>();
  224. if (!breakBeforeServed(context, elements)) {
  225. // if this FO has break-before specified, and it
  226. // has not yet been processed, return now
  227. return elements;
  228. }
  229. addFirstVisibleMarks(elements, context, alignment);
  230. //Used to indicate a special break-after case when all content has already been generated.
  231. BreakElement forcedBreakAfterLast = null;
  232. LayoutContext childLC;
  233. List<ListElement> childElements;
  234. LayoutManager currentChildLM;
  235. if (isRestart) {
  236. if (emptyStack) {
  237. assert restartAtLM != null && restartAtLM.getParent() == this;
  238. currentChildLM = restartAtLM;
  239. } else {
  240. currentChildLM = (LayoutManager) lmStack.pop();
  241. }
  242. setCurrentChildLM(currentChildLM);
  243. } else {
  244. currentChildLM = getChildLM();
  245. }
  246. while (currentChildLM != null) {
  247. childLC = makeChildLayoutContext(context);
  248. if (!isRestart || emptyStack) {
  249. if (isRestart) {
  250. currentChildLM.reset(); // TODO won't work with forced breaks
  251. }
  252. childElements = getNextChildElements(currentChildLM, context, childLC, alignment,
  253. null, null, null);
  254. } else {
  255. // restart && non-empty LM stack
  256. childElements = getNextChildElements(currentChildLM, context, childLC, alignment,
  257. lmStack, restartPosition, restartAtLM);
  258. // once encountered, irrelevant for following child LMs
  259. emptyStack = true;
  260. }
  261. if (contentList.isEmpty()) {
  262. // propagate keep-with-previous up from the first child
  263. context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
  264. }
  265. // handle non-empty child
  266. if (childElements != null && !childElements.isEmpty()) {
  267. if (!contentList.isEmpty()
  268. && !ElementListUtils.startsWithForcedBreak(childElements)) {
  269. // there is a block handled by prevLM before the one
  270. // handled by curLM, and the one handled
  271. // by the current LM does not begin with a break
  272. addInBetweenBreak(contentList, context, childLC);
  273. }
  274. if (childElements.size() == 1
  275. && ElementListUtils.startsWithForcedBreak(childElements)) {
  276. // a descendant of this block has break-before
  277. if (currentChildLM.isFinished() && !hasNextChildLM()) {
  278. // if there is no more content, make sure pending
  279. // marks are cleared
  280. forcedBreakAfterLast = (BreakElement) childElements.get(0);
  281. context.clearPendingMarks();
  282. // break without adding the child elements
  283. break;
  284. }
  285. if (contentList.isEmpty()) {
  286. // empty fo:block: zero-length box makes sure the IDs and/or markers
  287. // are registered and borders/padding are painted.
  288. elements.add(makeAuxiliaryZeroWidthBox());
  289. }
  290. // add the forced break
  291. contentList.addAll(childElements);
  292. // wrap position and return
  293. wrapPositionElements(contentList, elements);
  294. return elements;
  295. } else {
  296. // add all accumulated child elements
  297. contentList.addAll(childElements);
  298. if (ElementListUtils.endsWithForcedBreak(childElements)) {
  299. // a descendant of this block has break-after
  300. if (currentChildLM.isFinished() && !hasNextChildLM()) {
  301. // if there is no more content, make sure any
  302. // pending marks are cleared
  303. forcedBreakAfterLast = (BreakElement) ListUtil.removeLast(contentList);
  304. context.clearPendingMarks();
  305. break;
  306. }
  307. //wrap positions and return
  308. wrapPositionElements(contentList, elements);
  309. return elements;
  310. }
  311. }
  312. context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
  313. }
  314. currentChildLM = getChildLM();
  315. }
  316. if (contentList.isEmpty()) {
  317. if (forcedBreakAfterLast == null) {
  318. // empty fo:block: zero-length box makes sure the IDs and/or markers
  319. // are registered.
  320. elements.add(makeAuxiliaryZeroWidthBox());
  321. }
  322. } else {
  323. // wrap child positions
  324. wrapPositionElements(contentList, elements);
  325. }
  326. addLastVisibleMarks(elements, context, alignment);
  327. if (forcedBreakAfterLast == null) {
  328. addKnuthElementsForBreakAfter(elements, context);
  329. } else {
  330. forcedBreakAfterLast.clearPendingMarks();
  331. elements.add(forcedBreakAfterLast);
  332. }
  333. context.updateKeepWithNextPending(getKeepWithNext());
  334. setFinished(true);
  335. return elements;
  336. }
  337. /**
  338. * Creates and initializes a {@link LayoutContext} to pass to the child LM
  339. * @param context the parent {@link LayoutContext}
  340. * @return a new child layout context
  341. */
  342. protected LayoutContext makeChildLayoutContext(LayoutContext context) {
  343. LayoutContext childLC = new LayoutContext(0);
  344. childLC.copyPendingMarksFrom(context);
  345. childLC.setStackLimitBP(context.getStackLimitBP());
  346. childLC.setRefIPD(referenceIPD);
  347. return childLC;
  348. }
  349. /**
  350. * Checks if this LM's first "visible marks" (= borders, padding, spaces) have
  351. * already been processed, and if necessary, adds corresponding elements to
  352. * the specified list, and updates the given layout context accordingly.
  353. * @param elements the element list
  354. * @param context the layout context
  355. * @param alignment the vertical alignment
  356. */
  357. protected void addFirstVisibleMarks(List<ListElement> elements,
  358. LayoutContext context, int alignment) {
  359. if (!firstVisibleMarkServed) {
  360. addKnuthElementsForSpaceBefore(elements, alignment);
  361. context.updateKeepWithPreviousPending(getKeepWithPrevious());
  362. }
  363. addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
  364. firstVisibleMarkServed = true;
  365. //Spaces, border and padding to be repeated at each break
  366. addPendingMarks(context);
  367. }
  368. /**
  369. * Adds elements the LM's last/closing marks to the specified list, and
  370. * updates the layout context accordingly.
  371. * @param elements the element list
  372. * @param context the layout context
  373. * @param alignment the vertical alignment
  374. */
  375. protected void addLastVisibleMarks(List<ListElement> elements,
  376. LayoutContext context, int alignment) {
  377. addKnuthElementsForBorderPaddingAfter(elements, true);
  378. addKnuthElementsForSpaceAfter(elements, alignment);
  379. // All child content processed. Only break-after can occur now, so...
  380. context.clearPendingMarks();
  381. }
  382. /**
  383. * Check whether there is a break-before condition. If so, and
  384. * the specified {@code context} allows it, add the necessary elements
  385. * to the given {@code elements} list.
  386. * @param context the layout context
  387. * @param elements the element list
  388. * @return {@code false} if there is a break-before condition, and it has not been served;
  389. * {@code true} otherwise
  390. */
  391. protected boolean breakBeforeServed(LayoutContext context, List<ListElement> elements) {
  392. if (!breakBeforeServed) {
  393. breakBeforeServed = true;
  394. if (!context.suppressBreakBefore()) {
  395. if (addKnuthElementsForBreakBefore(elements, context)) {
  396. return false;
  397. }
  398. }
  399. }
  400. return breakBeforeServed;
  401. }
  402. private KnuthBox makeZeroWidthBox() {
  403. return new KnuthBox(0, new NonLeafPosition(this, null), false);
  404. }
  405. private KnuthBox makeAuxiliaryZeroWidthBox() {
  406. return new KnuthBox(0, notifyPos(new Position(this)), true);
  407. }
  408. private KnuthPenalty makeZeroWidthPenalty(int penaltyValue) {
  409. return new KnuthPenalty(0, penaltyValue, false, new NonLeafPosition(this, null), false);
  410. }
  411. private KnuthGlue makeSpaceAdjustmentGlue(int width, Adjustment adjustmentClass,
  412. boolean isAuxiliary) {
  413. return new KnuthGlue(width, 0, 0,
  414. adjustmentClass,
  415. new NonLeafPosition(this, null),
  416. isAuxiliary);
  417. }
  418. /**
  419. * Gets the next set of child elements for the given childLM.
  420. * The default implementation basically copies the pending marks to the child layout context,
  421. * and subsequently calls the appropriate variant of {@code childLM.getNextKnuthElements()},
  422. * passing it all relevant parameters.
  423. * @param childLM the current child LM
  424. * @param context the layout context
  425. * @param childLC the child layout context
  426. * @param alignment the vertical alignment
  427. * @param lmStack the stack of currently active LMs (if any)
  428. * @param restartPosition the position to restart from (if any)
  429. * @param restartAtLM the LM to restart from (if any)
  430. * @return list of elements corresponding to the content generated by childLM
  431. */
  432. protected List<ListElement> getNextChildElements(LayoutManager childLM, LayoutContext context,
  433. LayoutContext childLC, int alignment, Stack<LayoutManager> lmStack,
  434. Position restartPosition, LayoutManager restartAtLM) {
  435. if (childLM == this.childLMs.get(0)) {
  436. childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
  437. //Handled already by the parent (break collapsing, see above)
  438. }
  439. if (lmStack == null) {
  440. // route to default implementation, in case childLM does not provide
  441. // an override similar to this class
  442. return childLM.getNextKnuthElements(childLC, alignment);
  443. } else {
  444. return childLM.getNextKnuthElements(childLC, alignment, lmStack,
  445. restartPosition, restartAtLM);
  446. }
  447. }
  448. /**
  449. * Adds a break element to the content list between individual child elements.
  450. * @param contentList the content list
  451. * @param parentLC the parent layout context
  452. * @param childLC the currently active child layout context
  453. */
  454. protected void addInBetweenBreak(List<ListElement> contentList, LayoutContext parentLC,
  455. LayoutContext childLC) {
  456. if (mustKeepTogether()
  457. || parentLC.isKeepWithNextPending()
  458. || childLC.isKeepWithPreviousPending()) {
  459. Keep keep = getKeepTogether();
  460. //Handle pending keep-with-next
  461. keep = keep.compare(parentLC.getKeepWithNextPending());
  462. parentLC.clearKeepWithNextPending();
  463. //Handle pending keep-with-previous from child LM
  464. keep = keep.compare(childLC.getKeepWithPreviousPending());
  465. childLC.clearKeepWithPreviousPending();
  466. // add a penalty to forbid or discourage a break between blocks
  467. contentList.add(new BreakElement(
  468. new Position(this), keep.getPenalty(),
  469. keep.getContext(), parentLC));
  470. return;
  471. }
  472. ListElement last = ListUtil.getLast(contentList);
  473. if (last.isGlue()) {
  474. // the last element in contentList is a glue;
  475. // it is a feasible breakpoint, there is no need to add
  476. // a penalty
  477. log.warn("glue-type break possibility not handled properly, yet");
  478. //TODO Does this happen? If yes, need to deal with border and padding
  479. //at the break possibility
  480. } else if (!ElementListUtils.endsWithNonInfinitePenalty(contentList)) {
  481. // TODO vh: this is hacky
  482. // The getNextKnuthElements method of TableCellLM must not be called
  483. // twice, otherwise some settings like indents or borders will be
  484. // counted several times and lead to a wrong output. Anyway the
  485. // getNextKnuthElements methods should be called only once eventually
  486. // (i.e., when multi-threading the code), even when there are forced
  487. // breaks.
  488. // If we add a break possibility after a forced break the
  489. // AreaAdditionUtil.addAreas method will act on a sequence starting
  490. // with a SpaceResolver.SpaceHandlingBreakPosition element, having no
  491. // LM associated to it. Thus it will stop early instead of adding
  492. // areas for following Positions. The above test aims at preventing
  493. // such a situation from occurring. add a null penalty to allow a break
  494. // between blocks
  495. // add a null penalty to allow a break between blocks
  496. contentList.add(new BreakElement(
  497. new Position(this), 0, Constants.EN_AUTO, parentLC));
  498. }
  499. }
  500. /** {@inheritDoc} */
  501. public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
  502. assert (lastElement != null && lastElement.getPosition() != null);
  503. Position innerPosition = lastElement.getPosition().getPosition();
  504. if (innerPosition == null && lastElement.isGlue()) {
  505. // this adjustment applies to space-before or space-after of this block
  506. if (((KnuthGlue) lastElement).getAdjustmentClass()
  507. == Adjustment.SPACE_BEFORE_ADJUSTMENT) {
  508. // this adjustment applies to space-before
  509. adjustedSpaceBefore += adj;
  510. } else {
  511. // this adjustment applies to space-after
  512. adjustedSpaceAfter += adj;
  513. }
  514. return adj;
  515. } else if (innerPosition instanceof MappingPosition) {
  516. // this block has block-progression-unit > 0: the adjustment can concern
  517. // - the space-before or space-after of this block,
  518. // - the line number of a descendant of this block
  519. MappingPosition mappingPos = (MappingPosition)innerPosition;
  520. if (lastElement.isGlue()) {
  521. // lastElement is a glue
  522. ListIterator storedListIterator = storedList.listIterator(
  523. mappingPos.getFirstIndex());
  524. int newAdjustment = 0;
  525. while (storedListIterator.nextIndex() <= mappingPos.getLastIndex()) {
  526. KnuthElement storedElement = (KnuthElement)storedListIterator.next();
  527. if (storedElement.isGlue()) {
  528. newAdjustment += ((BlockLevelLayoutManager)storedElement
  529. .getLayoutManager()).negotiateBPDAdjustment(
  530. adj - newAdjustment, storedElement);
  531. }
  532. }
  533. newAdjustment = (newAdjustment > 0 ? bpUnit * neededUnits(newAdjustment)
  534. : -bpUnit * neededUnits(-newAdjustment));
  535. return newAdjustment;
  536. } else {
  537. // lastElement is a penalty: this means that the paragraph
  538. // has been split between consecutive pages:
  539. // this may involve a change in the number of lines
  540. KnuthPenalty storedPenalty = (KnuthPenalty)
  541. storedList.get(mappingPos.getLastIndex());
  542. if (storedPenalty.getWidth() > 0) {
  543. // the original penalty has width > 0
  544. return ((BlockLevelLayoutManager)storedPenalty.getLayoutManager())
  545. .negotiateBPDAdjustment(storedPenalty.getWidth(),
  546. storedPenalty);
  547. } else {
  548. // the original penalty has width = 0
  549. // the adjustment involves only the spaces before and after
  550. return adj;
  551. }
  552. }
  553. } else if (innerPosition != null && innerPosition.getLM() != this) {
  554. // this adjustment concerns another LM
  555. NonLeafPosition savedPos = (NonLeafPosition) lastElement.getPosition();
  556. lastElement.setPosition(innerPosition);
  557. int returnValue = ((BlockLevelLayoutManager)lastElement.getLayoutManager())
  558. .negotiateBPDAdjustment(adj, lastElement);
  559. lastElement.setPosition(savedPos);
  560. return returnValue;
  561. } else {
  562. // this should never happen
  563. log.error("BlockLayoutManager.negotiateBPDAdjustment(): unexpected Position");
  564. return 0;
  565. }
  566. }
  567. /** {@inheritDoc} */
  568. public void discardSpace(KnuthGlue spaceGlue) {
  569. assert (spaceGlue != null && spaceGlue.getPosition() != null);
  570. Position innerPosition = spaceGlue.getPosition().getPosition();
  571. if (innerPosition == null || innerPosition.getLM() == this) {
  572. // if this block has block-progression-unit > 0, innerPosition can be
  573. // a MappingPosition
  574. // spaceGlue represents space before or space after of this block
  575. if (spaceGlue.getAdjustmentClass() == Adjustment.SPACE_BEFORE_ADJUSTMENT) {
  576. // space-before must be discarded
  577. adjustedSpaceBefore = 0;
  578. foSpaceBefore = MinOptMax.ZERO;
  579. } else {
  580. // space-after must be discarded
  581. adjustedSpaceAfter = 0;
  582. foSpaceAfter = MinOptMax.ZERO;
  583. //TODO Why are both cases handled in the same way?
  584. }
  585. } else {
  586. // this element was not created by this BlockLM
  587. NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition();
  588. spaceGlue.setPosition(innerPosition);
  589. ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
  590. spaceGlue.setPosition(savedPos);
  591. }
  592. }
  593. /** {@inheritDoc} */
  594. @Override
  595. public List getChangedKnuthElements(List oldList, int alignment) {
  596. ListIterator<KnuthElement> oldListIterator = oldList.listIterator();
  597. KnuthElement currElement = null;
  598. KnuthElement prevElement = null;
  599. List<KnuthElement> returnedList = new LinkedList<KnuthElement>();
  600. List<KnuthElement> returnList = new LinkedList<KnuthElement>();
  601. int fromIndex = 0;
  602. // "unwrap" the Positions stored in the elements
  603. KnuthElement oldElement;
  604. while (oldListIterator.hasNext()) {
  605. oldElement = oldListIterator.next();
  606. assert oldElement.getPosition() != null;
  607. Position innerPosition = oldElement.getPosition().getPosition();
  608. if (innerPosition != null) {
  609. // oldElement was created by a descendant
  610. oldElement.setPosition(innerPosition);
  611. } else {
  612. // oldElement was created by this LM:
  613. // modify its position in order to recognize it was not created
  614. // by a child
  615. oldElement.setPosition(new Position(this));
  616. }
  617. }
  618. // create the iterator
  619. ListIterator<KnuthElement> workListIterator = oldList.listIterator();
  620. while (workListIterator.hasNext()) {
  621. currElement = workListIterator.next();
  622. if (prevElement != null
  623. && prevElement.getLayoutManager() != currElement.getLayoutManager()) {
  624. // prevElement is the last element generated by the same LM
  625. BlockLevelLayoutManager prevLM
  626. = (BlockLevelLayoutManager)prevElement.getLayoutManager();
  627. BlockLevelLayoutManager currLM
  628. = (BlockLevelLayoutManager)currElement.getLayoutManager();
  629. boolean somethingAdded = false;
  630. if (prevLM != this) {
  631. returnedList.addAll(
  632. prevLM.getChangedKnuthElements(
  633. oldList.subList(fromIndex, workListIterator.previousIndex()),
  634. alignment));
  635. somethingAdded = true;
  636. } else {
  637. // do nothing
  638. }
  639. fromIndex = workListIterator.previousIndex();
  640. /*
  641. * TODO: why are KnuthPenalties added here,
  642. * while in getNextKE they were changed to BreakElements?
  643. */
  644. // there is another block after this one
  645. if (somethingAdded
  646. && (this.mustKeepTogether()
  647. || prevLM.mustKeepWithNext()
  648. || currLM.mustKeepWithPrevious())) {
  649. // add an infinite penalty to forbid a break between blocks
  650. returnedList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
  651. } else if (somethingAdded
  652. && !ListUtil.getLast(returnedList).isGlue()) {
  653. // add a null penalty to allow a break between blocks
  654. returnedList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
  655. }
  656. }
  657. prevElement = currElement;
  658. }
  659. if (currElement != null) {
  660. LayoutManager currLM = currElement.getLayoutManager();
  661. if (currLM != this) {
  662. returnedList.addAll(currLM.getChangedKnuthElements(
  663. oldList.subList(fromIndex, oldList.size()), alignment));
  664. } else {
  665. // there are no more elements to add
  666. // remove the last penalty added to returnedList
  667. if (!returnedList.isEmpty()) {
  668. ListUtil.removeLast(returnedList);
  669. }
  670. }
  671. }
  672. // append elements representing space-before
  673. boolean spaceBeforeIsConditional = true;
  674. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  675. spaceBeforeIsConditional = getSpaceBeforeProperty().isDiscard();
  676. }
  677. if (adjustedSpaceBefore != 0) {
  678. if (!spaceBeforeIsConditional) {
  679. // add elements to prevent the glue to be discarded
  680. returnList.add(makeZeroWidthBox());
  681. returnList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
  682. }
  683. returnList.add(makeSpaceAdjustmentGlue(adjustedSpaceBefore,
  684. Adjustment.SPACE_BEFORE_ADJUSTMENT,
  685. false));
  686. }
  687. // "wrap" the Position stored in each element of returnedList
  688. // and add elements to returnList
  689. for (KnuthElement el : returnedList) {
  690. el.setPosition(new NonLeafPosition(this, el.getPosition()));
  691. returnList.add(el);
  692. }
  693. // append elements representing space-after
  694. boolean spaceAfterIsConditional = true;
  695. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  696. spaceAfterIsConditional = getSpaceAfterProperty().isDiscard();
  697. }
  698. if (adjustedSpaceAfter != 0) {
  699. if (!spaceAfterIsConditional) {
  700. returnList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
  701. }
  702. returnList.add(makeSpaceAdjustmentGlue(adjustedSpaceAfter,
  703. Adjustment.SPACE_AFTER_ADJUSTMENT,
  704. spaceAfterIsConditional));
  705. if (!spaceAfterIsConditional) {
  706. returnList.add(makeZeroWidthBox());
  707. }
  708. }
  709. return returnList;
  710. }
  711. /**
  712. * Retrieves and returns the keep-together strength from the parent element.
  713. * @return the keep-together strength
  714. */
  715. protected Keep getParentKeepTogether() {
  716. Keep keep = Keep.KEEP_AUTO;
  717. if (getParent() instanceof BlockLevelLayoutManager) {
  718. keep = ((BlockLevelLayoutManager)getParent()).getKeepTogether();
  719. } else if (getParent() instanceof InlineLayoutManager) {
  720. if (((InlineLayoutManager) getParent()).mustKeepTogether()) {
  721. keep = Keep.KEEP_ALWAYS;
  722. }
  723. //TODO Fix me
  724. //strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength();
  725. }
  726. return keep;
  727. }
  728. /** {@inheritDoc} */
  729. public boolean mustKeepTogether() {
  730. return !getKeepTogether().isAuto();
  731. }
  732. /** {@inheritDoc} */
  733. public boolean mustKeepWithPrevious() {
  734. return !getKeepWithPrevious().isAuto();
  735. }
  736. /** {@inheritDoc} */
  737. public boolean mustKeepWithNext() {
  738. return !getKeepWithNext().isAuto();
  739. }
  740. /** {@inheritDoc} */
  741. public Keep getKeepTogether() {
  742. Keep keep = Keep.getKeep(getKeepTogetherProperty());
  743. keep = keep.compare(getParentKeepTogether());
  744. return keep;
  745. }
  746. /** {@inheritDoc} */
  747. public Keep getKeepWithPrevious() {
  748. return Keep.getKeep(getKeepWithPreviousProperty());
  749. }
  750. /** {@inheritDoc} */
  751. public Keep getKeepWithNext() {
  752. return Keep.getKeep(getKeepWithNextProperty());
  753. }
  754. /**
  755. * {@inheritDoc}
  756. * Default implementation throws a {@link IllegalStateException}.
  757. * Must be implemented by the subclass, if applicable.
  758. */
  759. public KeepProperty getKeepTogetherProperty() {
  760. throw new IllegalStateException();
  761. }
  762. /**
  763. * {@inheritDoc}
  764. * Default implementation throws a {@link IllegalStateException}.
  765. * Must be implemented by the subclass, if applicable.
  766. */
  767. public KeepProperty getKeepWithPreviousProperty() {
  768. throw new IllegalStateException();
  769. }
  770. /**
  771. * {@inheritDoc}
  772. * Default implementation throws a {@link IllegalStateException}.
  773. * Must be implemented by the subclass, if applicable.
  774. */
  775. public KeepProperty getKeepWithNextProperty() {
  776. throw new IllegalStateException();
  777. }
  778. /**
  779. * Adds the unresolved elements for border and padding to a layout context so break
  780. * possibilities can be properly constructed.
  781. * @param context the layout context
  782. */
  783. protected void addPendingMarks(LayoutContext context) {
  784. CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground();
  785. if (borderAndPadding != null) {
  786. if (borderAndPadding.getBorderBeforeWidth(false) > 0) {
  787. context.addPendingBeforeMark(new BorderElement(
  788. getAuxiliaryPosition(),
  789. borderAndPadding.getBorderInfo(
  790. CommonBorderPaddingBackground.BEFORE).getWidth(),
  791. RelSide.BEFORE,
  792. false, false, this));
  793. }
  794. if (borderAndPadding.getPaddingBefore(false, this) > 0) {
  795. context.addPendingBeforeMark(new PaddingElement(
  796. getAuxiliaryPosition(),
  797. borderAndPadding.getPaddingLengthProperty(
  798. CommonBorderPaddingBackground.BEFORE),
  799. RelSide.BEFORE,
  800. false, false, this));
  801. }
  802. if (borderAndPadding.getBorderAfterWidth(false) > 0) {
  803. context.addPendingAfterMark(new BorderElement(
  804. getAuxiliaryPosition(),
  805. borderAndPadding.getBorderInfo(
  806. CommonBorderPaddingBackground.AFTER).getWidth(),
  807. RelSide.AFTER,
  808. false, false, this));
  809. }
  810. if (borderAndPadding.getPaddingAfter(false, this) > 0) {
  811. context.addPendingAfterMark(new PaddingElement(
  812. getAuxiliaryPosition(),
  813. borderAndPadding.getPaddingLengthProperty(
  814. CommonBorderPaddingBackground.AFTER),
  815. RelSide.AFTER,
  816. false, false, this));
  817. }
  818. }
  819. }
  820. /** @return the border, padding and background info structure */
  821. private CommonBorderPaddingBackground getBorderPaddingBackground() {
  822. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  823. return ((org.apache.fop.fo.flow.Block)fobj)
  824. .getCommonBorderPaddingBackground();
  825. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  826. return ((org.apache.fop.fo.flow.BlockContainer)fobj)
  827. .getCommonBorderPaddingBackground();
  828. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  829. return ((org.apache.fop.fo.flow.ListBlock)fobj)
  830. .getCommonBorderPaddingBackground();
  831. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  832. return ((org.apache.fop.fo.flow.ListItem)fobj)
  833. .getCommonBorderPaddingBackground();
  834. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  835. return ((org.apache.fop.fo.flow.table.Table)fobj)
  836. .getCommonBorderPaddingBackground();
  837. } else {
  838. return null;
  839. }
  840. }
  841. /** @return the space-before property */
  842. protected SpaceProperty getSpaceBeforeProperty() {
  843. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  844. return ((org.apache.fop.fo.flow.Block)fobj)
  845. .getCommonMarginBlock().spaceBefore;
  846. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  847. return ((org.apache.fop.fo.flow.BlockContainer)fobj)
  848. .getCommonMarginBlock().spaceBefore;
  849. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  850. return ((org.apache.fop.fo.flow.ListBlock)fobj)
  851. .getCommonMarginBlock().spaceBefore;
  852. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  853. return ((org.apache.fop.fo.flow.ListItem)fobj)
  854. .getCommonMarginBlock().spaceBefore;
  855. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  856. return ((org.apache.fop.fo.flow.table.Table)fobj)
  857. .getCommonMarginBlock().spaceBefore;
  858. } else {
  859. return null;
  860. }
  861. }
  862. /** @return the space-after property */
  863. protected SpaceProperty getSpaceAfterProperty() {
  864. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  865. return ((org.apache.fop.fo.flow.Block)fobj)
  866. .getCommonMarginBlock().spaceAfter;
  867. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  868. return ((org.apache.fop.fo.flow.BlockContainer)fobj)
  869. .getCommonMarginBlock().spaceAfter;
  870. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  871. return ((org.apache.fop.fo.flow.ListBlock)fobj)
  872. .getCommonMarginBlock().spaceAfter;
  873. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  874. return ((org.apache.fop.fo.flow.ListItem)fobj)
  875. .getCommonMarginBlock().spaceAfter;
  876. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  877. return ((org.apache.fop.fo.flow.table.Table)fobj)
  878. .getCommonMarginBlock().spaceAfter;
  879. } else {
  880. return null;
  881. }
  882. }
  883. /**
  884. * Creates Knuth elements for before border padding and adds them to the return list.
  885. * @param returnList return list to add the additional elements to
  886. * @param isFirst true if this is the first time a layout manager instance needs to generate
  887. * border and padding
  888. */
  889. protected void addKnuthElementsForBorderPaddingBefore(List returnList, boolean isFirst) {
  890. //Border and Padding (before)
  891. CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground();
  892. if (borderAndPadding != null) {
  893. if (borderAndPadding.getBorderBeforeWidth(false) > 0) {
  894. returnList.add(new BorderElement(
  895. getAuxiliaryPosition(),
  896. borderAndPadding.getBorderInfo(CommonBorderPaddingBackground.BEFORE)
  897. .getWidth(),
  898. RelSide.BEFORE, isFirst, false, this));
  899. }
  900. if (borderAndPadding.getPaddingBefore(false, this) > 0) {
  901. returnList.add(new PaddingElement(
  902. getAuxiliaryPosition(),
  903. borderAndPadding.getPaddingLengthProperty(
  904. CommonBorderPaddingBackground.BEFORE),
  905. RelSide.BEFORE, isFirst, false, this));
  906. }
  907. }
  908. }
  909. /**
  910. * Creates Knuth elements for after border padding and adds them to the return list.
  911. * @param returnList return list to add the additional elements to
  912. * @param isLast true if this is the last time a layout manager instance needs to generate
  913. * border and padding
  914. */
  915. protected void addKnuthElementsForBorderPaddingAfter(List returnList, boolean isLast) {
  916. //Border and Padding (after)
  917. CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground();
  918. if (borderAndPadding != null) {
  919. if (borderAndPadding.getPaddingAfter(false, this) > 0) {
  920. returnList.add(new PaddingElement(
  921. getAuxiliaryPosition(),
  922. borderAndPadding.getPaddingLengthProperty(
  923. CommonBorderPaddingBackground.AFTER),
  924. RelSide.AFTER, false, isLast, this));
  925. }
  926. if (borderAndPadding.getBorderAfterWidth(false) > 0) {
  927. returnList.add(new BorderElement(
  928. getAuxiliaryPosition(),
  929. borderAndPadding.getBorderInfo(CommonBorderPaddingBackground.AFTER)
  930. .getWidth(),
  931. RelSide.AFTER, false, isLast, this));
  932. }
  933. }
  934. }
  935. /**
  936. * Creates Knuth elements for break-before and adds them to the return list.
  937. * @param returnList return list to add the additional elements to
  938. * @param context the layout context
  939. * @return true if an element has been added due to a break-before.
  940. */
  941. protected boolean addKnuthElementsForBreakBefore(List returnList, LayoutContext context) {
  942. int breakBefore = BreakOpportunityHelper.getBreakBefore(this);
  943. if (breakBefore == EN_PAGE
  944. || breakBefore == EN_COLUMN
  945. || breakBefore == EN_EVEN_PAGE
  946. || breakBefore == EN_ODD_PAGE) {
  947. // return a penalty element, representing a forced page break
  948. returnList.add(new BreakElement(getAuxiliaryPosition(),
  949. 0, -KnuthElement.INFINITE, breakBefore, context));
  950. return true;
  951. } else {
  952. return false;
  953. }
  954. }
  955. /**
  956. * Creates Knuth elements for break-after and adds them to the return list.
  957. * @param returnList return list to add the additional elements to
  958. * @param context the layout context
  959. * @return true if an element has been added due to a break-after.
  960. */
  961. protected boolean addKnuthElementsForBreakAfter(List returnList, LayoutContext context) {
  962. int breakAfter = -1;
  963. if (fobj instanceof BreakPropertySet) {
  964. breakAfter = ((BreakPropertySet)fobj).getBreakAfter();
  965. }
  966. if (breakAfter == EN_PAGE
  967. || breakAfter == EN_COLUMN
  968. || breakAfter == EN_EVEN_PAGE
  969. || breakAfter == EN_ODD_PAGE) {
  970. // add a penalty element, representing a forced page break
  971. returnList.add(new BreakElement(getAuxiliaryPosition(),
  972. 0, -KnuthElement.INFINITE, breakAfter, context));
  973. return true;
  974. } else {
  975. return false;
  976. }
  977. }
  978. /**
  979. * Creates Knuth elements for space-before and adds them to the return list.
  980. * @param returnList return list to add the additional elements to
  981. * @param alignment vertical alignment
  982. */
  983. protected void addKnuthElementsForSpaceBefore(List returnList, int alignment) {
  984. SpaceProperty spaceBefore = getSpaceBeforeProperty();
  985. // append elements representing space-before
  986. if (spaceBefore != null
  987. && !(spaceBefore.getMinimum(this).getLength().getValue(this) == 0
  988. && spaceBefore.getMaximum(this).getLength().getValue(this) == 0)) {
  989. returnList.add(new SpaceElement(getAuxiliaryPosition(), spaceBefore,
  990. RelSide.BEFORE,
  991. true, false, this));
  992. }
  993. }
  994. /**
  995. * Creates Knuth elements for space-after and adds them to the return list.
  996. * @param returnList return list to add the additional elements to
  997. * @param alignment vertical alignment
  998. */
  999. protected void addKnuthElementsForSpaceAfter(List returnList, int alignment) {
  1000. SpaceProperty spaceAfter = getSpaceAfterProperty();
  1001. // append elements representing space-after
  1002. if (spaceAfter != null
  1003. && !(spaceAfter.getMinimum(this).getLength().getValue(this) == 0
  1004. && spaceAfter.getMaximum(this).getLength().getValue(this) == 0)) {
  1005. returnList.add(new SpaceElement(getAuxiliaryPosition(), spaceAfter,
  1006. RelSide.AFTER,
  1007. false, true, this));
  1008. }
  1009. }
  1010. /** A mapping position. */
  1011. protected static class MappingPosition extends Position {
  1012. private int firstIndex;
  1013. private int lastIndex;
  1014. /**
  1015. * Construct mapping position.
  1016. * @param lm layout manager
  1017. * @param first position
  1018. * @param last position
  1019. */
  1020. public MappingPosition(LayoutManager lm, int first, int last) {
  1021. super(lm);
  1022. firstIndex = first;
  1023. lastIndex = last;
  1024. }
  1025. /** @return first index */
  1026. public int getFirstIndex() {
  1027. return firstIndex;
  1028. }
  1029. /** @return last index */
  1030. public int getLastIndex() {
  1031. return lastIndex;
  1032. }
  1033. }
  1034. /**
  1035. * "wrap" the Position inside each element moving the elements from
  1036. * SourceList to targetList
  1037. * @param sourceList source list
  1038. * @param targetList target list receiving the wrapped position elements
  1039. */
  1040. protected void wrapPositionElements(List sourceList, List targetList) {
  1041. wrapPositionElements(sourceList, targetList, false);
  1042. }
  1043. /**
  1044. * "wrap" the Position inside each element moving the elements from
  1045. * SourceList to targetList
  1046. * @param sourceList source list
  1047. * @param targetList target list receiving the wrapped position elements
  1048. * @param force if true, every Position is wrapped regardless of its LM of origin
  1049. */
  1050. protected void wrapPositionElements(List sourceList, List targetList, boolean force) {
  1051. ListIterator listIter = sourceList.listIterator();
  1052. Object tempElement;
  1053. while (listIter.hasNext()) {
  1054. tempElement = listIter.next();
  1055. if (tempElement instanceof ListElement) {
  1056. wrapPositionElement(
  1057. (ListElement) tempElement,
  1058. targetList,
  1059. force);
  1060. } else if (tempElement instanceof List) {
  1061. wrapPositionElements(
  1062. (List) tempElement,
  1063. targetList,
  1064. force);
  1065. }
  1066. }
  1067. }
  1068. /**
  1069. * "wrap" the Position inside the given element and add it to the target list.
  1070. * @param el the list element
  1071. * @param targetList target list receiving the wrapped position elements
  1072. * @param force if true, every Position is wrapped regardless of its LM of origin
  1073. */
  1074. protected void wrapPositionElement(ListElement el, List targetList, boolean force) {
  1075. if (force || el.getLayoutManager() != this) {
  1076. el.setPosition(notifyPos(new NonLeafPosition(this, el.getPosition())));
  1077. }
  1078. targetList.add(el);
  1079. }
  1080. /** @return the sum of start-indent and end-indent */
  1081. protected int getIPIndents() {
  1082. return startIndent + endIndent;
  1083. }
  1084. /**
  1085. * Returns the IPD of the content area
  1086. * @return the IPD of the content area
  1087. */
  1088. @Override
  1089. public int getContentAreaIPD() {
  1090. return contentAreaIPD;
  1091. }
  1092. /**
  1093. * Sets the IPD of the content area
  1094. * @param contentAreaIPD the IPD of the content area
  1095. */
  1096. protected void setContentAreaIPD(int contentAreaIPD) {
  1097. this.contentAreaIPD = contentAreaIPD;
  1098. }
  1099. /**
  1100. * Returns the BPD of the content area
  1101. * @return the BPD of the content area
  1102. */
  1103. @Override
  1104. public int getContentAreaBPD() {
  1105. return -1;
  1106. }
  1107. /** {@inheritDoc} */
  1108. @Override
  1109. public void reset() {
  1110. super.reset();
  1111. breakBeforeServed = false;
  1112. firstVisibleMarkServed = false;
  1113. // TODO startIndent, endIndent
  1114. }
  1115. /**
  1116. * Whether this LM can handle horizontal overflow error messages (only a BlockContainerLayoutManager can).
  1117. * @param milliPoints horizontal overflow
  1118. * @return true if handled by a BlockContainerLayoutManager
  1119. */
  1120. public boolean handleOverflow(int milliPoints) {
  1121. if (getParent() instanceof BlockStackingLayoutManager) {
  1122. return ((BlockStackingLayoutManager) getParent()).handleOverflow(milliPoints);
  1123. }
  1124. return false;
  1125. }
  1126. }