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.

InlineStackingLayoutManager.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /*
  2. * $Id: InlineStackingLayoutManager.java,v 1.13 2003/03/05 20:38:26 jeremias Exp $
  3. * ============================================================================
  4. * The Apache Software License, Version 1.1
  5. * ============================================================================
  6. *
  7. * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modifica-
  10. * tion, are permitted provided that the following conditions are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if any, must
  20. * include the following acknowledgment: "This product includes software
  21. * developed by the Apache Software Foundation (http://www.apache.org/)."
  22. * Alternately, this acknowledgment may appear in the software itself, if
  23. * and wherever such third-party acknowledgments normally appear.
  24. *
  25. * 4. The names "FOP" and "Apache Software Foundation" must not be used to
  26. * endorse or promote products derived from this software without prior
  27. * written permission. For written permission, please contact
  28. * apache@apache.org.
  29. *
  30. * 5. Products derived from this software may not be called "Apache", nor may
  31. * "Apache" appear in their name, without prior written permission of the
  32. * Apache Software Foundation.
  33. *
  34. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  35. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  36. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  37. * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  38. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
  39. * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  40. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  41. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  43. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. * ============================================================================
  45. *
  46. * This software consists of voluntary contributions made by many individuals
  47. * on behalf of the Apache Software Foundation and was originally created by
  48. * James Tauber <jtauber@jtauber.com>. For more information on the Apache
  49. * Software Foundation, please see <http://www.apache.org/>.
  50. */
  51. package org.apache.fop.layoutmgr;
  52. import java.util.Iterator;
  53. import java.util.ListIterator;
  54. import java.util.HashMap;
  55. import org.apache.fop.fo.FObj;
  56. import org.apache.fop.fo.PropertyManager;
  57. import org.apache.fop.fo.properties.CommonBorderAndPadding;
  58. import org.apache.fop.fo.properties.CommonBackground;
  59. import org.apache.fop.traits.InlineProps;
  60. import org.apache.fop.area.Area;
  61. import org.apache.fop.area.inline.InlineArea;
  62. import org.apache.fop.area.inline.InlineParent;
  63. import org.apache.fop.area.inline.Space;
  64. import org.apache.fop.traits.MinOptMax;
  65. /**
  66. * LayoutManager for objects which stack children in the inline direction,
  67. * such as Inline or Line
  68. */
  69. public class InlineStackingLayoutManager extends AbstractLayoutManager {
  70. private static class StackingIter extends PositionIterator {
  71. StackingIter(Iterator parentIter) {
  72. super(parentIter);
  73. }
  74. protected LayoutProcessor getLM(Object nextObj) {
  75. return ((Position) nextObj).getPosition().getLM();
  76. }
  77. protected Position getPos(Object nextObj) {
  78. return ((Position) nextObj).getPosition();
  79. }
  80. }
  81. /**
  82. * Size of any start or end borders and padding.
  83. */
  84. private MinOptMax allocIPD = new MinOptMax(0);
  85. /**
  86. * Size of border and padding in BPD (ie, before and after).
  87. */
  88. private MinOptMax extraBPD;
  89. private InlineProps inlineProps = null;
  90. private CommonBorderAndPadding borderProps = null;
  91. private CommonBackground backgroundProps;
  92. private Area currentArea; // LineArea or InlineParent
  93. private BreakPoss prevBP;
  94. private LayoutContext childLC ;
  95. private LayoutManager lastChildLM = null; // Set when return last breakposs
  96. private boolean bAreaCreated = false;
  97. /** Used to store previous content IPD for each child LM. */
  98. private HashMap hmPrevIPD = new HashMap();
  99. /**
  100. * Create an inline stacking layout manager.
  101. * This is used for fo's that create areas that
  102. * contain inline areas.
  103. *
  104. * @param fobj the formatting object that creates the area
  105. * @param childLMiter the iterator for child areas
  106. */
  107. public InlineStackingLayoutManager() {
  108. }
  109. /**
  110. * Set the FO object for this layout manager
  111. *
  112. * @param fo the fo for this layout manager
  113. */
  114. public void setFObj(FObj fo) {
  115. this.fobj = fo;
  116. foID = fobj.getID();
  117. childLMiter = null;
  118. }
  119. /**
  120. * Set the iterator.
  121. *
  122. * @param iter the iterator for this LM
  123. */
  124. public void setLMiter(ListIterator iter) {
  125. childLMiter = iter;
  126. }
  127. /**
  128. * Check if this generates inline areas.
  129. * This creates inline areas that contain other inline areas.
  130. *
  131. * @return true
  132. */
  133. public boolean generatesInlineAreas() {
  134. return true;
  135. }
  136. /**
  137. * Initialize properties for this layout manager.
  138. *
  139. * @param propMgr the property manager from the fo that created this manager
  140. */
  141. protected void initProperties(PropertyManager propMgr) {
  142. // super.initProperties(propMgr);
  143. inlineProps = propMgr.getInlineProps();
  144. borderProps = propMgr.getBorderAndPadding();
  145. // Calculdate border and padding size in BPD
  146. int iPad = borderProps.getPadding(CommonBorderAndPadding.BEFORE, false);
  147. iPad += borderProps.getBorderWidth(CommonBorderAndPadding.BEFORE,
  148. false);
  149. iPad += borderProps.getPadding(CommonBorderAndPadding.AFTER, false);
  150. iPad += borderProps.getBorderWidth(CommonBorderAndPadding.AFTER, false);
  151. extraBPD = new MinOptMax(iPad);
  152. backgroundProps = propMgr.getBackgroundProps();
  153. }
  154. private MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
  155. int iBP = borderProps.getPadding(CommonBorderAndPadding.START,
  156. bNotFirst);
  157. iBP += borderProps.getBorderWidth(CommonBorderAndPadding.START,
  158. bNotFirst);
  159. iBP += borderProps.getPadding(CommonBorderAndPadding.END, bNotLast);
  160. iBP += borderProps.getBorderWidth(CommonBorderAndPadding.END, bNotLast);
  161. return new MinOptMax(iBP);
  162. }
  163. protected boolean hasLeadingFence(boolean bNotFirst) {
  164. int iBP = borderProps.getPadding(CommonBorderAndPadding.START,
  165. bNotFirst);
  166. iBP += borderProps.getBorderWidth(CommonBorderAndPadding.START,
  167. bNotFirst);
  168. return (iBP > 0);
  169. }
  170. protected boolean hasTrailingFence(boolean bNotLast) {
  171. int iBP = borderProps.getPadding(CommonBorderAndPadding.END, bNotLast);
  172. iBP += borderProps.getBorderWidth(CommonBorderAndPadding.END, bNotLast);
  173. return (iBP > 0);
  174. }
  175. /**
  176. * Reset position for returning next BreakPossibility.
  177. * @param prevPos a Position returned by this layout manager
  178. * representing a potential break decision.
  179. */
  180. public void resetPosition(Position prevPos) {
  181. if (prevPos != null) {
  182. // ASSERT (prevPos.getLM() == this)
  183. if (prevPos.getLM() != this) {
  184. //getLogger().error(
  185. // "InlineStackingLayoutManager.resetPosition: " +
  186. // "LM mismatch!!!");
  187. }
  188. // Back up the child LM Position
  189. Position childPos = prevPos.getPosition();
  190. reset(childPos);
  191. if (prevBP != null
  192. && prevBP.getLayoutManager() != childPos.getLM()) {
  193. childLC = null;
  194. }
  195. prevBP = new BreakPoss(childPos);
  196. } else {
  197. // Backup to start of first child layout manager
  198. prevBP = null;
  199. // super.resetPosition(prevPos);
  200. reset(prevPos);
  201. // If any areas created, we are restarting!
  202. bAreaCreated = false;
  203. }
  204. // Do we need to reset some context like pending or prevContent?
  205. // What about prevBP?
  206. }
  207. /**
  208. * Return value indicating whether the next area to be generated could
  209. * start a new line. This should only be called in the "START" condition
  210. * if a previous inline BP couldn't end the line.
  211. * Return true if any space-start, border-start or padding-start, else
  212. * propagate to first child LM
  213. */
  214. public boolean canBreakBefore(LayoutContext context) {
  215. if (inlineProps.spaceStart.getSpace().min > 0 || hasLeadingFence(false)) {
  216. return true;
  217. }
  218. LayoutProcessor lm = getChildLM();
  219. if (lm != null) {
  220. return lm.canBreakBefore(context);
  221. } else {
  222. return false; // ??? NO child LM?
  223. }
  224. }
  225. protected MinOptMax getPrevIPD(LayoutManager lm) {
  226. return (MinOptMax) hmPrevIPD.get(lm);
  227. }
  228. /**
  229. * Clear the previous IPD calculation.
  230. */
  231. protected void clearPrevIPD() {
  232. hmPrevIPD.clear();
  233. }
  234. /**
  235. * Get the next break position for this layout manager.
  236. * The next break position will be an position within the
  237. * areas return by the child inline layout managers.
  238. *
  239. * @param lc the layout context for finding breaks
  240. * @return the next break position
  241. */
  242. public BreakPoss getNextBreakPoss(LayoutContext lc) {
  243. // Get a break from currently active child LM
  244. BreakPoss bp = null;
  245. LayoutProcessor curLM;
  246. SpaceSpecifier leadingSpace = lc.getLeadingSpace();
  247. if (lc.startsNewArea()) {
  248. // First call to this LM in new parent "area", but this may
  249. // not be the first area created by this inline
  250. childLC = new LayoutContext(lc);
  251. lc.getLeadingSpace().addSpace(inlineProps.spaceStart);
  252. // Check for "fence"
  253. if (hasLeadingFence(!lc.isFirstArea())) {
  254. // Reset leading space sequence for child areas
  255. leadingSpace = new SpaceSpecifier(false);
  256. }
  257. // Reset state variables
  258. clearPrevIPD(); // Clear stored prev content dimensions
  259. }
  260. // We only do this loop more than once if a childLM returns
  261. // a null BreakPoss, meaning it has nothing (more) to layout.
  262. while ((curLM = getChildLM()) != null) {
  263. // ignore nested blocks for now
  264. if (!curLM.generatesInlineAreas()) {
  265. getLogger().warn("ignoring block inside inline fo");
  266. curLM.setFinished(true);
  267. continue;
  268. }
  269. /* If first break for this child LM, set START_AREA flag
  270. * and initialize pending space from previous LM sibling's
  271. * trailing space specifiers.
  272. */
  273. boolean bFirstChildBP = (prevBP == null
  274. || prevBP.getLayoutManager() != curLM);
  275. initChildLC(childLC, prevBP, lc.startsNewArea(),
  276. bFirstChildBP, leadingSpace);
  277. if (lc.tryHyphenate()) {
  278. childLC.setHyphContext(lc.getHyphContext());
  279. }
  280. if (((bp = curLM.getNextBreakPoss(childLC)) != null)
  281. || (lc.tryHyphenate()
  282. && !lc.getHyphContext().hasMoreHyphPoints())) {
  283. break;
  284. }
  285. // If LM has no content, should it generate any area? If not,
  286. // should trailing space from a previous area interact with
  287. // leading space from a following area?
  288. }
  289. if (bp == null) {
  290. setFinished(true);
  291. return null; // There was no childLM with anything to layout
  292. // Alternative is to return a BP with the isLast flag set
  293. } else {
  294. boolean bIsLast = false;
  295. if (getChildLM() == null) {
  296. bIsLast = true;
  297. setFinished(true);
  298. } else if (bp.couldEndLine()) {
  299. /* Child LM ends with suppressible spaces. See if it could
  300. * end this LM's area too. Child LM finish flag is NOT set!
  301. */
  302. bIsLast = !hasMoreLM(bp.getLayoutManager());
  303. }
  304. return makeBreakPoss(bp, lc, bIsLast);
  305. }
  306. }
  307. /** ATTENTION: ALSO USED BY LineLayoutManager! */
  308. protected void initChildLC(LayoutContext childLC, BreakPoss prevBP,
  309. boolean bStartParent, boolean bFirstChildBP,
  310. SpaceSpecifier leadingSpace) {
  311. childLC.setFlags(LayoutContext.NEW_AREA,
  312. (bFirstChildBP || bStartParent));
  313. if (bStartParent) {
  314. // Start of a new line area or inline parent area
  315. childLC.setFlags(LayoutContext.FIRST_AREA, bFirstChildBP);
  316. childLC.setLeadingSpace(leadingSpace);
  317. } else if (bFirstChildBP) {
  318. // Space-after sequence from previous "area"
  319. childLC.setFlags(LayoutContext.FIRST_AREA, true);
  320. childLC.setLeadingSpace(prevBP.getTrailingSpace());
  321. } else {
  322. childLC.setLeadingSpace(null);
  323. }
  324. }
  325. private BreakPoss makeBreakPoss(BreakPoss bp, LayoutContext lc,
  326. boolean bIsLast) {
  327. NonLeafPosition inlbp = new NonLeafPosition(this, bp.getPosition());
  328. BreakPoss myBP = new BreakPoss(inlbp, bp.getFlags());
  329. myBP.setFlag(BreakPoss.ISFIRST, lc.isFirstArea());
  330. myBP.setFlag(BreakPoss.ISLAST, bIsLast);
  331. if (bIsLast) {
  332. lastChildLM = bp.getLayoutManager();
  333. }
  334. // Update dimension information for our allocation area,
  335. // including child areas
  336. // generated by previous childLM which have completed layout
  337. // Update pending area measure
  338. // This includes all previous breakinfo
  339. MinOptMax bpDim = (MinOptMax) bp.getStackingSize().clone();
  340. MinOptMax prevIPD = updatePrevIPD(bp, prevBP, lc.startsNewArea(),
  341. lc.isFirstArea());
  342. if (lc.startsNewArea()) {
  343. myBP.setLeadingSpace(lc.getLeadingSpace());
  344. }
  345. // Add size of previous child areas which are finished
  346. bpDim.add(prevIPD);
  347. SpaceSpecifier trailingSpace = bp.getTrailingSpace();
  348. if (hasTrailingFence(!bIsLast)) {
  349. bpDim.add(bp.resolveTrailingSpace(false));
  350. trailingSpace = new SpaceSpecifier(false);
  351. } else {
  352. // Need this to avoid modifying pending space specifiers
  353. // on previous BP from child as we use these on the next
  354. // call in this LM
  355. trailingSpace = (SpaceSpecifier) trailingSpace.clone();
  356. }
  357. trailingSpace.addSpace(inlineProps.spaceEnd);
  358. myBP.setTrailingSpace(trailingSpace);
  359. // Add start and end borders and padding
  360. bpDim.add(getExtraIPD(!lc.isFirstArea(), !bIsLast));
  361. myBP.setStackingSize(bpDim);
  362. myBP.setNonStackingSize(
  363. MinOptMax.add(bp.getNonStackingSize(), extraBPD));
  364. prevBP = bp;
  365. // if (bIsLast) {
  366. // setFinished(true); // Our last area, so indicate done
  367. // }
  368. return myBP;
  369. }
  370. /** ATTENTION: ALSO USED BY LineLayoutManager! */
  371. protected MinOptMax updatePrevIPD(BreakPoss bp, BreakPoss prevBP,
  372. boolean bStartParent, boolean bFirstArea) {
  373. MinOptMax prevIPD = new MinOptMax(0);
  374. if (bStartParent) {
  375. if (hasLeadingFence(!bFirstArea)) {
  376. // Space-start before first child area placed
  377. prevIPD.add(bp.resolveLeadingSpace());
  378. }
  379. hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
  380. } else {
  381. // In case of reset to a previous position, it may already
  382. // be calculated
  383. prevIPD = (MinOptMax) hmPrevIPD.get(bp.getLayoutManager());
  384. if (prevIPD == null) {
  385. // ASSERT(prevBP.getLayoutManager() != bp.getLayoutManager());
  386. /* This is first bp generated by child (in this parent area).
  387. * Calculate space-start on this area in combination with any
  388. * pending space-end with previous break.
  389. * Corresponds to Space between two child areas.
  390. */
  391. prevIPD = (MinOptMax) hmPrevIPD.get(
  392. prevBP.getLayoutManager());
  393. prevIPD = MinOptMax.add(prevIPD, bp.resolveLeadingSpace());
  394. prevIPD.add(prevBP.getStackingSize());
  395. hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
  396. }
  397. }
  398. return prevIPD;
  399. }
  400. public void getWordChars(StringBuffer sbChars, Position bp1,
  401. Position bp2) {
  402. Position endPos = ((NonLeafPosition) bp2).getPosition();
  403. Position prevPos = null;
  404. if (bp1 != null) {
  405. prevPos = ((NonLeafPosition) bp1).getPosition();
  406. if (prevPos.getLM() != endPos.getLM()) {
  407. prevPos = null;
  408. }
  409. }
  410. endPos.getLM().getWordChars(sbChars, prevPos, endPos);
  411. }
  412. /******
  413. protected BreakableText getText(BreakPoss prevBP, BreakPoss lastBP) {
  414. }
  415. *****/
  416. protected InlineParent createArea() {
  417. return new InlineParent();
  418. }
  419. /**
  420. * Generate and add areas to parent area.
  421. * Set size of each area. This should only create and return one
  422. * inline area for any inline parent area.
  423. *
  424. * @param parentIter Iterator over Position information returned
  425. * by this LayoutManager.
  426. * @param dSpaceAdjust Factor controlling how much extra space to add
  427. * in order to justify the line.
  428. */
  429. public void addAreas(PositionIterator parentIter,
  430. LayoutContext context) {
  431. InlineParent parent = createArea();
  432. parent.setHeight(context.getLineHeight());
  433. parent.setOffset(0);
  434. setCurrentArea(parent);
  435. setChildContext(new LayoutContext(context)); // Store current value
  436. // If has fence, make a new leadingSS
  437. /* How to know if first area created by this LM? Keep a count and
  438. * reset it if getNextBreakPoss() is called again.
  439. */
  440. if (hasLeadingFence(bAreaCreated)) {
  441. getContext().setLeadingSpace(new SpaceSpecifier(false));
  442. getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
  443. true);
  444. } else {
  445. getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
  446. false);
  447. }
  448. context.getLeadingSpace().addSpace(inlineProps.spaceStart);
  449. // posIter iterates over positions returned by this LM
  450. StackingIter childPosIter = new StackingIter(parentIter);
  451. LayoutProcessor prevLM = null;
  452. LayoutProcessor childLM ;
  453. while ((childLM = childPosIter.getNextChildLM()) != null) {
  454. //getContext().setTrailingSpace(new SpaceSpecifier(false));
  455. childLM.addAreas(childPosIter, getContext());
  456. getContext().setLeadingSpace(getContext().getTrailingSpace());
  457. getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
  458. true);
  459. prevLM = childLM;
  460. }
  461. /* If has trailing fence, resolve trailing space specs from descendants.
  462. * Otherwise, propagate any trailing space specs to parent LM via
  463. * the context object.
  464. * If the last child LM called return ISLAST in the context object
  465. * and it is the last child LM for this LM, then this must be
  466. * the last area for the current LM also.
  467. */
  468. boolean bIsLast =
  469. (getContext().isLastArea() && prevLM == lastChildLM);
  470. if (hasTrailingFence(bIsLast)) {
  471. addSpace(getCurrentArea(),
  472. getContext().getTrailingSpace().resolve(false),
  473. getContext().getSpaceAdjust());
  474. context.setTrailingSpace(new SpaceSpecifier(false));
  475. } else {
  476. // Propagate trailing space-spec sequence to parent LM in context
  477. context.setTrailingSpace(getContext().getTrailingSpace());
  478. }
  479. // Add own trailing space to parent context (or set on area?)
  480. if (context.getTrailingSpace() != null) {
  481. context.getTrailingSpace().addSpace(inlineProps.spaceEnd);
  482. }
  483. // Add border and padding to current area and set flags (FIRST, LAST ...)
  484. TraitSetter.setBorderPaddingTraits(getCurrentArea(),
  485. borderProps, bAreaCreated, !bIsLast);
  486. if (borderProps != null) {
  487. TraitSetter.addBorders(getCurrentArea(), borderProps);
  488. }
  489. if (backgroundProps != null) {
  490. TraitSetter.addBackground(getCurrentArea(), backgroundProps);
  491. }
  492. parentLM.addChild(getCurrentArea());
  493. context.setFlags(LayoutContext.LAST_AREA, bIsLast);
  494. bAreaCreated = true;
  495. }
  496. protected Area getCurrentArea() {
  497. return currentArea;
  498. }
  499. protected void setCurrentArea(Area area) {
  500. currentArea = area;
  501. }
  502. public void addChild(Area childArea) {
  503. // Make sure childArea is inline area
  504. if (childArea instanceof InlineArea) {
  505. Area parent = getCurrentArea();
  506. if (getContext().resolveLeadingSpace()) {
  507. addSpace(parent,
  508. getContext().getLeadingSpace().resolve(false),
  509. getContext().getSpaceAdjust());
  510. }
  511. parent.addChild(childArea);
  512. }
  513. }
  514. protected void setChildContext(LayoutContext lc) {
  515. childLC = lc;
  516. }
  517. // Current child layout context
  518. protected LayoutContext getContext() {
  519. return childLC ;
  520. }
  521. protected void addSpace(Area parentArea, MinOptMax spaceRange,
  522. double dSpaceAdjust) {
  523. if (spaceRange != null) {
  524. int iAdjust = spaceRange.opt;
  525. if (dSpaceAdjust > 0.0) {
  526. // Stretch by factor
  527. iAdjust += (int)((double)(spaceRange.max
  528. - spaceRange.opt) * dSpaceAdjust);
  529. } else if (dSpaceAdjust < 0.0) {
  530. // Shrink by factor
  531. iAdjust += (int)((double)(spaceRange.opt
  532. - spaceRange.min) * dSpaceAdjust);
  533. }
  534. if (iAdjust != 0) {
  535. //getLogger().debug("Add leading space: " + iAdjust);
  536. Space ls = new Space();
  537. ls.setWidth(iAdjust);
  538. parentArea.addChild(ls);
  539. }
  540. }
  541. }
  542. }