Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

BlockStackingLayoutManager.java 51KB

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