Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

BlockStackingLayoutManager.java 52KB

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