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.

LineLayoutManager.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /*
  2. * $Id: LineLayoutManager.java,v 1.24 2003/03/07 07:58:51 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 org.apache.fop.fo.PropertyManager;
  53. import org.apache.fop.fo.properties.CommonMarginBlock;
  54. import org.apache.fop.fo.properties.CommonHyphenation;
  55. import org.apache.fop.layout.hyphenation.Hyphenation;
  56. import org.apache.fop.layout.hyphenation.Hyphenator;
  57. import org.apache.fop.traits.BlockProps;
  58. import org.apache.fop.area.LineArea;
  59. import org.apache.fop.area.Resolveable;
  60. import org.apache.fop.fo.properties.TextAlign;
  61. import java.util.ListIterator;
  62. import java.util.Iterator;
  63. import java.util.List;
  64. import java.util.ArrayList;
  65. import org.apache.fop.traits.MinOptMax;
  66. /**
  67. * LayoutManager for lines. It builds one or more lines containing
  68. * inline areas generated by its sub layout managers.
  69. * A break is found for each line which may contain one of more
  70. * breaks from the child layout managers.
  71. * Once a break is found then it is return for the parent layout
  72. * manager to handle.
  73. * When the areas are being added to the page this manager
  74. * creates a line area to contain the inline areas added by the
  75. * child layout managers.
  76. */
  77. public class LineLayoutManager extends InlineStackingLayoutManager {
  78. /**
  79. * Private class to store information about inline breaks.
  80. * Each value holds the start and end indexes into a List of
  81. * inline break positions.
  82. */
  83. private static class LineBreakPosition extends LeafPosition {
  84. // int iPos;
  85. double dAdjust; // Percentage to adjust (stretch or shrink)
  86. double ipdAdjust; // Percentage to adjust (stretch or shrink)
  87. int startIndent;
  88. int lineHeight;
  89. int baseline;
  90. LineBreakPosition(LayoutProcessor lm, int iBreakIndex,
  91. double ipdA, double adjust, int ind, int lh, int bl) {
  92. super(lm, iBreakIndex);
  93. // iPos = iBreakIndex;
  94. ipdAdjust = ipdA;
  95. dAdjust = adjust;
  96. startIndent = ind;
  97. lineHeight = lh;
  98. baseline = bl;
  99. }
  100. }
  101. /** Break positions returned by inline content. */
  102. private List vecInlineBreaks = new ArrayList();
  103. private BreakPoss prevBP = null; // Last confirmed break position
  104. private int bTextAlignment = TextAlign.JUSTIFY;
  105. private int iTextIndent = 0;
  106. private int iIndents = 0;
  107. private CommonHyphenation hyphProps;
  108. private int lineHeight;
  109. private int lead;
  110. private int follow;
  111. // inline start pos when adding areas
  112. private int iStartPos = 0;
  113. /**
  114. * Create a new Line Layout Manager.
  115. * This is used by the block layout manager to create
  116. * line managers for handling inline areas flowing into line areas.
  117. *
  118. * @param lh the default line height
  119. * @param l the default lead, from top to baseline
  120. * @param f the default follow, from baseline to bottom
  121. */
  122. public LineLayoutManager(int lh, int l, int f) {
  123. lineHeight = lh;
  124. lead = l;
  125. follow = f;
  126. init(); // Normally done when started by parent!
  127. }
  128. /**
  129. * Initialize the properties for this layout manager.
  130. * The properties are from the block area.
  131. * @see org.apache.fop.layoutmgr.AbstractLayoutManager#initProperties(PropertyManager)
  132. */
  133. protected void initProperties(PropertyManager propMgr) {
  134. CommonMarginBlock marginProps = propMgr.getMarginProps();
  135. iIndents = marginProps.startIndent + marginProps.endIndent;
  136. BlockProps blockProps = propMgr.getBlockProps();
  137. bTextAlignment = blockProps.textAlign;
  138. iTextIndent = blockProps.firstIndent;
  139. hyphProps = propMgr.getHyphenationProps();
  140. }
  141. /**
  142. * Call child layout managers to generate content.
  143. * This gets the next break which is a full line.
  144. *
  145. * @param context the layout context for finding breaks
  146. * @return the next break position
  147. */
  148. public BreakPoss getNextBreakPoss(LayoutContext context) {
  149. // Get a break from currently active child LM
  150. // Set up constraints for inline level managers
  151. LayoutProcessor curLM ; // currently active LM
  152. BreakPoss prev = null;
  153. BreakPoss bp = null; // proposed BreakPoss
  154. ArrayList vecPossEnd = new ArrayList();
  155. // IPD remaining in line
  156. MinOptMax availIPD = context.getStackLimit();
  157. // QUESTION: maybe LayoutContext holds the Properties which
  158. // come from block-level?
  159. LayoutContext inlineLC = new LayoutContext(context);
  160. clearPrevIPD();
  161. int iPrevLineEnd = vecInlineBreaks.size();
  162. prevBP = null;
  163. while ((curLM = getChildLM()) != null) {
  164. // INITIALIZE LAYOUT CONTEXT FOR CALL TO CHILD LM
  165. // First break for the child LM in each of its areas
  166. boolean bFirstBPforLM = (vecInlineBreaks.isEmpty()
  167. || (((BreakPoss) vecInlineBreaks.get(vecInlineBreaks.size() - 1)).
  168. getLayoutManager() != curLM));
  169. // Need previous breakpoint! ATTENTION when backing up for hyphenation!
  170. prev = (vecInlineBreaks.isEmpty())
  171. ? null
  172. : (BreakPoss) vecInlineBreaks.get(vecInlineBreaks.size() - 1);
  173. initChildLC(inlineLC, prev,
  174. (vecInlineBreaks.size() == iPrevLineEnd),
  175. bFirstBPforLM, new SpaceSpecifier(true));
  176. /* If first BP in this line but line is not first in this
  177. * LM and previous line end decision was not forced (LINEFEED),
  178. * then set the SUPPRESS_LEADING_SPACE flag.
  179. */
  180. inlineLC.setFlags(LayoutContext.SUPPRESS_LEADING_SPACE,
  181. (vecInlineBreaks.size() == iPrevLineEnd
  182. && !vecInlineBreaks.isEmpty()
  183. && ((BreakPoss) vecInlineBreaks.get(vecInlineBreaks.size() - 1)).
  184. isForcedBreak() == false));
  185. // GET NEXT POSSIBLE BREAK FROM CHILD LM
  186. // prevBP = bp;
  187. if ((bp = curLM.getNextBreakPoss(inlineLC)) != null) {
  188. // Add any space before and previous content dimension
  189. MinOptMax prevIPD = updatePrevIPD(bp, prev,
  190. (vecInlineBreaks.size() == iPrevLineEnd),
  191. inlineLC.isFirstArea());
  192. MinOptMax bpDim =
  193. MinOptMax.add(bp.getStackingSize(), prevIPD);
  194. // check if this bp fits in line
  195. boolean bBreakOK = couldEndLine(bp);
  196. if (bBreakOK) {
  197. /* Add any non-conditional trailing space, assuming we
  198. * end the line here. If we can't break here, we just
  199. * check if the content fits.
  200. */
  201. bpDim.add(bp.resolveTrailingSpace(true));
  202. }
  203. // TODO: stop if linebreak is forced (NEWLINE)
  204. // PROBLEM: interaction with wrap which can be set
  205. // at lower levels!
  206. // System.err.println("BPdim=" + bpDim.opt);
  207. // Check if proposed area would fit in line
  208. if (bpDim.min > availIPD.max) {
  209. // See if we have already found a potential break
  210. //if (vecPossEnd.size() > 0) break;
  211. // This break position doesn't fit
  212. // TODO: If we are in nowrap, we use it as is!
  213. if (bTextAlignment == TextAlign.JUSTIFY || prevBP == null) {
  214. // If we are already in a hyphenation loop, then stop.
  215. if (inlineLC.tryHyphenate()) {
  216. break;
  217. }
  218. // Otherwise, prepare to try hyphenation
  219. if (!bBreakOK) {
  220. // Make sure we collect the entire word!
  221. vecInlineBreaks.add(bp);
  222. continue;
  223. }
  224. inlineLC.setHyphContext(
  225. getHyphenContext(prevBP, bp));
  226. if (inlineLC.getHyphContext() == null) {
  227. break;
  228. }
  229. inlineLC.setFlags(LayoutContext.TRY_HYPHENATE,
  230. true);
  231. // Reset to previous acceptable break
  232. reset();
  233. } else {
  234. /* If we are not in justified text, we can end the line at
  235. * prevBP.
  236. */
  237. break;
  238. }
  239. } else {
  240. // Add the BP to the list whether or not we can break
  241. vecInlineBreaks.add(bp);
  242. // Handle end of this LM's areas
  243. if (bBreakOK) {
  244. prevBP = bp; // Save reference to this BP
  245. if (bp.isForcedBreak()) {
  246. break;
  247. }
  248. if (bpDim.max >= availIPD.min) {
  249. /* This is a possible line BP (line could be filled)
  250. * bpDim.max >= availIPD.min
  251. * Keep this as a possible break, depending on
  252. * "cost". We will choose lowest cost.
  253. * Cost depends on stretch
  254. * (ie, bpDim.opt closes to availIPD.opt), keeps
  255. * and hyphenation.
  256. */
  257. vecPossEnd.add(new BreakCost(bp,
  258. Math.abs(availIPD.opt - bpDim.opt)));
  259. }
  260. // Otherwise it's short
  261. } else {
  262. /* Can't end line here. */
  263. }
  264. } // end of bpDim.min <= availIPD.max
  265. // end of getNextBreakPoss!=null on current child LM
  266. } else {
  267. /* The child LM can return a null BreakPoss if it has
  268. * nothing (more) to layout. This can happen when backing
  269. * up. Just try the next child LM.
  270. */
  271. }
  272. if (inlineLC.tryHyphenate()
  273. && !inlineLC.getHyphContext().hasMoreHyphPoints()) {
  274. break;
  275. }
  276. } // end of while on child LM
  277. if ((curLM = getChildLM()) == null) {
  278. // No more content to layout!
  279. setFinished(true);
  280. }
  281. if (bp == null) {
  282. return null;
  283. }
  284. if (prevBP == null) {
  285. prevBP = bp;
  286. }
  287. // Choose the best break
  288. if (!bp.isForcedBreak() && vecPossEnd.size() > 0) {
  289. prevBP = getBestBP(vecPossEnd);
  290. }
  291. // Backup child LM if necessary
  292. if (bp != prevBP && !bp.couldEndLine()) {
  293. reset();
  294. }
  295. // Don't justify last line in the sequence or if forced line-end
  296. int talign = bTextAlignment;
  297. if ((bTextAlignment == TextAlign.JUSTIFY
  298. && (prevBP.isForcedBreak()
  299. || isFinished()))) {
  300. talign = TextAlign.START;
  301. }
  302. return makeLineBreak(iPrevLineEnd, availIPD, talign);
  303. }
  304. private void reset() {
  305. while (vecInlineBreaks.get(vecInlineBreaks.size() - 1) != prevBP) {
  306. vecInlineBreaks.remove(vecInlineBreaks.size() - 1);
  307. }
  308. reset(prevBP.getPosition());
  309. }
  310. protected boolean couldEndLine(BreakPoss bp) {
  311. if (bp.canBreakAfter()) {
  312. return true; // no keep, ends on break char
  313. } else if (bp.isSuppressible()) {
  314. // NOTE: except at end of content for this LM!!
  315. // Never break after only space chars or any other sequence
  316. // of areas which would be suppressed at the end of the line.
  317. return false;
  318. } else {
  319. // See if could break before next area
  320. // TODO: do we need to set anything on the layout context?
  321. LayoutContext lc = new LayoutContext(0);
  322. LayoutProcessor nextLM = getChildLM();
  323. return (nextLM == null || nextLM.canBreakBefore(lc));
  324. }
  325. }
  326. private BreakPoss getBestBP(ArrayList vecPossEnd) {
  327. if (vecPossEnd.size() == 1) {
  328. return ((BreakCost) vecPossEnd.get(0)).getBP();
  329. }
  330. // Choose the best break (use a sort on cost!)
  331. Iterator iter = vecPossEnd.iterator();
  332. int minCost = Integer.MAX_VALUE;
  333. BreakPoss bestBP = null;
  334. while (iter.hasNext()) {
  335. BreakCost bc = (BreakCost) iter.next();
  336. if (bc.getCost() < minCost) {
  337. minCost = bc.getCost();
  338. bestBP = bc.getBP();
  339. }
  340. }
  341. return bestBP;
  342. }
  343. /** Line area is always considered to act as a fence. */
  344. protected boolean hasLeadingFence(boolean bNotFirst) {
  345. return true;
  346. }
  347. /** Line area is always considered to act as a fence. */
  348. protected boolean hasTrailingFence(boolean bNotLast) {
  349. return true;
  350. }
  351. private HyphContext getHyphenContext(BreakPoss prev,
  352. BreakPoss newBP) {
  353. // Get a "word" to hyphenate by getting characters from all
  354. // pending break poss which are in vecInlineBreaks, starting
  355. // with the position just AFTER prev.getPosition()
  356. vecInlineBreaks.add(newBP);
  357. ListIterator bpIter =
  358. vecInlineBreaks.listIterator(vecInlineBreaks.size());
  359. while (bpIter.hasPrevious() && bpIter.previous() != prev) {
  360. }
  361. if (bpIter.next() != prev) {
  362. getLogger().error("findHyphenPoss: problem!");
  363. return null;
  364. }
  365. StringBuffer sbChars = new StringBuffer(30);
  366. while (bpIter.hasNext()) {
  367. BreakPoss bp = (BreakPoss) bpIter.next();
  368. if (bp.getLayoutManager() == prev.getLayoutManager()) {
  369. bp.getLayoutManager().getWordChars(sbChars,
  370. prev.getPosition(), bp.getPosition());
  371. } else {
  372. bp.getLayoutManager().getWordChars(sbChars, null,
  373. bp.getPosition());
  374. }
  375. prev = bp;
  376. }
  377. vecInlineBreaks.remove(vecInlineBreaks.size() - 1); // remove last
  378. getLogger().debug("Word to hyphenate: " + sbChars.toString());
  379. // Now find all hyphenation points in this word (get in an array of offsets)
  380. // hyphProps are from the block level?. Note that according to the spec,
  381. // they also "apply to" fo:character. I don't know what that means, since
  382. // if we change language in the middle of a "word", the effect would seem
  383. // quite strange! Or perhaps in that case, we say that it's several words.
  384. // We probably should bring the hyphenation props up from the actual
  385. // TextLM which generate the hyphenation buffer, since these properties
  386. // inherit and could be specified on an inline or wrapper below the block
  387. // level.
  388. Hyphenation hyph = Hyphenator.hyphenate(hyphProps.language,
  389. hyphProps.country, sbChars.toString(),
  390. hyphProps.hyphenationRemainCharacterCount,
  391. hyphProps.hyphenationPushCharacterCount);
  392. // They hyph structure contains the information we need
  393. // Now start from prev: reset to that position, ask that LM to get
  394. // a Position for the first hyphenation offset. If the offset isn't in
  395. // its characters, it returns null, but must tell how many chars it had.
  396. // Keep looking at currentBP using next hyphenation point until the
  397. // returned size is greater than the available size or no more hyphenation
  398. // points remain. Choose the best break.
  399. if (hyph != null) {
  400. return new HyphContext(hyph.getHyphenationPoints());
  401. } else {
  402. return null;
  403. }
  404. }
  405. /**
  406. * Make a line break for returning as the next break.
  407. * This makes the line break and calculates the height and
  408. * ipd adjustment factors.
  409. *
  410. * @param prevLineEnd previous line break index
  411. * @param target the target ipd value
  412. * @param textalign the text align in operation for this line
  413. * @return the line break position
  414. */
  415. private BreakPoss makeLineBreak(int prevLineEnd, MinOptMax target,
  416. int textalign) {
  417. // make a new BP
  418. // Store information needed to make areas in the LineBreakPosition!
  419. // lead to baseline is
  420. // max of: baseline fixed alignment and middle/2
  421. // after baseline is
  422. // max: top height-lead, middle/2 and bottom height-lead
  423. int halfLeading = (lineHeight - lead - follow) / 2;
  424. // height before baseline
  425. int lineLead = lead + halfLeading;
  426. // maximum size of top and bottom alignment
  427. int maxtb = follow + halfLeading;
  428. // max size of middle alignment below baseline
  429. int middlefollow = maxtb;
  430. // calculate actual ipd
  431. MinOptMax actual = new MinOptMax();
  432. BreakPoss lastBP = null;
  433. LayoutManager lastLM = null;
  434. for (Iterator iter = vecInlineBreaks.listIterator(prevLineEnd);
  435. iter.hasNext();) {
  436. BreakPoss bp = (BreakPoss)iter.next();
  437. if (bp.getLead() > lineLead) {
  438. lineLead = bp.getLead();
  439. }
  440. if (bp.getTotal() > maxtb) {
  441. maxtb = bp.getTotal();
  442. }
  443. if (bp.getMiddle() > middlefollow) {
  444. middlefollow = bp.getMiddle();
  445. }
  446. // the stacking size of textLM accumulate for each break
  447. // so the ipd is only added at the end of each LM
  448. if (bp.getLayoutManager() != lastLM) {
  449. if (lastLM != null) {
  450. actual.add(lastBP.getStackingSize());
  451. }
  452. lastLM = bp.getLayoutManager();
  453. }
  454. lastBP = bp;
  455. }
  456. if (lastBP != null) {
  457. // add final ipd
  458. actual.add(lastBP.getStackingSize());
  459. // ATTENTION: make sure this hasn't gotten start space for next
  460. // LM added onto it!
  461. actual.add(lastBP.resolveTrailingSpace(true));
  462. }
  463. if (maxtb - lineLead > middlefollow) {
  464. middlefollow = maxtb - lineLead;
  465. }
  466. // in 7.21.4 the spec suggests that the leader and other
  467. // similar min/opt/max areas should be adjusted before
  468. // adjusting word spacing
  469. // Calculate stretch or shrink factor
  470. double ipdAdjust = 0;
  471. int targetWith = target.opt;
  472. int realWidth = actual.opt;
  473. if (actual.opt > targetWith) {
  474. if (actual.opt - targetWith < (actual.opt - actual.min)) {
  475. ipdAdjust = -(actual.opt - targetWith)
  476. / (float)(actual.opt - actual.min);
  477. realWidth = targetWith;
  478. } else {
  479. ipdAdjust = -1;
  480. realWidth = actual.max;
  481. }
  482. } else {
  483. if (targetWith - actual.opt < actual.max - actual.opt) {
  484. ipdAdjust = (targetWith - actual.opt)
  485. / (float)(actual.max - actual.opt);
  486. realWidth = targetWith;
  487. } else {
  488. ipdAdjust = 1;
  489. realWidth = actual.min;
  490. }
  491. }
  492. // if justifying then set the space adjustment
  493. // after the normal ipd adjustment
  494. double dAdjust = 0.0;
  495. int indent = 0;
  496. switch (textalign) {
  497. case TextAlign.JUSTIFY:
  498. if (realWidth != 0) {
  499. dAdjust = (targetWith - realWidth) / realWidth;
  500. }
  501. break;
  502. case TextAlign.START:
  503. //indent = 0;
  504. break;
  505. case TextAlign.CENTER:
  506. indent = (targetWith - realWidth) / 2;
  507. break;
  508. case TextAlign.END:
  509. indent = targetWith - realWidth;
  510. break;
  511. }
  512. LineBreakPosition lbp;
  513. lbp = new LineBreakPosition(this,
  514. vecInlineBreaks.size() - 1,
  515. ipdAdjust, dAdjust, indent,
  516. lineLead + middlefollow, lineLead);
  517. BreakPoss curLineBP = new BreakPoss(lbp);
  518. curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
  519. curLineBP.setStackingSize(new MinOptMax(lineLead + middlefollow));
  520. return curLineBP;
  521. }
  522. /**
  523. * Reset the positions to the given position.
  524. *
  525. * @param resetPos the position to reset to
  526. */
  527. public void resetPosition(Position resetPos) {
  528. if (resetPos == null) {
  529. iStartPos = 0;
  530. reset(null);
  531. vecInlineBreaks.clear();
  532. prevBP = null;
  533. } else {
  534. prevBP = (BreakPoss)vecInlineBreaks.get(((LineBreakPosition)resetPos).getLeafPos());
  535. while (vecInlineBreaks.get(vecInlineBreaks.size() - 1) != prevBP) {
  536. vecInlineBreaks.remove(vecInlineBreaks.size() - 1);
  537. }
  538. reset(prevBP.getPosition());
  539. }
  540. }
  541. /**
  542. * Add the areas with the break points.
  543. *
  544. * @param parentIter the iterator of break positions
  545. * @param context the context for adding areas
  546. */
  547. public void addAreas(PositionIterator parentIter,
  548. LayoutContext context) {
  549. addAreas(parentIter, 0.0);
  550. //vecInlineBreaks.clear();
  551. prevBP = null;
  552. }
  553. // Generate and add areas to parent area
  554. // Set size etc
  555. // dSpaceAdjust should reference extra space in the BPD
  556. /**
  557. * Add the areas with the associated space adjustment.
  558. *
  559. * @param parentIter the iterator of breaks positions
  560. * @param dSpaceAdjust the space adjustment
  561. */
  562. public void addAreas(PositionIterator parentIter, double dSpaceAdjust) {
  563. LayoutProcessor childLM;
  564. LayoutContext lc = new LayoutContext(0);
  565. while (parentIter.hasNext()) {
  566. LineBreakPosition lbp = (LineBreakPosition) parentIter.next();
  567. LineArea lineArea = new LineArea();
  568. lineArea.setStartIndent(lbp.startIndent);
  569. lineArea.setHeight(lbp.lineHeight);
  570. lc.setBaseline(lbp.baseline);
  571. lc.setLineHeight(lbp.lineHeight);
  572. setCurrentArea(lineArea);
  573. // Add the inline areas to lineArea
  574. PositionIterator inlinePosIter =
  575. new BreakPossPosIter(vecInlineBreaks, iStartPos,
  576. lbp.getLeafPos() + 1);
  577. iStartPos = lbp.getLeafPos() + 1;
  578. lc.setSpaceAdjust(lbp.dAdjust);
  579. lc.setIPDAdjust(lbp.ipdAdjust);
  580. lc.setLeadingSpace(new SpaceSpecifier(true));
  581. lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
  582. setChildContext(lc);
  583. while ((childLM = inlinePosIter.getNextChildLM()) != null) {
  584. childLM.addAreas(inlinePosIter, lc);
  585. lc.setLeadingSpace(lc.getTrailingSpace());
  586. lc.setTrailingSpace(new SpaceSpecifier(false));
  587. }
  588. // when can this be null?
  589. if (lc.getTrailingSpace() != null) {
  590. addSpace(lineArea, lc.getTrailingSpace().resolve(true),
  591. lc.getSpaceAdjust());
  592. }
  593. parentLM.addChild(lineArea);
  594. }
  595. setCurrentArea(null); // ?? necessary
  596. }
  597. /**
  598. * Add an unresolved area.
  599. * If a child layout manager needs to add an unresolved area
  600. * for page reference or linking then this intercepts it for
  601. * line area handling.
  602. * A line area may need to have the inline areas adjusted
  603. * to properly fill the line area. This adds a resolver that
  604. * resolves the inline area and can do the necessary
  605. * adjustments to the line and inline areas.
  606. *
  607. * @param id the id reference of the resolveable
  608. * @param res the resolveable object
  609. */
  610. public void addUnresolvedArea(String id, Resolveable res) {
  611. // create a resolveable class that handles ipd
  612. // adjustment for the current line
  613. parentLM.addUnresolvedArea(id, res);
  614. }
  615. }