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 72KB

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