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

BlockStackingLayoutManager.java 73KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597
  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.Iterator;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.ListIterator;
  23. import org.apache.commons.logging.Log;
  24. import org.apache.commons.logging.LogFactory;
  25. import org.apache.fop.area.Area;
  26. import org.apache.fop.area.Block;
  27. import org.apache.fop.area.BlockParent;
  28. import org.apache.fop.fo.FObj;
  29. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  30. import org.apache.fop.fo.properties.SpaceProperty;
  31. import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
  32. import org.apache.fop.layoutmgr.inline.LineLayoutManager;
  33. import org.apache.fop.traits.MinOptMax;
  34. import org.apache.fop.util.ListUtil;
  35. /**
  36. * Base LayoutManager class for all areas which stack their child
  37. * areas in the block-progression direction, such as Flow, Block, ListBlock.
  38. */
  39. public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
  40. implements BlockLevelLayoutManager {
  41. /**
  42. * logging instance
  43. */
  44. private static Log log = LogFactory.getLog(BlockStackingLayoutManager.class);
  45. /**
  46. * Reference to FO whose areas it's managing or to the traits
  47. * of the FO.
  48. */
  49. //protected LayoutManager curChildLM = null; AbstractLayoutManager also defines this!
  50. protected BlockParent parentArea = null;
  51. /** Value of the block-progression-unit (non-standard property) */
  52. protected int bpUnit = 0;
  53. /** space-before value adjusted for block-progression-unit handling */
  54. protected int adjustedSpaceBefore = 0;
  55. /** space-after value adjusted for block-progression-unit handling */
  56. protected int adjustedSpaceAfter = 0;
  57. /** Only used to store the original list when createUnitElements is called */
  58. protected List storedList = null;
  59. /** Indicates whether break before has been served or not */
  60. protected boolean breakBeforeServed = false;
  61. /** Indicates whether the first visible mark has been returned by this LM, yet */
  62. protected boolean firstVisibleMarkServed = false;
  63. /** Reference IPD available */
  64. protected int referenceIPD = 0;
  65. /** the effective start-indent value */
  66. protected int startIndent = 0;
  67. /** the effective end-indent value */
  68. protected int endIndent = 0;
  69. /**
  70. * Holds the (one-time use) fo:block space-before
  71. * and -after properties. Large fo:blocks are split
  72. * into multiple Area. Blocks to accomodate the subsequent
  73. * regions (pages) they are placed on. space-before
  74. * is applied at the beginning of the first
  75. * Block and space-after at the end of the last Block
  76. * used in rendering the fo:block.
  77. */
  78. protected MinOptMax foSpaceBefore = null;
  79. /** see foSpaceBefore */
  80. protected MinOptMax foSpaceAfter = null;
  81. private Position auxiliaryPosition;
  82. private int contentAreaIPD = 0;
  83. /**
  84. * @param node the fo this LM deals with
  85. */
  86. public BlockStackingLayoutManager(FObj node) {
  87. super(node);
  88. setGeneratesBlockArea(true);
  89. }
  90. /**
  91. * @return current area being filled
  92. */
  93. protected BlockParent getCurrentArea() {
  94. return this.parentArea;
  95. }
  96. /**
  97. * Set the current area being filled.
  98. * @param parentArea the current area to be filled
  99. */
  100. protected void setCurrentArea(BlockParent parentArea) {
  101. this.parentArea = parentArea;
  102. }
  103. /**
  104. * Add a block spacer for space before and space after a block.
  105. * This adds an empty Block area that acts as a block space.
  106. *
  107. * @param adjust the adjustment value
  108. * @param minoptmax the min/opt/max value of the spacing
  109. */
  110. public void addBlockSpacing(double adjust, MinOptMax minoptmax) {
  111. int sp = TraitSetter.getEffectiveSpace(adjust, minoptmax);
  112. if (sp != 0) {
  113. Block spacer = new Block();
  114. spacer.setBPD(sp);
  115. parentLM.addChildArea(spacer);
  116. }
  117. }
  118. /**
  119. * Add the childArea to the passed area.
  120. * Called by child LayoutManager when it has filled one of its areas.
  121. * The LM should already have an Area in which to put the child.
  122. * See if the area will fit in the current area.
  123. * If so, add it. Otherwise initiate breaking.
  124. * @param childArea the area to add: will be some block-stacked Area.
  125. * @param parentArea the area in which to add the childArea
  126. */
  127. protected void addChildToArea(Area childArea,
  128. BlockParent parentArea) {
  129. // This should be a block-level Area (Block in the generic sense)
  130. if (!(childArea instanceof Block)) {
  131. //log.error("Child not a Block in BlockStackingLM!");
  132. }
  133. parentArea.addBlock((Block) childArea);
  134. flush(); // hand off current area to parent
  135. }
  136. /**
  137. * Add the childArea to the current area.
  138. * Called by child LayoutManager when it has filled one of its areas.
  139. * The LM should already have an Area in which to put the child.
  140. * See if the area will fit in the current area.
  141. * If so, add it. Otherwise initiate breaking.
  142. * @param childArea the area to add: will be some block-stacked Area.
  143. */
  144. public void addChildArea(Area childArea) {
  145. addChildToArea(childArea, getCurrentArea());
  146. }
  147. /**
  148. * Force current area to be added to parent area.
  149. */
  150. protected void flush() {
  151. if (getCurrentArea() != null) {
  152. parentLM.addChildArea(getCurrentArea());
  153. }
  154. }
  155. /** @return a cached auxiliary Position instance used for things like spaces. */
  156. protected Position getAuxiliaryPosition() {
  157. if (this.auxiliaryPosition == null) {
  158. this.auxiliaryPosition = new NonLeafPosition(this, null);
  159. }
  160. return this.auxiliaryPosition;
  161. }
  162. /**
  163. * @param len length in millipoints to span with bp units
  164. * @return the minimum integer n such that n * bpUnit >= len
  165. */
  166. protected int neededUnits(int len) {
  167. return (int) Math.ceil((float)len / bpUnit);
  168. }
  169. /**
  170. * Determines and sets the content area IPD based on available reference area IPD, start- and
  171. * end-indent properties.
  172. * end-indent is adjusted based on overconstrained geometry rules, if necessary.
  173. *
  174. * @return the resulting content area IPD
  175. */
  176. protected int updateContentAreaIPDwithOverconstrainedAdjust() {
  177. int ipd = referenceIPD - (startIndent + endIndent);
  178. if (ipd < 0) {
  179. //5.3.4, XSL 1.0, Overconstrained Geometry
  180. log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj);
  181. BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
  182. getFObj().getUserAgent().getEventBroadcaster());
  183. eventProducer.overconstrainedAdjustEndIndent(this,
  184. getFObj().getName(), ipd, getFObj().getLocator());
  185. endIndent += ipd;
  186. ipd = 0;
  187. //TODO Should we skip layout for a block that has ipd=0?
  188. }
  189. setContentAreaIPD(ipd);
  190. return ipd;
  191. }
  192. /**
  193. * Sets the content area IPD by directly supplying the value.
  194. * end-indent is adjusted based on overconstrained geometry rules, if necessary.
  195. * @param contentIPD the IPD of the content
  196. * @return the resulting content area IPD
  197. */
  198. protected int updateContentAreaIPDwithOverconstrainedAdjust(int contentIPD) {
  199. int ipd = referenceIPD - (contentIPD + (startIndent + endIndent));
  200. if (ipd < 0) {
  201. //5.3.4, XSL 1.0, Overconstrained Geometry
  202. log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj);
  203. BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
  204. getFObj().getUserAgent().getEventBroadcaster());
  205. eventProducer.overconstrainedAdjustEndIndent(this,
  206. getFObj().getName(), ipd, getFObj().getLocator());
  207. endIndent += ipd;
  208. }
  209. setContentAreaIPD(contentIPD);
  210. return contentIPD;
  211. }
  212. /** {@inheritDoc} */
  213. public List getNextKnuthElements(LayoutContext context, int alignment) {
  214. //log.debug("BLM.getNextKnuthElements> keep-together = "
  215. // + layoutProps.keepTogether.getType());
  216. //log.debug(" keep-with-previous = " +
  217. // layoutProps.keepWithPrevious.getType());
  218. //log.debug(" keep-with-next = " +
  219. // layoutProps.keepWithNext.getType());
  220. BlockLevelLayoutManager curLM; // currently active LM
  221. BlockLevelLayoutManager prevLM = null; // previously active LM
  222. referenceIPD = context.getRefIPD();
  223. updateContentAreaIPDwithOverconstrainedAdjust();
  224. List returnedList = null;
  225. List contentList = new LinkedList();
  226. List returnList = new LinkedList();
  227. if (!breakBeforeServed) {
  228. try {
  229. if (addKnuthElementsForBreakBefore(returnList, context)) {
  230. return returnList;
  231. }
  232. } finally {
  233. breakBeforeServed = true;
  234. }
  235. }
  236. if (!firstVisibleMarkServed) {
  237. addKnuthElementsForSpaceBefore(returnList, alignment);
  238. context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
  239. }
  240. addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
  241. firstVisibleMarkServed = true;
  242. //Spaces, border and padding to be repeated at each break
  243. addPendingMarks(context);
  244. //Used to indicate a special break-after case when all content has already been generated.
  245. BreakElement forcedBreakAfterLast = null;
  246. while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
  247. LayoutContext childLC = new LayoutContext(0);
  248. childLC.copyPendingMarksFrom(context);
  249. if (curLM instanceof LineLayoutManager) {
  250. // curLM is a LineLayoutManager
  251. // set stackLimit for lines (stack limit is now i-p-direction, not b-p-direction!)
  252. childLC.setStackLimitBP(context.getStackLimitBP());
  253. childLC.setStackLimitIP(new MinOptMax(getContentAreaIPD()));
  254. childLC.setRefIPD(getContentAreaIPD());
  255. } else {
  256. // curLM is a ?
  257. //childLC.setStackLimit(MinOptMax.subtract(context
  258. // .getStackLimit(), stackSize));
  259. childLC.setStackLimitBP(context.getStackLimitBP());
  260. childLC.setRefIPD(referenceIPD);
  261. }
  262. // get elements from curLM
  263. returnedList = curLM.getNextKnuthElements(childLC, alignment);
  264. if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
  265. //Propagate keep-with-previous up from the first child
  266. context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
  267. childLC.clearKeepWithPreviousPending();
  268. }
  269. if (returnedList != null
  270. && returnedList.size() == 1
  271. && ((ListElement) returnedList.get(0)).isForcedBreak()) {
  272. if (curLM.isFinished() && !hasNextChildLM()) {
  273. // a descendant of this block has break-before
  274. forcedBreakAfterLast = (BreakElement) returnedList.get(0);
  275. context.clearPendingMarks();
  276. break;
  277. }
  278. if (contentList.isEmpty()) {
  279. // Empty fo:block, zero-length box makes sure the IDs and/or markers
  280. // are registered and borders/padding are painted.
  281. returnList.add(new KnuthBox(0, notifyPos(new Position(this)), false));
  282. }
  283. // a descendant of this block has break-before
  284. contentList.addAll(returnedList);
  285. /* extension: conversione di tutta la sequenza fin'ora ottenuta */
  286. if (bpUnit > 0) {
  287. storedList = contentList;
  288. contentList = createUnitElements(contentList);
  289. }
  290. /* end of extension */
  291. // "wrap" the Position inside each element
  292. // moving the elements from contentList to returnList
  293. returnedList = new LinkedList();
  294. wrapPositionElements(contentList, returnList);
  295. return returnList;
  296. } else {
  297. if (prevLM != null) {
  298. // there is a block handled by prevLM
  299. // before the one handled by curLM
  300. addInBetweenBreak(contentList, context, childLC);
  301. }
  302. if (returnedList == null || returnedList.isEmpty()) {
  303. //Avoid NoSuchElementException below (happens with empty blocks)
  304. continue;
  305. }
  306. contentList.addAll(returnedList);
  307. if (((ListElement) ListUtil.getLast(returnedList))
  308. .isForcedBreak()) {
  309. // a descendant of this block has break-after
  310. if (curLM.isFinished() && !hasNextChildLM()) {
  311. forcedBreakAfterLast = (BreakElement) ListUtil
  312. .removeLast(contentList);
  313. context.clearPendingMarks();
  314. break;
  315. }
  316. /* extension: conversione di tutta la sequenza fin'ora ottenuta */
  317. if (bpUnit > 0) {
  318. storedList = contentList;
  319. contentList = createUnitElements(contentList);
  320. }
  321. /* end of extension */
  322. returnedList = new LinkedList();
  323. wrapPositionElements(contentList, returnList);
  324. return returnList;
  325. }
  326. }
  327. // propagate and clear
  328. context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
  329. childLC.clearKeepsPending();
  330. prevLM = curLM;
  331. }
  332. /* Extension: conversione di tutta la sequenza fin'ora ottenuta */
  333. if (bpUnit > 0) {
  334. storedList = contentList;
  335. contentList = createUnitElements(contentList);
  336. }
  337. /* end of extension */
  338. returnedList = new LinkedList();
  339. if (!contentList.isEmpty()) {
  340. wrapPositionElements(contentList, returnList);
  341. } else if (forcedBreakAfterLast == null) {
  342. // Empty fo:block, zero-length box makes sure the IDs and/or markers
  343. // are registered.
  344. returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true));
  345. }
  346. addKnuthElementsForBorderPaddingAfter(returnList, true);
  347. addKnuthElementsForSpaceAfter(returnList, alignment);
  348. //All child content is processed. Only break-after can occur now, so...
  349. context.clearPendingMarks();
  350. if (forcedBreakAfterLast == null) {
  351. addKnuthElementsForBreakAfter(returnList, context);
  352. }
  353. if (forcedBreakAfterLast != null) {
  354. forcedBreakAfterLast.clearPendingMarks();
  355. wrapPositionElement(forcedBreakAfterLast, returnList, false);
  356. }
  357. context.updateKeepWithNextPending(getKeepWithNextStrength());
  358. setFinished(true);
  359. return returnList;
  360. }
  361. /**
  362. * Adds a break element to the content list between individual child elements.
  363. * @param contentList the content list to populate
  364. * @param context the current layout context
  365. * @param childLC the currently active child layout context
  366. */
  367. protected void addInBetweenBreak(List contentList, LayoutContext context,
  368. LayoutContext childLC) {
  369. if (mustKeepTogether()
  370. || context.isKeepWithNextPending()
  371. || childLC.isKeepWithPreviousPending()) {
  372. int strength = getKeepTogetherStrength();
  373. //Handle pending keep-with-next
  374. strength = Math.max(strength, context.getKeepWithNextPending());
  375. context.clearKeepWithNextPending();
  376. //Handle pending keep-with-previous from child LM
  377. strength = Math.max(strength, childLC.getKeepWithPreviousPending());
  378. childLC.clearKeepWithPreviousPending();
  379. int penalty = KeepUtil.getPenaltyForKeep(strength);
  380. // add a penalty to forbid or discourage a break between blocks
  381. contentList.add(new BreakElement(
  382. new Position(this), penalty, context));
  383. return;
  384. }
  385. ListElement last = (ListElement) ListUtil.getLast(contentList);
  386. if (last.isGlue()) {
  387. // the last element in contentList is a glue;
  388. // it is a feasible breakpoint, there is no need to add
  389. // a penalty
  390. log.warn("glue-type break possibility not handled properly, yet");
  391. //TODO Does this happen? If yes, need to deal with border and padding
  392. //at the break possibility
  393. } else if (!ElementListUtils.endsWithNonInfinitePenalty(contentList)) {
  394. // TODO vh: this is hacky
  395. // The getNextKnuthElements method of TableCellLM must not be called
  396. // twice, otherwise some settings like indents or borders will be
  397. // counted several times and lead to a wrong output. Anyway the
  398. // getNextKnuthElements methods should be called only once eventually
  399. // (i.e., when multi-threading the code), even when there are forced
  400. // breaks.
  401. // If we add a break possibility after a forced break the
  402. // AreaAdditionUtil.addAreas method will act on a sequence starting
  403. // with a SpaceResolver.SpaceHandlingBreakPosition element, having no
  404. // LM associated to it. Thus it will stop early instead of adding
  405. // areas for following Positions. The above test aims at preventing
  406. // such a situation from occurring. add a null penalty to allow a break
  407. // between blocks
  408. // add a null penalty to allow a break between blocks
  409. contentList.add(new BreakElement(
  410. new Position(this), 0, context));
  411. }
  412. }
  413. /**
  414. * {@inheritDoc}
  415. */
  416. public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
  417. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> " + adj);
  418. /*LF*/ //log.debug(" lastElement e' " + (lastElement.isPenalty()
  419. // ? "penalty" : (lastElement.isGlue() ? "glue" : "box" )));
  420. /*LF*/ //log.debug(" position e' " + lastElement.getPosition().getClass().getName());
  421. /*LF*/ //log.debug(" " + (bpUnit > 0 ? "unit" : ""));
  422. Position innerPosition = ((NonLeafPosition) lastElement.getPosition()).getPosition();
  423. if (innerPosition == null && lastElement.isGlue()) {
  424. // this adjustment applies to space-before or space-after of this block
  425. if (((KnuthGlue) lastElement).getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) {
  426. // this adjustment applies to space-before
  427. adjustedSpaceBefore += adj;
  428. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> spazio prima: " + adj);
  429. } else {
  430. // this adjustment applies to space-after
  431. adjustedSpaceAfter += adj;
  432. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> spazio dopo: " + adj);
  433. }
  434. return adj;
  435. } else if (innerPosition instanceof MappingPosition) {
  436. // this block has block-progression-unit > 0: the adjustment can concern
  437. // - the space-before or space-after of this block,
  438. // - the line number of a descendant of this block
  439. MappingPosition mappingPos = (MappingPosition)innerPosition;
  440. if (lastElement.isGlue()) {
  441. // lastElement is a glue
  442. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> bpunit con glue");
  443. ListIterator storedListIterator = storedList.listIterator(
  444. mappingPos.getFirstIndex());
  445. int newAdjustment = 0;
  446. while (storedListIterator.nextIndex() <= mappingPos.getLastIndex()) {
  447. KnuthElement storedElement = (KnuthElement)storedListIterator.next();
  448. if (storedElement.isGlue()) {
  449. newAdjustment += ((BlockLevelLayoutManager)storedElement
  450. .getLayoutManager()).negotiateBPDAdjustment(
  451. adj - newAdjustment, storedElement);
  452. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> (progressivo) righe: "
  453. // + newAdjustment);
  454. }
  455. }
  456. newAdjustment = (newAdjustment > 0 ? bpUnit * neededUnits(newAdjustment)
  457. : -bpUnit * neededUnits(-newAdjustment));
  458. return newAdjustment;
  459. } else {
  460. // lastElement is a penalty: this means that the paragraph
  461. // has been split between consecutive pages:
  462. // this may involve a change in the number of lines
  463. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> bpunit con penalty");
  464. KnuthPenalty storedPenalty = (KnuthPenalty)
  465. storedList.get(mappingPos.getLastIndex());
  466. if (storedPenalty.getW() > 0) {
  467. // the original penalty has width > 0
  468. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> chiamata passata");
  469. return ((BlockLevelLayoutManager)storedPenalty.getLayoutManager())
  470. .negotiateBPDAdjustment(storedPenalty.getW(),
  471. (KnuthElement)storedPenalty);
  472. } else {
  473. // the original penalty has width = 0
  474. // the adjustment involves only the spaces before and after
  475. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> chiamata gestita");
  476. return adj;
  477. }
  478. }
  479. } else if (innerPosition.getLM() != this) {
  480. // this adjustment concerns another LM
  481. NonLeafPosition savedPos = (NonLeafPosition) lastElement.getPosition();
  482. lastElement.setPosition(innerPosition);
  483. int returnValue = ((BlockLevelLayoutManager)lastElement.getLayoutManager())
  484. .negotiateBPDAdjustment(adj, lastElement);
  485. lastElement.setPosition(savedPos);
  486. /*LF*/ //log.debug(" BLM.negotiateBPDAdjustment> righe: " + returnValue);
  487. return returnValue;
  488. } else {
  489. // this should never happen
  490. log.error("BlockLayoutManager.negotiateBPDAdjustment(): unexpected Position");
  491. return 0;
  492. }
  493. }
  494. /**
  495. * {@inheritDoc}
  496. */
  497. public void discardSpace(KnuthGlue spaceGlue) {
  498. //log.debug(" BLM.discardSpace> " + spaceGlue.getPosition().getClass().getName());
  499. Position innerPosition = ((NonLeafPosition) spaceGlue.getPosition()).getPosition();
  500. if (innerPosition == null || innerPosition.getLM() == this) {
  501. // if this block has block-progression-unit > 0, innerPosition can be
  502. // a MappingPosition
  503. // spaceGlue represents space before or space after of this block
  504. if (spaceGlue.getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) {
  505. // space-before must be discarded
  506. adjustedSpaceBefore = 0;
  507. foSpaceBefore = new MinOptMax(0);
  508. } else {
  509. // space-after must be discarded
  510. adjustedSpaceAfter = 0;
  511. foSpaceAfter = new MinOptMax(0);
  512. //TODO Why are both cases handled in the same way?
  513. }
  514. } else {
  515. // this element was not created by this BlockLM
  516. NonLeafPosition savedPos = (NonLeafPosition)spaceGlue.getPosition();
  517. spaceGlue.setPosition(innerPosition);
  518. ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
  519. spaceGlue.setPosition(savedPos);
  520. }
  521. }
  522. /**
  523. * {@inheritDoc}
  524. */
  525. public List getChangedKnuthElements(List oldList, int alignment) {
  526. /*LF*/ //log.debug("");
  527. /*LF*/ //log.debug(" BLM.getChangedKnuthElements> inizio: oldList.size() = "
  528. // + oldList.size());
  529. ListIterator oldListIterator = oldList.listIterator();
  530. KnuthElement returnedElement;
  531. KnuthElement currElement = null;
  532. KnuthElement prevElement = null;
  533. List returnedList = new LinkedList();
  534. List returnList = new LinkedList();
  535. int fromIndex = 0;
  536. // "unwrap" the Positions stored in the elements
  537. KnuthElement oldElement = null;
  538. while (oldListIterator.hasNext()) {
  539. oldElement = (KnuthElement)oldListIterator.next();
  540. Position innerPosition = ((NonLeafPosition) oldElement.getPosition()).getPosition();
  541. //log.debug(" BLM> unwrapping: "
  542. // + (oldElement.isBox() ? "box " : (oldElement.isGlue() ? "glue " : "penalty"))
  543. // + " creato da " + oldElement.getLayoutManager().getClass().getName());
  544. //log.debug(" BLM> unwrapping: "
  545. // + oldElement.getPosition().getClass().getName());
  546. if (innerPosition != null) {
  547. // oldElement was created by a descendant of this BlockLM
  548. oldElement.setPosition(innerPosition);
  549. } else {
  550. // thisElement was created by this BlockLM
  551. // modify its position in order to recognize it was not created
  552. // by a child
  553. oldElement.setPosition(new Position(this));
  554. }
  555. }
  556. // create the iterator
  557. List workList;
  558. if (bpUnit == 0) {
  559. workList = oldList;
  560. } else {
  561. // the storedList must be used instead of oldList;
  562. // find the index of the first element of returnedList
  563. // corresponding to the first element of oldList
  564. oldListIterator = oldList.listIterator();
  565. KnuthElement el = (KnuthElement) oldListIterator.next();
  566. while (!(el.getPosition() instanceof MappingPosition)) {
  567. el = (KnuthElement) oldListIterator.next();
  568. }
  569. int iFirst = ((MappingPosition) el.getPosition()).getFirstIndex();
  570. // find the index of the last element of returnedList
  571. // corresponding to the last element of oldList
  572. oldListIterator = oldList.listIterator(oldList.size());
  573. el = (KnuthElement) oldListIterator.previous();
  574. while (!(el.getPosition() instanceof MappingPosition)) {
  575. el = (KnuthElement) oldListIterator.previous();
  576. }
  577. int iLast = ((MappingPosition) el.getPosition()).getLastIndex();
  578. //log-debug(" si usa storedList da " + iFirst + " a " + iLast
  579. // + " compresi su " + storedList.size() + " elementi totali");
  580. workList = storedList.subList(iFirst, iLast + 1);
  581. }
  582. ListIterator workListIterator = workList.listIterator();
  583. //log.debug(" BLM.getChangedKnuthElements> workList.size() = "
  584. // + workList.size() + " da 0 a " + (workList.size() - 1));
  585. while (workListIterator.hasNext()) {
  586. currElement = (KnuthElement) workListIterator.next();
  587. //log.debug("elemento n. " + workListIterator.previousIndex()
  588. // + " nella workList");
  589. if (prevElement != null
  590. && prevElement.getLayoutManager() != currElement.getLayoutManager()) {
  591. // prevElement is the last element generated by the same LM
  592. BlockLevelLayoutManager prevLM = (BlockLevelLayoutManager)
  593. prevElement.getLayoutManager();
  594. BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
  595. currElement.getLayoutManager();
  596. boolean bSomethingAdded = false;
  597. if (prevLM != this) {
  598. //log.debug(" BLM.getChangedKnuthElements> chiamata da "
  599. // + fromIndex + " a " + workListIterator.previousIndex() + " su "
  600. // + prevLM.getClass().getName());
  601. returnedList.addAll(prevLM.getChangedKnuthElements(workList.subList(
  602. fromIndex, workListIterator.previousIndex()), alignment));
  603. bSomethingAdded = true;
  604. } else {
  605. // prevLM == this
  606. // do nothing
  607. //log.debug(" BLM.getChangedKnuthElements> elementi propri, "
  608. // + "ignorati, da " + fromIndex + " a " + workListIterator.previousIndex()
  609. // + " su " + prevLM.getClass().getName());
  610. }
  611. fromIndex = workListIterator.previousIndex();
  612. /*
  613. * TODO: why are KnuthPenalties added here,
  614. * while in getNextKE they were changed to BreakElements?
  615. */
  616. // there is another block after this one
  617. if (bSomethingAdded
  618. && (this.mustKeepTogether()
  619. || prevLM.mustKeepWithNext()
  620. || currLM.mustKeepWithPrevious())) {
  621. // add an infinite penalty to forbid a break between blocks
  622. returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  623. new Position(this), false));
  624. } else if (bSomethingAdded
  625. && !((KnuthElement) ListUtil.getLast(returnedList))
  626. .isGlue()) {
  627. // add a null penalty to allow a break between blocks
  628. returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
  629. }
  630. }
  631. prevElement = currElement;
  632. }
  633. if (currElement != null) {
  634. BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
  635. currElement.getLayoutManager();
  636. if (currLM != this) {
  637. //log.debug(" BLM.getChangedKnuthElements> chiamata da " + fromIndex
  638. // + " a " + oldList.size() + " su " + currLM.getClass().getName());
  639. returnedList.addAll(currLM.getChangedKnuthElements(
  640. workList.subList(fromIndex, workList.size()), alignment));
  641. } else {
  642. // currLM == this
  643. // there are no more elements to add
  644. // remove the last penalty added to returnedList
  645. if (!returnedList.isEmpty()) {
  646. ListUtil.removeLast(returnedList);
  647. }
  648. //log.debug(" BLM.getChangedKnuthElements> elementi propri, ignorati, da "
  649. // + fromIndex + " a " + workList.size());
  650. }
  651. }
  652. // append elements representing space-before
  653. boolean spaceBeforeIsConditional = true;
  654. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  655. spaceBeforeIsConditional = ((org.apache.fop.fo.flow.Block)fobj)
  656. .getCommonMarginBlock().spaceBefore.getSpace().isDiscard();
  657. }
  658. if (bpUnit > 0
  659. || adjustedSpaceBefore != 0) {
  660. if (!spaceBeforeIsConditional) {
  661. // add elements to prevent the glue to be discarded
  662. returnList.add(new KnuthBox(0,
  663. new NonLeafPosition(this, null), false));
  664. returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  665. new NonLeafPosition(this, null), false));
  666. }
  667. if (bpUnit > 0) {
  668. returnList.add(new KnuthGlue(0, 0, 0,
  669. SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
  670. } else {
  671. returnList.add(new KnuthGlue(adjustedSpaceBefore, 0, 0,
  672. SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
  673. }
  674. }
  675. //log.debug(" BLM.getChangedKnuthElements> intermedio: returnedList.size() = "
  676. // + returnedList.size());
  677. /* estensione: conversione complessiva */
  678. /*LF*/ if (bpUnit > 0) {
  679. /*LF*/ storedList = returnedList;
  680. /*LF*/ returnedList = createUnitElements(returnedList);
  681. /*LF*/ }
  682. /* estensione */
  683. // "wrap" the Position stored in each element of returnedList
  684. // and add elements to returnList
  685. ListIterator listIter = returnedList.listIterator();
  686. while (listIter.hasNext()) {
  687. returnedElement = (KnuthElement)listIter.next();
  688. returnedElement.setPosition(new NonLeafPosition(this, returnedElement.getPosition()));
  689. returnList.add(returnedElement);
  690. }
  691. // append elements representing space-after
  692. boolean spaceAfterIsConditional = true;
  693. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  694. spaceAfterIsConditional = ((org.apache.fop.fo.flow.Block)fobj)
  695. .getCommonMarginBlock().spaceAfter.getSpace().isDiscard();
  696. }
  697. if (bpUnit > 0 || adjustedSpaceAfter != 0) {
  698. if (!spaceAfterIsConditional) {
  699. returnList.add(new KnuthPenalty(0,
  700. KnuthElement.INFINITE, false,
  701. new NonLeafPosition(this, null), false));
  702. }
  703. if (bpUnit > 0) {
  704. returnList.add(new KnuthGlue(0, 0, 0,
  705. SPACE_AFTER_ADJUSTMENT,
  706. new NonLeafPosition(this, null),
  707. (!spaceAfterIsConditional) ? false : true));
  708. } else {
  709. returnList.add(new KnuthGlue(adjustedSpaceAfter, 0, 0,
  710. SPACE_AFTER_ADJUSTMENT,
  711. new NonLeafPosition(this, null),
  712. (!spaceAfterIsConditional) ? false : true));
  713. }
  714. if (!spaceAfterIsConditional) {
  715. returnList.add(new KnuthBox(0,
  716. new NonLeafPosition(this, null), true));
  717. }
  718. }
  719. //log.debug(" BLM.getChangedKnuthElements> finished: returnList.size() = "
  720. // + returnList.size());
  721. return returnList;
  722. }
  723. /**
  724. * Retrieves and returns the keep-together strength from the parent element.
  725. * @return the keep-together strength
  726. */
  727. protected int getParentKeepTogetherStrength() {
  728. int strength = KEEP_AUTO;
  729. if (getParent() instanceof BlockLevelLayoutManager) {
  730. strength = ((BlockLevelLayoutManager)getParent()).getKeepTogetherStrength();
  731. } else if (getParent() instanceof InlineLayoutManager) {
  732. if (((InlineLayoutManager) getParent()).mustKeepTogether()) {
  733. strength = KEEP_ALWAYS;
  734. }
  735. //TODO Fix me
  736. //strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength();
  737. }
  738. return strength;
  739. }
  740. /** {@inheritDoc} */
  741. public boolean mustKeepTogether() {
  742. return getKeepTogetherStrength() > KEEP_AUTO;
  743. }
  744. /** {@inheritDoc} */
  745. public boolean mustKeepWithPrevious() {
  746. return getKeepWithPreviousStrength() > KEEP_AUTO;
  747. }
  748. /** {@inheritDoc} */
  749. public boolean mustKeepWithNext() {
  750. return getKeepWithNextStrength() > KEEP_AUTO;
  751. }
  752. /**
  753. * Adds the unresolved elements for border and padding to a layout context so break
  754. * possibilities can be properly constructed.
  755. * @param context the layout context
  756. */
  757. protected void addPendingMarks(LayoutContext context) {
  758. CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground();
  759. if (borderAndPadding != null) {
  760. if (borderAndPadding.getBorderBeforeWidth(false) > 0) {
  761. context.addPendingBeforeMark(new BorderElement(
  762. getAuxiliaryPosition(),
  763. borderAndPadding.getBorderInfo(
  764. CommonBorderPaddingBackground.BEFORE).getWidth(),
  765. RelSide.BEFORE,
  766. false, false, this));
  767. }
  768. if (borderAndPadding.getPaddingBefore(false, this) > 0) {
  769. context.addPendingBeforeMark(new PaddingElement(
  770. getAuxiliaryPosition(),
  771. borderAndPadding.getPaddingLengthProperty(
  772. CommonBorderPaddingBackground.BEFORE),
  773. RelSide.BEFORE,
  774. false, false, this));
  775. }
  776. if (borderAndPadding.getBorderAfterWidth(false) > 0) {
  777. context.addPendingAfterMark(new BorderElement(
  778. getAuxiliaryPosition(),
  779. borderAndPadding.getBorderInfo(
  780. CommonBorderPaddingBackground.AFTER).getWidth(),
  781. RelSide.AFTER,
  782. false, false, this));
  783. }
  784. if (borderAndPadding.getPaddingAfter(false, this) > 0) {
  785. context.addPendingAfterMark(new PaddingElement(
  786. getAuxiliaryPosition(),
  787. borderAndPadding.getPaddingLengthProperty(
  788. CommonBorderPaddingBackground.AFTER),
  789. RelSide.AFTER,
  790. false, false, this));
  791. }
  792. }
  793. }
  794. /** @return the border, padding and background info structure */
  795. private CommonBorderPaddingBackground getBorderPaddingBackground() {
  796. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  797. return ((org.apache.fop.fo.flow.Block)fobj)
  798. .getCommonBorderPaddingBackground();
  799. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  800. return ((org.apache.fop.fo.flow.BlockContainer)fobj)
  801. .getCommonBorderPaddingBackground();
  802. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  803. return ((org.apache.fop.fo.flow.ListBlock)fobj)
  804. .getCommonBorderPaddingBackground();
  805. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  806. return ((org.apache.fop.fo.flow.ListItem)fobj)
  807. .getCommonBorderPaddingBackground();
  808. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  809. return ((org.apache.fop.fo.flow.table.Table)fobj)
  810. .getCommonBorderPaddingBackground();
  811. } else {
  812. return null;
  813. }
  814. }
  815. /** @return the space-before property */
  816. private SpaceProperty getSpaceBeforeProperty() {
  817. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  818. return ((org.apache.fop.fo.flow.Block)fobj)
  819. .getCommonMarginBlock().spaceBefore;
  820. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  821. return ((org.apache.fop.fo.flow.BlockContainer)fobj)
  822. .getCommonMarginBlock().spaceBefore;
  823. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  824. return ((org.apache.fop.fo.flow.ListBlock)fobj)
  825. .getCommonMarginBlock().spaceBefore;
  826. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  827. return ((org.apache.fop.fo.flow.ListItem)fobj)
  828. .getCommonMarginBlock().spaceBefore;
  829. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  830. return ((org.apache.fop.fo.flow.table.Table)fobj)
  831. .getCommonMarginBlock().spaceBefore;
  832. } else {
  833. return null;
  834. }
  835. }
  836. /** @return the space-after property */
  837. private SpaceProperty getSpaceAfterProperty() {
  838. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  839. return ((org.apache.fop.fo.flow.Block)fobj)
  840. .getCommonMarginBlock().spaceAfter;
  841. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  842. return ((org.apache.fop.fo.flow.BlockContainer)fobj)
  843. .getCommonMarginBlock().spaceAfter;
  844. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  845. return ((org.apache.fop.fo.flow.ListBlock)fobj)
  846. .getCommonMarginBlock().spaceAfter;
  847. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  848. return ((org.apache.fop.fo.flow.ListItem)fobj)
  849. .getCommonMarginBlock().spaceAfter;
  850. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  851. return ((org.apache.fop.fo.flow.table.Table)fobj)
  852. .getCommonMarginBlock().spaceAfter;
  853. } else {
  854. return null;
  855. }
  856. }
  857. /**
  858. * Creates Knuth elements for before border padding and adds them to the return list.
  859. * @param returnList return list to add the additional elements to
  860. * @param isFirst true if this is the first time a layout manager instance needs to generate
  861. * border and padding
  862. */
  863. protected void addKnuthElementsForBorderPaddingBefore(List returnList, boolean isFirst) {
  864. //Border and Padding (before)
  865. CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground();
  866. if (borderAndPadding != null) {
  867. if (borderAndPadding.getBorderBeforeWidth(false) > 0) {
  868. returnList.add(new BorderElement(
  869. getAuxiliaryPosition(),
  870. borderAndPadding.getBorderInfo(CommonBorderPaddingBackground.BEFORE)
  871. .getWidth(),
  872. RelSide.BEFORE, isFirst, false, this));
  873. }
  874. if (borderAndPadding.getPaddingBefore(false, this) > 0) {
  875. returnList.add(new PaddingElement(
  876. getAuxiliaryPosition(),
  877. borderAndPadding.getPaddingLengthProperty(
  878. CommonBorderPaddingBackground.BEFORE),
  879. RelSide.BEFORE, isFirst, false, this));
  880. }
  881. }
  882. }
  883. /**
  884. * Creates Knuth elements for after border padding and adds them to the return list.
  885. * @param returnList return list to add the additional elements to
  886. * @param isLast true if this is the last time a layout manager instance needs to generate
  887. * border and padding
  888. */
  889. protected void addKnuthElementsForBorderPaddingAfter(List returnList, boolean isLast) {
  890. //Border and Padding (after)
  891. CommonBorderPaddingBackground borderAndPadding = getBorderPaddingBackground();
  892. if (borderAndPadding != null) {
  893. if (borderAndPadding.getPaddingAfter(false, this) > 0) {
  894. returnList.add(new PaddingElement(
  895. getAuxiliaryPosition(),
  896. borderAndPadding.getPaddingLengthProperty(
  897. CommonBorderPaddingBackground.AFTER),
  898. RelSide.AFTER, false, isLast, this));
  899. }
  900. if (borderAndPadding.getBorderAfterWidth(false) > 0) {
  901. returnList.add(new BorderElement(
  902. getAuxiliaryPosition(),
  903. borderAndPadding.getBorderInfo(CommonBorderPaddingBackground.AFTER)
  904. .getWidth(),
  905. RelSide.AFTER, false, isLast, this));
  906. }
  907. }
  908. }
  909. /**
  910. * Creates Knuth elements for break-before and adds them to the return list.
  911. * @param returnList return list to add the additional elements to
  912. * @param context the layout context
  913. * @return true if an element has been added due to a break-before.
  914. */
  915. protected boolean addKnuthElementsForBreakBefore(List returnList,
  916. LayoutContext context) {
  917. int breakBefore = -1;
  918. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  919. breakBefore = ((org.apache.fop.fo.flow.Block) fobj).getBreakBefore();
  920. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  921. breakBefore = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakBefore();
  922. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  923. breakBefore = ((org.apache.fop.fo.flow.ListBlock) fobj).getBreakBefore();
  924. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  925. breakBefore = ((org.apache.fop.fo.flow.ListItem) fobj).getBreakBefore();
  926. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  927. breakBefore = ((org.apache.fop.fo.flow.table.Table) fobj).getBreakBefore();
  928. }
  929. if (breakBefore == EN_PAGE
  930. || breakBefore == EN_COLUMN
  931. || breakBefore == EN_EVEN_PAGE
  932. || breakBefore == EN_ODD_PAGE) {
  933. // return a penalty element, representing a forced page break
  934. returnList.add(new BreakElement(getAuxiliaryPosition(),
  935. 0, -KnuthElement.INFINITE, breakBefore, context));
  936. return true;
  937. } else {
  938. return false;
  939. }
  940. }
  941. /**
  942. * Creates Knuth elements for break-after 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-after.
  946. */
  947. protected boolean addKnuthElementsForBreakAfter(List returnList,
  948. LayoutContext context) {
  949. int breakAfter = -1;
  950. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  951. breakAfter = ((org.apache.fop.fo.flow.Block) fobj).getBreakAfter();
  952. } else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
  953. breakAfter = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakAfter();
  954. } else if (fobj instanceof org.apache.fop.fo.flow.ListBlock) {
  955. breakAfter = ((org.apache.fop.fo.flow.ListBlock) fobj).getBreakAfter();
  956. } else if (fobj instanceof org.apache.fop.fo.flow.ListItem) {
  957. breakAfter = ((org.apache.fop.fo.flow.ListItem) fobj).getBreakAfter();
  958. } else if (fobj instanceof org.apache.fop.fo.flow.table.Table) {
  959. breakAfter = ((org.apache.fop.fo.flow.table.Table) fobj).getBreakAfter();
  960. }
  961. if (breakAfter == EN_PAGE
  962. || breakAfter == EN_COLUMN
  963. || breakAfter == EN_EVEN_PAGE
  964. || breakAfter == EN_ODD_PAGE) {
  965. // add a penalty element, representing a forced page break
  966. returnList.add(new BreakElement(getAuxiliaryPosition(),
  967. 0, -KnuthElement.INFINITE, breakAfter, context));
  968. return true;
  969. } else {
  970. return false;
  971. }
  972. }
  973. /**
  974. * Creates Knuth elements for space-before and adds them to the return list.
  975. * @param returnList return list to add the additional elements to
  976. * @param alignment vertical alignment
  977. */
  978. protected void addKnuthElementsForSpaceBefore(List returnList/*,
  979. Position returnPosition*/, int alignment) {
  980. SpaceProperty spaceBefore = getSpaceBeforeProperty();
  981. // append elements representing space-before
  982. if (spaceBefore != null
  983. && !(spaceBefore.getMinimum(this).getLength().getValue(this) == 0
  984. && spaceBefore.getMaximum(this).getLength().getValue(this) == 0)) {
  985. returnList.add(new SpaceElement(getAuxiliaryPosition(), spaceBefore,
  986. RelSide.BEFORE,
  987. true, false, this));
  988. }
  989. /*
  990. if (bpUnit > 0
  991. || spaceBefore != null
  992. && !(spaceBefore.getMinimum(this).getLength().getValue(this) == 0
  993. && spaceBefore.getMaximum(this).getLength().getValue(this) == 0)) {
  994. if (spaceBefore != null && !spaceBefore.getSpace().isDiscard()) {
  995. // add elements to prevent the glue to be discarded
  996. returnList.add(new KnuthBox(0, getAuxiliaryPosition(), false));
  997. returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
  998. false, getAuxiliaryPosition(), false));
  999. }
  1000. if (bpUnit > 0) {
  1001. returnList.add(new KnuthGlue(0, 0, 0,
  1002. BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT,
  1003. getAuxiliaryPosition(), true));
  1004. } else { //if (alignment == EN_JUSTIFY) {
  1005. returnList.add(new KnuthGlue(
  1006. spaceBefore.getOptimum(this).getLength().getValue(this),
  1007. spaceBefore.getMaximum(this).getLength().getValue(this)
  1008. - spaceBefore.getOptimum(this).getLength().getValue(this),
  1009. spaceBefore.getOptimum(this).getLength().getValue(this)
  1010. - spaceBefore.getMinimum(this).getLength().getValue(this),
  1011. BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT,
  1012. getAuxiliaryPosition(), true));
  1013. // } else {
  1014. // returnList.add(new KnuthGlue(
  1015. // spaceBefore.getOptimum().getLength().getValue(this),
  1016. // 0, 0, BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT,
  1017. // returnPosition, true));
  1018. }
  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/*, Position returnPosition*/,
  1027. int alignment) {
  1028. SpaceProperty spaceAfter = getSpaceAfterProperty();
  1029. // append elements representing space-after
  1030. if (spaceAfter != null
  1031. && !(spaceAfter.getMinimum(this).getLength().getValue(this) == 0
  1032. && spaceAfter.getMaximum(this).getLength().getValue(this) == 0)) {
  1033. returnList.add(new SpaceElement(getAuxiliaryPosition(), spaceAfter,
  1034. RelSide.AFTER,
  1035. false, true, this));
  1036. }
  1037. /*
  1038. if (bpUnit > 0
  1039. || spaceAfter != null
  1040. && !(spaceAfter.getMinimum(this).getLength().getValue(this) == 0
  1041. && spaceAfter.getMaximum(this).getLength().getValue(this) == 0)) {
  1042. if (spaceAfter != null && !spaceAfter.getSpace().isDiscard()) {
  1043. returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
  1044. false, getAuxiliaryPosition(), false));
  1045. }
  1046. if (bpUnit > 0) {
  1047. returnList.add(new KnuthGlue(0, 0, 0,
  1048. BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT,
  1049. getAuxiliaryPosition(), true));
  1050. } else { //if (alignment == EN_JUSTIFY) {
  1051. returnList.add(new KnuthGlue(
  1052. spaceAfter.getOptimum(this).getLength().getValue(this),
  1053. spaceAfter.getMaximum(this).getLength().getValue(this)
  1054. - spaceAfter.getOptimum(this).getLength().getValue(this),
  1055. spaceAfter.getOptimum(this).getLength().getValue(this)
  1056. - spaceAfter.getMinimum(this).getLength().getValue(this),
  1057. BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, getAuxiliaryPosition(),
  1058. (!spaceAfter.getSpace().isDiscard()) ? false : true));
  1059. // } else {
  1060. // returnList.add(new KnuthGlue(
  1061. // spaceAfter.getOptimum().getLength().getValue(this), 0, 0,
  1062. // BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT, returnPosition,
  1063. // (!spaceAfter.getSpace().isDiscard()) ? false : true));
  1064. }
  1065. if (spaceAfter != null && !spaceAfter.getSpace().isDiscard()) {
  1066. returnList.add(new KnuthBox(0, getAuxiliaryPosition(), true));
  1067. }
  1068. }*/
  1069. }
  1070. protected List createUnitElements(List oldList) {
  1071. //log.debug("Start conversion: " + oldList.size()
  1072. // + " elements, space-before.min=" + layoutProps.spaceBefore.getSpace().min
  1073. // + " space-after.min=" + layoutProps.spaceAfter.getSpace().min);
  1074. // add elements at the beginning and at the end of oldList
  1075. // representing minimum spaces
  1076. LayoutManager lm = ((KnuthElement)oldList.get(0)).getLayoutManager();
  1077. boolean bAddedBoxBefore = false;
  1078. boolean bAddedBoxAfter = false;
  1079. if (adjustedSpaceBefore > 0) {
  1080. oldList.add(0, new KnuthBox(adjustedSpaceBefore,
  1081. new Position(lm), true));
  1082. bAddedBoxBefore = true;
  1083. }
  1084. if (adjustedSpaceAfter > 0) {
  1085. oldList.add(new KnuthBox(adjustedSpaceAfter,
  1086. new Position(lm), true));
  1087. bAddedBoxAfter = true;
  1088. }
  1089. MinOptMax totalLength = new MinOptMax(0);
  1090. MinOptMax totalUnits = new MinOptMax(0);
  1091. LinkedList newList = new LinkedList();
  1092. //log.debug(" Prima scansione");
  1093. // scan the list once to compute total min, opt and max length
  1094. ListIterator oldListIterator = oldList.listIterator();
  1095. while (oldListIterator.hasNext()) {
  1096. KnuthElement element = (KnuthElement) oldListIterator.next();
  1097. if (element.isBox()) {
  1098. totalLength.add(new MinOptMax(element.getW()));
  1099. //log.debug("box " + element.getW());
  1100. } else if (element.isGlue()) {
  1101. totalLength.min -= ((KnuthGlue) element).getZ();
  1102. totalLength.max += ((KnuthGlue) element).getY();
  1103. //leafValue = ((LeafPosition) element.getPosition()).getLeafPos();
  1104. //log.debug("glue " + element.getW() + " + "
  1105. // + ((KnuthGlue) element).getY() + " - " + ((KnuthGlue) element).getZ());
  1106. } else {
  1107. //log.debug((((KnuthPenalty)element).getP() == KnuthElement.INFINITE
  1108. // ? "PENALTY " : "penalty ") + element.getW());
  1109. }
  1110. }
  1111. // compute the total amount of "units"
  1112. totalUnits = new MinOptMax(neededUnits(totalLength.min),
  1113. neededUnits(totalLength.opt),
  1114. neededUnits(totalLength.max));
  1115. //log.debug(" totalLength= " + totalLength);
  1116. //log.debug(" unita'= " + totalUnits);
  1117. //log.debug(" Seconda scansione");
  1118. // scan the list once more, stopping at every breaking point
  1119. // in order to compute partial min, opt and max length
  1120. // and create the new elements
  1121. oldListIterator = oldList.listIterator();
  1122. boolean bPrevIsBox = false;
  1123. MinOptMax lengthBeforeBreak = new MinOptMax(0);
  1124. MinOptMax lengthAfterBreak = (MinOptMax) totalLength.clone();
  1125. MinOptMax unitsBeforeBreak;
  1126. MinOptMax unitsAfterBreak;
  1127. MinOptMax unsuppressibleUnits = new MinOptMax(0);
  1128. int firstIndex = 0;
  1129. int lastIndex = -1;
  1130. while (oldListIterator.hasNext()) {
  1131. KnuthElement element = (KnuthElement) oldListIterator.next();
  1132. lastIndex++;
  1133. if (element.isBox()) {
  1134. lengthBeforeBreak.add(new MinOptMax(element.getW()));
  1135. lengthAfterBreak.subtract(new MinOptMax(element.getW()));
  1136. bPrevIsBox = true;
  1137. } else if (element.isGlue()) {
  1138. lengthBeforeBreak.min -= ((KnuthGlue) element).getZ();
  1139. lengthAfterBreak.min += ((KnuthGlue) element).getZ();
  1140. lengthBeforeBreak.max += ((KnuthGlue) element).getY();
  1141. lengthAfterBreak.max -= ((KnuthGlue) element).getY();
  1142. bPrevIsBox = false;
  1143. } else {
  1144. lengthBeforeBreak.add(new MinOptMax(element.getW()));
  1145. bPrevIsBox = false;
  1146. }
  1147. // create the new elements
  1148. if (element.isPenalty() && ((KnuthPenalty) element).getP() < KnuthElement.INFINITE
  1149. || element.isGlue() && bPrevIsBox
  1150. || !oldListIterator.hasNext()) {
  1151. // suppress elements after the breaking point
  1152. int iStepsForward = 0;
  1153. while (oldListIterator.hasNext()) {
  1154. KnuthElement el = (KnuthElement) oldListIterator.next();
  1155. iStepsForward++;
  1156. if (el.isGlue()) {
  1157. // suppressed glue
  1158. lengthAfterBreak.min += ((KnuthGlue) el).getZ();
  1159. lengthAfterBreak.max -= ((KnuthGlue) el).getY();
  1160. } else if (el.isPenalty()) {
  1161. // suppressed penalty, do nothing
  1162. } else {
  1163. // box, end of suppressions
  1164. break;
  1165. }
  1166. }
  1167. // compute the partial amount of "units" before and after the break
  1168. unitsBeforeBreak = new MinOptMax(neededUnits(lengthBeforeBreak.min),
  1169. neededUnits(lengthBeforeBreak.opt),
  1170. neededUnits(lengthBeforeBreak.max));
  1171. unitsAfterBreak = new MinOptMax(neededUnits(lengthAfterBreak.min),
  1172. neededUnits(lengthAfterBreak.opt),
  1173. neededUnits(lengthAfterBreak.max));
  1174. // rewind the iterator and lengthAfterBreak
  1175. for (int i = 0; i < iStepsForward; i++) {
  1176. KnuthElement el = (KnuthElement) oldListIterator.previous();
  1177. if (el.isGlue()) {
  1178. lengthAfterBreak.min -= ((KnuthGlue) el).getZ();
  1179. lengthAfterBreak.max += ((KnuthGlue) el).getY();
  1180. }
  1181. }
  1182. // compute changes in length, stretch and shrink
  1183. int uLengthChange = unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt;
  1184. int uStretchChange = (unitsBeforeBreak.max + unitsAfterBreak.max - totalUnits.max)
  1185. - (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt);
  1186. int uShrinkChange = (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt)
  1187. - (unitsBeforeBreak.min + unitsAfterBreak.min - totalUnits.min);
  1188. // compute the number of normal, stretch and shrink unit
  1189. // that must be added to the new sequence
  1190. int uNewNormal = unitsBeforeBreak.opt - unsuppressibleUnits.opt;
  1191. int uNewStretch = (unitsBeforeBreak.max - unitsBeforeBreak.opt)
  1192. - (unsuppressibleUnits.max - unsuppressibleUnits.opt);
  1193. int uNewShrink = (unitsBeforeBreak.opt - unitsBeforeBreak.min)
  1194. - (unsuppressibleUnits.opt - unsuppressibleUnits.min);
  1195. //log.debug("("
  1196. // + unsuppressibleUnits.min + "-" + unsuppressibleUnits.opt + "-"
  1197. // + unsuppressibleUnits.max + ") "
  1198. // + " -> " + unitsBeforeBreak.min + "-" + unitsBeforeBreak.opt + "-"
  1199. // + unitsBeforeBreak.max
  1200. // + " + " + unitsAfterBreak.min + "-" + unitsAfterBreak.opt + "-"
  1201. // + unitsAfterBreak.max
  1202. // + (uLengthChange != 0 ? " [length " + uLengthChange + "] " : "")
  1203. // + (uStretchChange != 0 ? " [stretch " + uStretchChange + "] " : "")
  1204. // + (uShrinkChange != 0 ? " [shrink " + uShrinkChange + "]" : ""));
  1205. // create the MappingPosition which will be stored in the new elements
  1206. // correct firstIndex and lastIndex
  1207. int firstIndexCorrection = 0;
  1208. int lastIndexCorrection = 0;
  1209. if (bAddedBoxBefore) {
  1210. if (firstIndex != 0) {
  1211. firstIndexCorrection++;
  1212. }
  1213. lastIndexCorrection++;
  1214. }
  1215. if (bAddedBoxAfter && lastIndex == (oldList.size() - 1)) {
  1216. lastIndexCorrection++;
  1217. }
  1218. MappingPosition mappingPos = new MappingPosition(this,
  1219. firstIndex - firstIndexCorrection,
  1220. lastIndex - lastIndexCorrection);
  1221. // new box
  1222. newList.add(new KnuthBox((uNewNormal - uLengthChange) * bpUnit,
  1223. mappingPos,
  1224. false));
  1225. unsuppressibleUnits.add(new MinOptMax(uNewNormal - uLengthChange));
  1226. //log.debug(" box " + (uNewNormal - uLengthChange));
  1227. // new infinite penalty, glue and box, if necessary
  1228. if (uNewStretch - uStretchChange > 0
  1229. || uNewShrink - uShrinkChange > 0) {
  1230. int iStretchUnits = (uNewStretch - uStretchChange > 0
  1231. ? (uNewStretch - uStretchChange) : 0);
  1232. int iShrinkUnits = (uNewShrink - uShrinkChange > 0
  1233. ? (uNewShrink - uShrinkChange) : 0);
  1234. newList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  1235. mappingPos,
  1236. false));
  1237. newList.add(new KnuthGlue(0,
  1238. iStretchUnits * bpUnit,
  1239. iShrinkUnits * bpUnit,
  1240. LINE_NUMBER_ADJUSTMENT,
  1241. mappingPos,
  1242. false));
  1243. //log.debug(" PENALTY");
  1244. //log.debug(" glue 0 " + iStretchUnits + " " + iShrinkUnits);
  1245. unsuppressibleUnits.max += iStretchUnits;
  1246. unsuppressibleUnits.min -= iShrinkUnits;
  1247. if (!oldListIterator.hasNext()) {
  1248. newList.add(new KnuthBox(0,
  1249. mappingPos,
  1250. false));
  1251. //log.debug(" box 0");
  1252. }
  1253. }
  1254. // new breaking sequence
  1255. if (uStretchChange != 0
  1256. || uShrinkChange != 0) {
  1257. // new infinite penalty, glue, penalty and glue
  1258. newList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
  1259. mappingPos,
  1260. false));
  1261. newList.add(new KnuthGlue(0,
  1262. uStretchChange * bpUnit,
  1263. uShrinkChange * bpUnit,
  1264. LINE_NUMBER_ADJUSTMENT,
  1265. mappingPos,
  1266. false));
  1267. newList.add(new KnuthPenalty(uLengthChange * bpUnit,
  1268. 0, false, element.getPosition(), false));
  1269. newList.add(new KnuthGlue(0,
  1270. -uStretchChange * bpUnit,
  1271. -uShrinkChange * bpUnit,
  1272. LINE_NUMBER_ADJUSTMENT,
  1273. mappingPos,
  1274. false));
  1275. //log.debug(" PENALTY");
  1276. //log.debug(" glue 0 " + uStretchChange + " " + uShrinkChange);
  1277. //log.debug(" penalty " + uLengthChange + " * unit");
  1278. //log.debug(" glue 0 " + (- uStretchChange) + " "
  1279. // + (- uShrinkChange));
  1280. } else if (oldListIterator.hasNext()) {
  1281. // new penalty
  1282. newList.add(new KnuthPenalty(uLengthChange * bpUnit,
  1283. 0, false,
  1284. mappingPos,
  1285. false));
  1286. //log.debug(" penalty " + uLengthChange + " * unit");
  1287. }
  1288. // update firstIndex
  1289. firstIndex = lastIndex + 1;
  1290. }
  1291. if (element.isPenalty()) {
  1292. lengthBeforeBreak.add(new MinOptMax(-element.getW()));
  1293. }
  1294. }
  1295. // remove elements at the beginning and at the end of oldList
  1296. // representing minimum spaces
  1297. if (adjustedSpaceBefore > 0) {
  1298. oldList.remove(0);
  1299. }
  1300. if (adjustedSpaceAfter > 0) {
  1301. ListUtil.removeLast(oldList);
  1302. }
  1303. // if space-before.conditionality is "discard", correct newList
  1304. boolean correctFirstElement = false;
  1305. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  1306. correctFirstElement = ((org.apache.fop.fo.flow.Block)fobj)
  1307. .getCommonMarginBlock().spaceBefore.getSpace().isDiscard();
  1308. }
  1309. if (correctFirstElement) {
  1310. // remove the wrong element
  1311. KnuthBox wrongBox = (KnuthBox) newList.removeFirst();
  1312. // if this paragraph is at the top of a page, the space before
  1313. // must be ignored; compute the length change
  1314. int decreasedLength = (neededUnits(totalLength.opt)
  1315. - neededUnits(totalLength.opt - adjustedSpaceBefore))
  1316. * bpUnit;
  1317. // insert the correct elements
  1318. newList.addFirst(new KnuthBox(wrongBox.getW() - decreasedLength,
  1319. wrongBox.getPosition(), false));
  1320. newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, SPACE_BEFORE_ADJUSTMENT,
  1321. wrongBox.getPosition(), false));
  1322. //log.debug(" rimosso box " + neededUnits(wrongBox.getW()));
  1323. //log.debug(" aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
  1324. //log.debug(" aggiunto box " + neededUnits(
  1325. // wrongBox.getW() - decreasedLength));
  1326. }
  1327. // if space-after.conditionality is "discard", correct newList
  1328. boolean correctLastElement = false;
  1329. if (fobj instanceof org.apache.fop.fo.flow.Block) {
  1330. correctLastElement = ((org.apache.fop.fo.flow.Block)fobj)
  1331. .getCommonMarginBlock().spaceAfter.getSpace().isDiscard();
  1332. }
  1333. if (correctLastElement) {
  1334. // remove the wrong element
  1335. KnuthBox wrongBox = (KnuthBox) newList.removeLast();
  1336. // if the old sequence is box(h) penalty(inf) glue(x,y,z) box(0)
  1337. // (it cannot be parted and has some stretch or shrink)
  1338. // the wrong box is the first one, not the last one
  1339. LinkedList preserveList = new LinkedList();
  1340. if (wrongBox.getW() == 0) {
  1341. preserveList.add(wrongBox);
  1342. preserveList.addFirst((KnuthGlue) newList.removeLast());
  1343. preserveList.addFirst((KnuthPenalty) newList.removeLast());
  1344. wrongBox = (KnuthBox) newList.removeLast();
  1345. }
  1346. // if this paragraph is at the bottom of a page, the space after
  1347. // must be ignored; compute the length change
  1348. int decreasedLength = (neededUnits(totalLength.opt)
  1349. - neededUnits(totalLength.opt - adjustedSpaceAfter))
  1350. * bpUnit;
  1351. // insert the correct box
  1352. newList.addLast(new KnuthBox(wrongBox.getW() - decreasedLength,
  1353. wrongBox.getPosition(), false));
  1354. // add preserved elements
  1355. if (!preserveList.isEmpty()) {
  1356. newList.addAll(preserveList);
  1357. }
  1358. // insert the correct glue
  1359. newList.addLast(new KnuthGlue(decreasedLength, 0, 0, SPACE_AFTER_ADJUSTMENT,
  1360. wrongBox.getPosition(), false));
  1361. //log.debug(" rimosso box " + neededUnits(wrongBox.getW()));
  1362. //log.debug(" aggiunto box " + neededUnits(
  1363. // wrongBox.getW() - decreasedLength));
  1364. //log.debug(" aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
  1365. }
  1366. return newList;
  1367. }
  1368. protected static class StackingIter extends PositionIterator {
  1369. StackingIter(Iterator parentIter) {
  1370. super(parentIter);
  1371. }
  1372. protected LayoutManager getLM(Object nextObj) {
  1373. return ((Position) nextObj).getLM();
  1374. }
  1375. protected Position getPos(Object nextObj) {
  1376. return ((Position) nextObj);
  1377. }
  1378. }
  1379. protected static class MappingPosition extends Position {
  1380. private int iFirstIndex;
  1381. private int iLastIndex;
  1382. public MappingPosition(LayoutManager lm, int first, int last) {
  1383. super(lm);
  1384. iFirstIndex = first;
  1385. iLastIndex = last;
  1386. }
  1387. public int getFirstIndex() {
  1388. return iFirstIndex;
  1389. }
  1390. public int getLastIndex() {
  1391. return iLastIndex;
  1392. }
  1393. }
  1394. /**
  1395. * "wrap" the Position inside each element moving the elements from
  1396. * SourceList to targetList
  1397. * @param sourceList source list
  1398. * @param targetList target list receiving the wrapped position elements
  1399. */
  1400. protected void wrapPositionElements(List sourceList, List targetList) {
  1401. wrapPositionElements(sourceList, targetList, false);
  1402. }
  1403. /**
  1404. * "wrap" the Position inside each element moving the elements from
  1405. * SourceList to targetList
  1406. * @param sourceList source list
  1407. * @param targetList target list receiving the wrapped position elements
  1408. * @param force if true, every Position is wrapped regardless of its LM of origin
  1409. */
  1410. protected void wrapPositionElements(List sourceList, List targetList, boolean force) {
  1411. ListIterator listIter = sourceList.listIterator();
  1412. Object tempElement;
  1413. while (listIter.hasNext()) {
  1414. tempElement = listIter.next();
  1415. if (tempElement instanceof ListElement) {
  1416. wrapPositionElement(
  1417. (ListElement) tempElement,
  1418. targetList,
  1419. force);
  1420. } else if (tempElement instanceof List) {
  1421. wrapPositionElements(
  1422. (List) tempElement,
  1423. targetList,
  1424. force);
  1425. }
  1426. }
  1427. }
  1428. /**
  1429. * "wrap" the Position inside the given element and add it to the target list.
  1430. * @param el the list element
  1431. * @param targetList target list receiving the wrapped position elements
  1432. * @param force if true, every Position is wrapped regardless of its LM of origin
  1433. */
  1434. protected void wrapPositionElement(ListElement el, List targetList, boolean force) {
  1435. if (force || el.getLayoutManager() != this) {
  1436. el.setPosition(notifyPos(new NonLeafPosition(this,
  1437. el.getPosition())));
  1438. }
  1439. targetList.add(el);
  1440. }
  1441. /** @return the sum of start-indent and end-indent */
  1442. protected int getIPIndents() {
  1443. return startIndent + endIndent;
  1444. }
  1445. /**
  1446. * Returns the IPD of the content area
  1447. * @return the IPD of the content area
  1448. */
  1449. public int getContentAreaIPD() {
  1450. return contentAreaIPD;
  1451. }
  1452. /**
  1453. * Sets the IPD of the content area
  1454. * @param contentAreaIPD the IPD of the content area
  1455. */
  1456. protected void setContentAreaIPD(int contentAreaIPD) {
  1457. this.contentAreaIPD = contentAreaIPD;
  1458. }
  1459. /**
  1460. * Returns the BPD of the content area
  1461. * @return the BPD of the content area
  1462. */
  1463. public int getContentAreaBPD() {
  1464. return -1;
  1465. }
  1466. }