1 17 18 19 20 package org.apache.fop.layoutmgr.inline; 21 22 import org.apache.commons.logging.Log; 23 import org.apache.commons.logging.LogFactory; 24 import org.apache.fop.datatypes.Length; 25 import org.apache.fop.datatypes.Numeric; 26 import org.apache.fop.fo.Constants; 27 import org.apache.fop.fo.FONode; 28 import org.apache.fop.fo.flow.Block; 29 import org.apache.fop.fo.properties.CommonHyphenation; 30 import org.apache.fop.hyphenation.Hyphenation; 31 import org.apache.fop.hyphenation.Hyphenator; 32 import org.apache.fop.layoutmgr.BlockLevelLayoutManager; 33 import org.apache.fop.layoutmgr.BreakElement; 34 import org.apache.fop.layoutmgr.BreakingAlgorithm; 35 import org.apache.fop.layoutmgr.ElementListObserver; 36 import org.apache.fop.layoutmgr.InlineKnuthSequence; 37 import org.apache.fop.layoutmgr.KnuthBlockBox; 38 import org.apache.fop.layoutmgr.KnuthBox; 39 import org.apache.fop.layoutmgr.KnuthElement; 40 import org.apache.fop.layoutmgr.KnuthGlue; 41 import org.apache.fop.layoutmgr.KnuthPenalty; 42 import org.apache.fop.layoutmgr.KnuthPossPosIter; 43 import org.apache.fop.layoutmgr.KnuthSequence; 44 import org.apache.fop.layoutmgr.LayoutContext; 45 import org.apache.fop.layoutmgr.LayoutManager; 46 import org.apache.fop.layoutmgr.LeafPosition; 47 import org.apache.fop.layoutmgr.ListElement; 48 import org.apache.fop.layoutmgr.NonLeafPosition; 49 import org.apache.fop.layoutmgr.Position; 50 import org.apache.fop.layoutmgr.PositionIterator; 51 import org.apache.fop.layoutmgr.SpaceSpecifier; 52 import org.apache.fop.area.Area; 53 import org.apache.fop.area.LineArea; 54 import org.apache.fop.area.inline.InlineArea; 55 56 import java.util.ListIterator ; 57 import java.util.List ; 58 import java.util.ArrayList ; 59 import java.util.LinkedList ; 60 import org.apache.fop.area.Trait; 61 import org.apache.fop.fonts.Font; 62 63 import org.apache.fop.traits.MinOptMax; 64 65 76 public class LineLayoutManager extends InlineStackingLayoutManager 77 implements BlockLevelLayoutManager { 78 79 82 private static Log log = LogFactory.getLog(LineLayoutManager.class); 83 84 private Block fobj; 85 private boolean isFirstInBlock; 86 87 88 public void initialize() { 89 textAlignment = fobj.getTextAlign(); 90 textAlignmentLast = fobj.getTextAlignLast(); 91 textIndent = fobj.getTextIndent(); 92 lastLineEndIndent = fobj.getLastLineEndIndent(); 93 hyphenationProperties = fobj.getCommonHyphenation(); 94 hyphenationLadderCount = fobj.getHyphenationLadderCount(); 95 wrapOption = fobj.getWrapOption(); 96 whiteSpaceTreament = fobj.getWhitespaceTreatment(); 97 effectiveAlignment = getEffectiveAlignment(textAlignment, textAlignmentLast); 99 isFirstInBlock = (this == getParent().getChildLMs().get(0)); 100 } 101 102 private int getEffectiveAlignment(int alignment, int alignmentLast) { 103 if (textAlignment != EN_JUSTIFY && textAlignmentLast == EN_JUSTIFY) { 104 return 0; 105 } else { 106 return textAlignment; 107 } 108 } 109 110 115 private static class LineBreakPosition extends LeafPosition { 116 private int iParIndex; private int iStartIndex; private int availableShrink; 119 private int availableStretch; 120 private int difference; 121 private double dAdjust; private double ipdAdjust; private int startIndent; 124 private int lineHeight; 125 private int lineWidth; 126 private int spaceBefore; 127 private int spaceAfter; 128 private int baseline; 129 130 LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex, 131 int shrink, int stretch, int diff, 132 double ipdA, double adjust, int ind, 133 int lh, int lw, int sb, int sa, int bl) { 134 super(lm, iBreakIndex); 135 availableShrink = shrink; 136 availableStretch = stretch; 137 difference = diff; 138 iParIndex = index; 139 this.iStartIndex = iStartIndex; 140 ipdAdjust = ipdA; 141 dAdjust = adjust; 142 startIndent = ind; 143 lineHeight = lh; 144 lineWidth = lw; 145 spaceBefore = sb; 146 spaceAfter = sa; 147 baseline = bl; 148 } 149 150 } 151 152 153 private int textAlignment = EN_JUSTIFY; 154 private int textAlignmentLast; 155 private int effectiveAlignment; 156 private Length textIndent; 157 private Length lastLineEndIndent; 158 private CommonHyphenation hyphenationProperties; 159 private Numeric hyphenationLadderCount; 160 private int wrapOption = EN_WRAP; 161 private int whiteSpaceTreament; 162 164 private Length lineHeight; 165 private int lead; 166 private int follow; 167 private AlignmentContext alignmentContext = null; 168 169 private List knuthParagraphs = null; 170 private int iReturnedLBP = 0; 171 172 private int flaggedPenalty = 50; 175 176 private LineLayoutPossibilities lineLayouts; 177 private List lineLayoutsList; 178 private int iLineWidth = 0; 179 180 186 public static final int DEFAULT_SPACE_WIDTH = 3336; 187 188 189 194 private class Update { 195 private InlineLevelLayoutManager inlineLM; 196 private int iFirstIndex; 197 198 public Update(InlineLevelLayoutManager lm, int index) { 199 inlineLM = lm; 200 iFirstIndex = index; 201 } 202 } 203 204 private class Paragraph extends InlineKnuthSequence { 206 207 private int ignoreAtStart = 0; 208 209 private int ignoreAtEnd = 0; 210 211 private MinOptMax lineFiller; 213 private int textAlignment; 214 private int textAlignmentLast; 215 private int textIndent; 216 private int lastLineEndIndent; 217 private int lineWidth; 218 private LineLayoutManager layoutManager; 220 221 public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast, 222 int indent, int endIndent) { 223 super(); 224 layoutManager = llm; 225 textAlignment = alignment; 226 textAlignmentLast = alignmentLast; 227 textIndent = indent; 228 lastLineEndIndent = endIndent; 229 } 230 231 public void startParagraph(int lw) { 232 lineWidth = lw; 233 startSequence(); 234 } 235 236 public void startSequence() { 237 if (textAlignment == EN_CENTER) { 240 lineFiller = new MinOptMax(lastLineEndIndent); 241 } else { 242 lineFiller = new MinOptMax(lastLineEndIndent, lastLineEndIndent, lineWidth); 243 } 244 245 if (textAlignment == EN_CENTER && textAlignmentLast != EN_JUSTIFY) { 247 this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0, 248 null, false)); 249 ignoreAtStart++; 250 } 251 252 if (isFirstInBlock && knuthParagraphs.size() == 0 255 && textIndent != 0) { 256 this.add(new KnuthInlineBox(textIndent, null, 257 null, false)); 258 ignoreAtStart++; 259 } 260 } 261 262 public void endParagraph() { 263 KnuthSequence finishedPar = this.endSequence(); 264 if (finishedPar != null) { 265 knuthParagraphs.add(finishedPar); 266 } 267 } 268 269 public KnuthSequence endSequence() { 270 if (this.size() > ignoreAtStart) { 271 if (textAlignment == EN_CENTER 272 && textAlignmentLast != EN_JUSTIFY) { 273 this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0, 274 null, false)); 275 this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE, 276 false, null, false)); 277 ignoreAtEnd = 2; 278 } else if (textAlignmentLast != EN_JUSTIFY) { 279 this.add(new KnuthPenalty(0, KnuthElement.INFINITE, 283 false, null, false)); 284 this.add(new KnuthGlue(0, 285 lineFiller.max - lineFiller.opt, 286 lineFiller.opt - lineFiller.min, null, false)); 287 this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE, 288 false, null, false)); 289 ignoreAtEnd = 3; 290 } else { 291 this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE, 293 false, null, false)); 294 ignoreAtEnd = 1; 295 } 296 return this; 297 } else { 298 this.clear(); 299 return null; 300 } 301 } 302 303 306 public boolean containsBox() { 307 for (int i = 0; i < this.size(); i++) { 308 KnuthElement el = (KnuthElement)this.get(i); 309 if (el.isBox()) { 310 return true; 311 } 312 } 313 return false; 314 } 315 } 316 317 private class LineBreakingAlgorithm extends BreakingAlgorithm { 318 private LineLayoutManager thisLLM; 319 private int pageAlignment; 320 private int activePossibility; 321 private int addedPositions; 322 private int textIndent; 323 private int fillerMinWidth; 324 private int lineHeight; 325 private int lead; 326 private int follow; 327 private int maxDiff; 328 private static final double MAX_DEMERITS = 10e6; 329 330 public LineBreakingAlgorithm (int pageAlign, 331 int textAlign, int textAlignLast, 332 int indent, int fillerWidth, 333 int lh, int ld, int fl, boolean first, 334 int maxFlagCount, LineLayoutManager llm) { 335 super(textAlign, textAlignLast, first, false, maxFlagCount); 336 pageAlignment = pageAlign; 337 textIndent = indent; 338 fillerMinWidth = fillerWidth; 339 lineHeight = lh; 340 lead = ld; 341 follow = fl; 342 thisLLM = llm; 343 activePossibility = -1; 344 maxDiff = fobj.getWidows() >= fobj.getOrphans() 345 ? fobj.getWidows() 346 : fobj.getOrphans(); 347 } 348 349 public void updateData1(int lineCount, double demerits) { 350 lineLayouts.addPossibility(lineCount, demerits); 351 if (super.log.isTraceEnabled()) { 352 super.log.trace( 353 "Layout possibility in " + lineCount + " lines; break at position:"); 354 } 355 } 356 357 public void updateData2(KnuthNode bestActiveNode, 358 KnuthSequence par, 359 int total) { 360 int indent = 0; 363 int difference = bestActiveNode.difference; 364 int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast; 365 indent += (textAlign == Constants.EN_CENTER) 366 ? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0; 367 indent += (bestActiveNode.line == 1 && bFirst && isFirstInBlock) ? textIndent : 0; 368 double ratio = (textAlign == Constants.EN_JUSTIFY 369 || difference < 0 && -difference <= bestActiveNode.availableShrink) 370 ? bestActiveNode.adjustRatio : 0; 371 372 375 if (activePossibility == -1) { 377 activePossibility = 0; 378 addedPositions = 0; 379 } 380 381 if (addedPositions == lineLayouts.getLineCount(activePossibility)) { 382 activePossibility++; 383 addedPositions = 0; 384 } 385 386 if (difference + bestActiveNode.availableShrink < 0) { 387 if (super.log.isWarnEnabled()) { 388 super.log.warn(FONode.decorateWithContextInfo( 389 "Line " + (addedPositions + 1) 390 + " of a paragraph overflows the available area.", getFObj())); 391 } 392 } 393 394 lineLayouts.addBreakPosition(makeLineBreakPosition(par, 397 (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1 : 0), 398 bestActiveNode.position, 399 bestActiveNode.availableShrink - (addedPositions > 0 400 ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min), 401 bestActiveNode.availableStretch, 402 difference, ratio, indent), activePossibility); 403 addedPositions++; 404 } 405 406 408 public void resetAlgorithm() { 409 activePossibility = -1; 410 } 411 412 private LineBreakPosition makeLineBreakPosition(KnuthSequence par, 413 int firstElementIndex, 414 int lastElementIndex, 415 int availableShrink, 416 int availableStretch, 417 int difference, 418 double ratio, 419 int indent) { 420 int spaceBefore = (lineHeight - lead - follow) / 2; 423 int spaceAfter = lineHeight - lead - follow - spaceBefore; 424 int lineLead = lead; 426 int lineFollow = follow; 428 boolean bZeroHeightLine = (difference == iLineWidth); 432 433 if (fobj.getLineStackingStrategy() != EN_FONT_HEIGHT) { 436 ListIterator inlineIterator 437 = par.listIterator(firstElementIndex); 438 AlignmentContext lastAC = null; 439 int maxIgnoredHeight = 0; for (int j = firstElementIndex; 441 j <= lastElementIndex; 442 j++) { 443 KnuthElement element = (KnuthElement) inlineIterator.next(); 444 if (element instanceof KnuthInlineBox ) { 445 AlignmentContext ac = ((KnuthInlineBox) element).getAlignmentContext(); 446 if (ac != null && lastAC != ac) { 447 if (!ac.usesInitialBaselineTable() 448 || ac.getAlignmentBaselineIdentifier() != EN_BEFORE_EDGE 449 && ac.getAlignmentBaselineIdentifier() != EN_AFTER_EDGE) { 450 int alignmentOffset = ac.getTotalAlignmentBaselineOffset(); 451 if (alignmentOffset + ac.getAltitude() > lineLead) { 452 lineLead = alignmentOffset + ac.getAltitude(); 453 } 454 if (ac.getDepth() - alignmentOffset > lineFollow) { 455 lineFollow = ac.getDepth() - alignmentOffset; 456 } 457 } else { 458 if (ac.getHeight() > maxIgnoredHeight) { 459 maxIgnoredHeight = ac.getHeight(); 460 } 461 } 462 lastAC = ac; 463 } 464 if (bZeroHeightLine 465 && (!element.isAuxiliary() || ac != null && ac.getHeight() > 0)) { 466 bZeroHeightLine = false; 467 } 468 } 469 } 470 471 if (lineFollow < maxIgnoredHeight - lineLead) { 472 lineFollow = maxIgnoredHeight - lineLead; 473 } 474 } 475 476 constantLineHeight = lineLead + lineFollow; 477 478 if (bZeroHeightLine) { 479 return new LineBreakPosition(thisLLM, 480 knuthParagraphs.indexOf(par), 481 firstElementIndex, lastElementIndex, 482 availableShrink, availableStretch, 483 difference, ratio, 0, indent, 484 0, iLineWidth, 0, 0, 0); 485 } else { 486 return new LineBreakPosition(thisLLM, 487 knuthParagraphs.indexOf(par), 488 firstElementIndex, lastElementIndex, 489 availableShrink, availableStretch, 490 difference, ratio, 0, indent, 491 lineLead + lineFollow, 492 iLineWidth, spaceBefore, spaceAfter, 493 lineLead); 494 } 495 } 496 497 public int findBreakingPoints(Paragraph par, 498 double threshold, boolean force, 499 int allowedBreaks) { 500 return super.findBreakingPoints(par, 501 threshold, force, allowedBreaks); 502 } 503 504 protected int filterActiveNodes() { 505 KnuthNode bestActiveNode = null; 506 507 if (pageAlignment == EN_JUSTIFY) { 508 for (int i = startLine; i < endLine; i++) { 511 for (KnuthNode node = getNode(i); node != null; node = node.next) { 512 bestActiveNode = compareNodes(bestActiveNode, node); 514 } 515 } 516 517 for (int i = startLine; i < endLine; i++) { 520 for (KnuthNode node = getNode(i); node != null; node = node.next) { 521 if (node.line != bestActiveNode.line 524 && node.totalDemerits > MAX_DEMERITS) { 525 removeNode(i, node); 527 } else { 528 } 530 } 531 } 532 } else { 533 for (int i = startLine; i < endLine; i++) { 535 for (KnuthNode node = getNode(i); node != null; node = node.next) { 536 bestActiveNode = compareNodes(bestActiveNode, node); 537 if (node != bestActiveNode) { 538 removeNode(i, node); 539 } 540 } 541 } 542 } 543 return bestActiveNode.line; 544 } 545 } 546 547 548 private int constantLineHeight = 12000; 549 550 551 560 public LineLayoutManager(Block block, Length lh, int l, int f) { 561 super(block); 562 fobj = block; 563 fobjIter = null; 566 lineHeight = lh; 567 lead = l; 568 follow = f; 569 } 570 571 572 public LinkedList getNextKnuthElements(LayoutContext context, int alignment) { 573 Font fs = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo(), this); 574 alignmentContext 575 = new AlignmentContext(fs, lineHeight.getValue(this), context.getWritingMode()); 576 context.setAlignmentContext(alignmentContext); 577 580 MinOptMax availIPD = context.getStackLimit(); 582 583 clearPrevIPD(); 584 585 if (knuthParagraphs == null) { 587 knuthParagraphs = new ArrayList (); 589 590 collectInlineKnuthElements(context, availIPD); 594 } else { 595 } 598 599 if (knuthParagraphs.size() == 0) { 601 setFinished(true); 602 return null; 603 } 604 605 return createLineBreaks(context.getBPAlignment(), context); 607 620 621 623 635 } 636 637 642 private void collectInlineKnuthElements(LayoutContext context, MinOptMax availIPD) { 643 LayoutContext inlineLC = new LayoutContext(context); 644 645 InlineLevelLayoutManager curLM; 646 LinkedList returnedList = null; 647 iLineWidth = context.getStackLimit().opt; 648 649 boolean bPrevWasKnuthBox = false; 652 653 StringBuffer trace = new StringBuffer ("LineLM:"); 654 655 Paragraph lastPar = null; 656 657 while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) { 658 returnedList = curLM.getNextKnuthElements(inlineLC, effectiveAlignment); 659 if (returnedList == null) { 660 continue; 665 } 666 if (returnedList.size() == 0) { 667 continue; 668 } 669 670 if (lastPar != null) { 671 KnuthSequence firstSeq = (KnuthSequence) returnedList.getFirst(); 672 673 if (!firstSeq.isInlineSequence()) { 675 lastPar.endParagraph(); 676 ElementListObserver.observe(lastPar, "line", null); 677 lastPar = null; 678 if (log.isTraceEnabled()) { 679 trace.append(" ]"); 680 } 681 bPrevWasKnuthBox = false; 682 } 683 684 if (lastPar != null) { 686 KnuthElement thisElement; 687 thisElement = (KnuthElement) firstSeq.get(0); 688 if (thisElement.isBox() && !thisElement.isAuxiliary() 689 && bPrevWasKnuthBox) { 690 lastPar.addALetterSpace(); 691 } 692 } 693 } 694 695 ListIterator iter = returnedList.listIterator(); 697 while (iter.hasNext()) { 698 KnuthSequence sequence = (KnuthSequence) iter.next(); 699 if (sequence.isInlineSequence()) { 701 ListElement lastElement; 703 lastElement = sequence.getLast(); 704 if (lastElement == null) { 705 throw new NullPointerException ( 706 "Sequence was empty! lastElement is null"); 707 } 708 bPrevWasKnuthBox = lastElement.isBox() && ((KnuthElement) lastElement).getW() != 0; 709 710 if (lastPar == null) { 713 lastPar = new Paragraph(this, 714 textAlignment, textAlignmentLast, 715 textIndent.getValue(this), 716 lastLineEndIndent.getValue(this)); 717 lastPar.startParagraph(availIPD.opt); 718 if (log.isTraceEnabled()) { 719 trace.append(" ["); 720 } 721 } else { 722 if (log.isTraceEnabled()) { 723 trace.append(" +"); 724 } 725 } 726 lastPar.addAll(sequence); 727 if (log.isTraceEnabled()) { 728 trace.append(" I"); 729 } 730 731 if (lastElement.isPenalty() 733 && ((KnuthPenalty) lastElement).getP() 734 == -KnuthPenalty.INFINITE) { 735 lastPar.removeLast(); 739 if (!lastPar.containsBox()) { 740 lastPar.add(new KnuthInlineBox(0, null, null, false)); 743 } 744 lastPar.endParagraph(); 745 ElementListObserver.observe(lastPar, "line", null); 746 lastPar = null; 747 if (log.isTraceEnabled()) { 748 trace.append(" ]"); 749 } 750 bPrevWasKnuthBox = false; 751 } 752 } else { knuthParagraphs.add(sequence); 755 if (log.isTraceEnabled()) { 756 trace.append(" B"); 757 } 758 } 759 } } 761 if (lastPar != null) { 762 lastPar.endParagraph(); 763 ElementListObserver.observe(lastPar, "line", fobj.getId()); 764 if (log.isTraceEnabled()) { 765 trace.append(" ]"); 766 } 767 } 768 log.trace(trace); 769 } 770 771 781 897 898 899 905 private LinkedList createLineBreaks(int alignment, LayoutContext context) { 906 907 ListIterator paragraphsIterator 909 = knuthParagraphs.listIterator(knuthParagraphs.size()); 910 lineLayoutsList = new ArrayList (knuthParagraphs.size()); 911 LineLayoutPossibilities llPoss; 912 while (paragraphsIterator.hasPrevious()) { 913 KnuthSequence seq = (KnuthSequence) paragraphsIterator.previous(); 914 if (!seq.isInlineSequence()) { 915 llPoss = new LineLayoutPossibilities(); 918 } else { 919 llPoss = findOptimalBreakingPoints(alignment, (Paragraph) seq); 920 } 921 lineLayoutsList.add(0, llPoss); 922 } 923 924 setFinished(true); 925 926 return postProcessLineBreaks(alignment, context); 928 } 929 930 936 private LineLayoutPossibilities findOptimalBreakingPoints(int alignment, Paragraph currPar) { 937 lineLayouts = new LineLayoutPossibilities(); 939 double maxAdjustment = 1; 940 int iBPcount = 0; 941 LineBreakingAlgorithm alg = new LineBreakingAlgorithm(alignment, 942 textAlignment, textAlignmentLast, 943 textIndent.getValue(this), currPar.lineFiller.opt, 944 lineHeight.getValue(this), lead, follow, 945 (knuthParagraphs.indexOf(currPar) == 0), 946 hyphenationLadderCount.getEnum() == EN_NO_LIMIT 947 ? 0 : hyphenationLadderCount.getValue(), 948 this); 949 950 if (hyphenationProperties.hyphenate == EN_TRUE 951 && fobj.getWrapOption() != EN_NO_WRAP) { 952 findHyphenationPoints(currPar); 953 } 954 955 int allowedBreaks; 957 if (wrapOption == EN_NO_WRAP) { 958 allowedBreaks = BreakingAlgorithm.ONLY_FORCED_BREAKS; 959 } else { 960 allowedBreaks = BreakingAlgorithm.NO_FLAGGED_PENALTIES; 961 } 962 alg.setConstantLineWidth(iLineWidth); 963 iBPcount = alg.findBreakingPoints(currPar, 964 maxAdjustment, false, allowedBreaks); 965 if (iBPcount == 0 || alignment == EN_JUSTIFY) { 966 if (iBPcount > 0) { 968 alg.resetAlgorithm(); 969 lineLayouts.savePossibilities(false); 970 } else { 971 log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment); 973 } 974 975 log.debug("Hyphenation possible? " + (hyphenationProperties.hyphenate == EN_TRUE)); 977 if (hyphenationProperties.hyphenate == EN_TRUE 978 && !(allowedBreaks == BreakingAlgorithm.ONLY_FORCED_BREAKS)) { 979 allowedBreaks = BreakingAlgorithm.ALL_BREAKS; 981 } else { 982 maxAdjustment = 5; 984 } 985 986 if ((iBPcount 987 = alg.findBreakingPoints(currPar, 988 maxAdjustment, false, allowedBreaks)) == 0) { 989 log.debug("No set of breaking points found with maxAdjustment = " 993 + maxAdjustment 994 + (hyphenationProperties.hyphenate == EN_TRUE 995 ? " and hyphenation" : "")); 996 maxAdjustment = 20; 997 iBPcount 998 = alg.findBreakingPoints(currPar, 999 maxAdjustment, true, allowedBreaks); 1000 } 1001 1002 lineLayouts.restorePossibilities(); 1004 1005 1008 if (false && alignment == EN_JUSTIFY && textAlignment == EN_JUSTIFY) { 1010 if (!lineLayouts.canUseMoreLines()) { 1013 alg.resetAlgorithm(); 1014 lineLayouts.savePossibilities(true); 1015 int savedLineWidth = iLineWidth; 1017 iLineWidth = (int) (iLineWidth * 0.95); 1018 iBPcount = alg.findBreakingPoints(currPar, 1019 maxAdjustment, true, allowedBreaks); 1020 lineLayouts.restorePossibilities(); 1022 iLineWidth = savedLineWidth; 1023 } 1024 if (!lineLayouts.canUseLessLines()) { 1025 alg.resetAlgorithm(); 1026 lineLayouts.savePossibilities(true); 1027 int savedLineWidth = iLineWidth; 1029 iLineWidth = (int) (iLineWidth * 1.05); 1030 alg.setConstantLineWidth(iLineWidth); 1031 iBPcount = alg.findBreakingPoints(currPar, 1032 maxAdjustment, true, allowedBreaks); 1033 lineLayouts.restorePossibilities(); 1035 iLineWidth = savedLineWidth; 1036 } 1037 } 1040 } 1041 return lineLayouts; 1042 } 1043 1044 1050 private LinkedList postProcessLineBreaks(int alignment, LayoutContext context) { 1051 1052 LinkedList returnList = new LinkedList (); 1053 1054 for (int p = 0; p < knuthParagraphs.size(); p++) { 1055 if (p > 0 && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) { 1057 returnList.add(new BreakElement( 1058 new Position(this), 0, context)); 1059 } 1061 1062 LineLayoutPossibilities llPoss; 1063 llPoss = (LineLayoutPossibilities) lineLayoutsList.get(p); 1064 KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(p); 1065 1066 if (!seq.isInlineSequence()) { 1067 LinkedList targetList = new LinkedList (); 1068 ListIterator listIter = seq.listIterator(); 1069 while (listIter.hasNext()) { 1070 ListElement tempElement; 1071 tempElement = (ListElement) listIter.next(); 1072 if (tempElement.getLayoutManager() != this) { 1073 tempElement.setPosition(notifyPos(new NonLeafPosition(this, 1074 tempElement.getPosition()))); 1075 } 1076 targetList.add(tempElement); 1077 } 1078 returnList.addAll(targetList); 1079 } else if (seq.isInlineSequence() && alignment == EN_JUSTIFY) { 1080 1083 Position returnPosition = new LeafPosition(this, p); 1084 createElements(returnList, llPoss, returnPosition); 1085 } else { 1086 1088 Position returnPosition = new LeafPosition(this, p); 1089 int startIndex = 0; 1090 for (int i = 0; 1091 i < llPoss.getChosenLineCount(); 1092 i++) { 1093 if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether() 1094 && i >= fobj.getOrphans() 1095 && i <= llPoss.getChosenLineCount() - fobj.getWidows() 1096 && returnList.size() > 0) { 1097 returnList.add(new BreakElement( 1099 returnPosition, 0, context)); 1100 } 1102 int endIndex 1103 = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos(); 1104 LinkedList footnoteList = new LinkedList (); 1107 ListIterator elementIterator = seq.listIterator(startIndex); 1108 while (elementIterator.nextIndex() <= endIndex) { 1109 KnuthElement element = (KnuthElement) elementIterator.next(); 1110 if (element instanceof KnuthInlineBox 1111 && ((KnuthInlineBox) element).isAnchor()) { 1112 footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM()); 1113 } else if (element instanceof KnuthBlockBox) { 1114 footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs()); 1115 } 1116 } 1117 startIndex = endIndex + 1; 1118 LineBreakPosition lbp 1119 = (LineBreakPosition) llPoss.getChosenPosition(i); 1120 returnList.add(new KnuthBlockBox 1121 (lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter, 1122 footnoteList, lbp, false)); 1123 1132 } 1133 } 1134 } 1135 1136 return returnList; 1137 } 1138 1139 1140 private void createElements(List list, LineLayoutPossibilities llPoss, 1141 Position elementPosition) { 1142 1143 int nInnerLines = 0; 1144 1145 int nOptionalLines = 0; 1146 1148 int nConditionalOptionalLines = 0; 1149 1150 int nEliminableLines = 0; 1151 1153 int nConditionalEliminableLines = 0; 1154 1155 int nFirstLines = fobj.getOrphans(); 1156 1157 int nLastLines = fobj.getWidows(); 1158 1159 List breaker = new LinkedList (); 1160 1161 1162 if (fobj.getOrphans() + fobj.getWidows() <= llPoss.getMinLineCount()) { 1163 nInnerLines = llPoss.getMinLineCount() 1164 - (fobj.getOrphans() + fobj.getWidows()); 1165 nOptionalLines = llPoss.getMaxLineCount() 1166 - llPoss.getOptLineCount(); 1167 nEliminableLines = llPoss.getOptLineCount() 1168 - llPoss.getMinLineCount(); 1169 } else if (fobj.getOrphans() + fobj.getWidows() <= llPoss.getOptLineCount()) { 1170 nOptionalLines = llPoss.getMaxLineCount() 1171 - llPoss.getOptLineCount(); 1172 nEliminableLines = llPoss.getOptLineCount() 1173 - (fobj.getOrphans() + fobj.getWidows()); 1174 nConditionalEliminableLines = (fobj.getOrphans() + fobj.getWidows()) 1175 - llPoss.getMinLineCount(); 1176 } else if (fobj.getOrphans() + fobj.getWidows() <= llPoss.getMaxLineCount()) { 1177 nOptionalLines = llPoss.getMaxLineCount() 1178 - (fobj.getOrphans() + fobj.getWidows()); 1179 nConditionalOptionalLines = (fobj.getOrphans() + fobj.getWidows()) 1180 - llPoss.getOptLineCount(); 1181 nConditionalEliminableLines = llPoss.getOptLineCount() 1182 - llPoss.getMinLineCount(); 1183 nFirstLines -= nConditionalOptionalLines; 1184 } else { 1185 nConditionalOptionalLines = llPoss.getMaxLineCount() 1186 - llPoss.getOptLineCount(); 1187 nConditionalEliminableLines = llPoss.getOptLineCount() 1188 - llPoss.getMinLineCount(); 1189 nFirstLines = llPoss.getOptLineCount(); 1190 nLastLines = 0; 1191 } 1192 1193 1194 1203 1204 if (nLastLines != 0 1205 && (nConditionalOptionalLines > 0 || nConditionalEliminableLines > 0)) { 1206 breaker.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false)); 1207 breaker.add(new KnuthGlue(0, -nConditionalOptionalLines * constantLineHeight, 1208 -nConditionalEliminableLines * constantLineHeight, 1209 LINE_NUMBER_ADJUSTMENT, elementPosition, false)); 1210 breaker.add(new KnuthPenalty(nConditionalOptionalLines * constantLineHeight, 1211 0, false, elementPosition, false)); 1212 breaker.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight, 1213 nConditionalEliminableLines * constantLineHeight, 1214 LINE_NUMBER_ADJUSTMENT, elementPosition, false)); 1215 } else if (nLastLines != 0) { 1216 breaker.add(new KnuthPenalty(0, 0, false, elementPosition, false)); 1217 } 1218 1219 1224 list.add(new KnuthBox(nFirstLines * constantLineHeight, elementPosition, 1227 (nLastLines == 0 1228 && nConditionalOptionalLines == 0 1229 && nConditionalEliminableLines == 0 ? true : false))); 1230 if (nConditionalOptionalLines > 0 1231 || nConditionalEliminableLines > 0) { 1232 list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false)); 1233 list.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight, 1234 nConditionalEliminableLines * constantLineHeight, 1235 LINE_NUMBER_ADJUSTMENT, elementPosition, false)); 1236 list.add(new KnuthBox(0, elementPosition, 1237 (nLastLines == 0 ? true : false))); 1238 } 1239 1240 for (int i = 0; i < nOptionalLines; i++) { 1242 list.addAll(breaker); 1243 list.add(new KnuthBox(0, elementPosition, false)); 1244 list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false)); 1245 list.add(new KnuthGlue(0, 1 * constantLineHeight, 0, 1246 LINE_NUMBER_ADJUSTMENT, elementPosition, false)); 1247 list.add(new KnuthBox(0, elementPosition, false)); 1248 } 1249 1250 for (int i = 0; i < nEliminableLines; i++) { 1252 list.addAll(breaker); 1253 list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false)); 1254 list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false)); 1255 list.add(new KnuthGlue(0, 0, 1 * constantLineHeight, 1256 LINE_NUMBER_ADJUSTMENT, elementPosition, false)); 1257 list.add(new KnuthBox(0, elementPosition, false)); 1258 } 1259 1260 for (int i = 0; i < nInnerLines; i++) { 1262 list.addAll(breaker); 1263 list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false)); 1264 } 1265 1266 if (nLastLines > 0) { 1268 list.addAll(breaker); 1269 list.add(new KnuthBox(nLastLines * constantLineHeight, 1270 elementPosition, true)); 1271 } 1272 } 1273 1274 1277 public boolean mustKeepTogether() { 1278 return ((BlockLevelLayoutManager) getParent()).mustKeepTogether(); 1279 } 1280 1281 1284 public boolean mustKeepWithPrevious() { 1285 return false; 1286 } 1287 1288 1291 public boolean mustKeepWithNext() { 1292 return false; 1293 } 1294 1295 1298 public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) { 1299 LeafPosition pos = (LeafPosition)lastElement.getPosition(); 1300 int totalAdj = adj; 1301 int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight 1306 + (adj > 0 ? - 0.4 : 0.4)); 1307 LineLayoutPossibilities llPoss; 1309 llPoss = (LineLayoutPossibilities) lineLayoutsList.get(pos.getLeafPos()); 1310 lineNumberDifference = llPoss.applyLineCountAdjustment(lineNumberDifference); 1311 return lineNumberDifference * constantLineHeight; 1312 } 1313 1314 1317 public void discardSpace(KnuthGlue spaceGlue) { 1318 } 1319 1320 1323 public LinkedList getChangedKnuthElements(List oldList, int alignment) { 1324 LinkedList returnList = new LinkedList (); 1325 for (int p = 0; p < knuthParagraphs.size(); p++) { 1326 LineLayoutPossibilities llPoss; 1327 llPoss = (LineLayoutPossibilities)lineLayoutsList.get(p); 1328 for (int i = 0; i < llPoss.getChosenLineCount(); i++) { 1330 if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether() 1331 && i >= fobj.getOrphans() 1332 && i <= llPoss.getChosenLineCount() - fobj.getWidows()) { 1333 returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false)); 1335 } 1336 LineBreakPosition lbp = (LineBreakPosition) llPoss.getChosenPosition(i); 1337 1340 MinOptMax contentIPD; 1342 if (alignment == EN_JUSTIFY) { 1343 contentIPD = new MinOptMax( 1344 lbp.lineWidth - lbp.difference - lbp.availableShrink, 1345 lbp.lineWidth - lbp.difference, 1346 lbp.lineWidth - lbp.difference + lbp.availableStretch); 1347 } else if (alignment == EN_CENTER) { 1348 contentIPD = new MinOptMax(lbp.lineWidth - 2 * lbp.startIndent); 1349 } else if (alignment == EN_END) { 1350 contentIPD = new MinOptMax(lbp.lineWidth - lbp.startIndent); 1351 } else { 1352 contentIPD = new MinOptMax(lbp.lineWidth - lbp.difference + lbp.startIndent); 1353 } 1354 returnList.add(new KnuthBlockBox(lbp.lineHeight, 1355 contentIPD, 1356 (lbp.ipdAdjust != 0 1357 ? lbp.lineWidth - lbp.difference : 0), 1358 lbp, false)); 1359 } 1360 } 1361 return returnList; 1362 } 1363 1364 1368 private void findHyphenationPoints(Paragraph currPar) { 1369 ListIterator currParIterator 1371 = currPar.listIterator(currPar.ignoreAtStart); 1372 LinkedList updateList = new LinkedList (); 1374 KnuthElement firstElement = null; 1375 KnuthElement nextElement = null; 1376 InlineLevelLayoutManager currLM = null; 1378 int boxCount; 1380 int auxCount; 1382 StringBuffer sbChars = null; 1383 1384 while (currParIterator.hasNext()) { 1386 firstElement = (KnuthElement) currParIterator.next(); 1387 if (firstElement.getLayoutManager() != currLM) { 1389 currLM = (InlineLevelLayoutManager) firstElement.getLayoutManager(); 1390 if (currLM != null) { 1391 updateList.add(new Update(currLM, currParIterator.previousIndex())); 1392 } else { 1393 break; 1394 } 1395 } else if (currLM == null) { 1396 break; 1397 } 1398 1400 if (firstElement.isBox() && !firstElement.isAuxiliary()) { 1403 boxCount = 1; 1404 auxCount = 0; 1405 sbChars = new StringBuffer (); 1406 currLM.getWordChars(sbChars, firstElement.getPosition()); 1407 while (currParIterator.hasNext()) { 1409 nextElement = (KnuthElement) currParIterator.next(); 1410 if (nextElement.isBox() && !nextElement.isAuxiliary()) { 1411 if (currLM != nextElement.getLayoutManager()) { 1413 currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager(); 1414 updateList.add(new Update(currLM, currParIterator.previousIndex())); 1415 } 1416 boxCount++; 1418 currLM.getWordChars(sbChars, nextElement.getPosition()); 1419 } else if (!nextElement.isAuxiliary()) { 1420 currParIterator.previous(); 1423 break; 1424 } else { 1425 if (currLM != nextElement.getLayoutManager()) { 1426 currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager(); 1427 updateList.add(new Update(currLM, currParIterator.previousIndex())); 1428 } 1429 auxCount++; 1431 } 1432 } 1433 log.trace(" Word to hyphenate: " + sbChars.toString()); 1434 HyphContext hc = getHyphenContext(sbChars); 1436 if (hc != null) { 1438 KnuthElement element = null; 1439 for (int i = 0; i < (boxCount + auxCount); i++) { 1440 currParIterator.previous(); 1441 } 1442 for (int i = 0; i < (boxCount + auxCount); i++) { 1443 element = (KnuthElement) currParIterator.next(); 1444 if (element.isBox() && !element.isAuxiliary()) { 1445 ((InlineLevelLayoutManager) 1446 element.getLayoutManager()).hyphenate(element.getPosition(), hc); 1447 } else { 1448 } 1450 } 1451 } 1452 } 1453 } 1454 1455 ListIterator updateListIterator = updateList.listIterator(); 1457 Update currUpdate = null; 1458 int iAddedElements = 0; 1460 1462 while (updateListIterator.hasNext()) { 1463 currUpdate = (Update) updateListIterator.next(); 1466 int fromIndex = currUpdate.iFirstIndex; 1467 int toIndex; 1468 if (updateListIterator.hasNext()) { 1469 Update nextUpdate = (Update) updateListIterator.next(); 1470 toIndex = nextUpdate.iFirstIndex; 1471 updateListIterator.previous(); 1472 } else { 1473 toIndex = currPar.size() - currPar.ignoreAtEnd 1475 - iAddedElements; 1476 } 1477 1478 if (((InlineLevelLayoutManager) currUpdate.inlineLM) 1481 .applyChanges(currPar.subList(fromIndex + iAddedElements, 1482 toIndex + iAddedElements))) { 1483 LinkedList newElements = null; 1485 newElements 1486 = currUpdate.inlineLM.getChangedKnuthElements 1487 (currPar.subList(fromIndex + iAddedElements, 1488 toIndex + iAddedElements), 1489 effectiveAlignment); 1490 currPar.subList(fromIndex + iAddedElements, 1492 toIndex + iAddedElements).clear(); 1493 currPar.addAll(fromIndex + iAddedElements, newElements); 1495 iAddedElements += newElements.size() - (toIndex - fromIndex); 1496 } 1497 } 1498 updateListIterator = null; 1499 updateList.clear(); 1500 } 1501 1502 1507 protected boolean hasLeadingFence(boolean isNotFirst) { 1508 return true; 1509 } 1510 1511 1516 protected boolean hasTrailingFence(boolean isNotLast) { 1517 return true; 1518 } 1519 1520 private HyphContext getHyphenContext(StringBuffer sbChars) { 1521 Hyphenation hyph 1535 = Hyphenator.hyphenate(hyphenationProperties.language, 1536 hyphenationProperties.country, 1537 getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(), 1538 sbChars.toString(), 1539 hyphenationProperties.hyphenationRemainCharacterCount, 1540 hyphenationProperties.hyphenationPushCharacterCount); 1541 if (hyph != null) { 1550 return new HyphContext(hyph.getHyphenationPoints()); 1551 } else { 1552 return null; 1553 } 1554 } 1555 1556 1561 public void resetPosition(Position resetPos) { 1562 if (resetPos == null) { 1563 setFinished(false); 1564 iReturnedLBP = 0; 1565 } else { 1566 if (isFinished()) { 1567 setFinished(false); 1571 iReturnedLBP--; 1572 } 1573 while ((LineBreakPosition) lineLayouts.getChosenPosition(iReturnedLBP) 1576 != (LineBreakPosition) resetPos) { 1577 iReturnedLBP--; 1578 } 1579 iReturnedLBP++; 1580 } 1581 } 1582 1583 1589 public void addAreas(PositionIterator parentIter, 1590 LayoutContext context) { 1591 while (parentIter.hasNext()) { 1592 Position pos = (Position) parentIter.next(); 1593 boolean isLastPosition = !parentIter.hasNext(); 1594 if (pos instanceof LineBreakPosition) { 1595 addInlineArea(context, pos, isLastPosition); 1596 } else if ((pos instanceof NonLeafPosition) && pos.generatesAreas()) { 1597 addBlockArea(context, pos, isLastPosition); 1598 } else { 1599 1604 } 1605 } 1606 setCurrentArea(null); } 1608 1609 1615 private void addInlineArea(LayoutContext context, Position pos, boolean isLastPosition) { 1616 ListIterator seqIterator = null; 1617 KnuthElement tempElement = null; 1618 LayoutManager lastLM = null; 1620 1621 LineBreakPosition lbp = (LineBreakPosition) pos; 1622 int iCurrParIndex; 1623 iCurrParIndex = lbp.iParIndex; 1624 KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex); 1625 int iStartElement = lbp.iStartIndex; 1626 int iEndElement = lbp.getLeafPos(); 1627 1628 LineArea lineArea 1629 = new LineArea((lbp.getLeafPos() < seq.size() - 1 1630 ? textAlignment : textAlignmentLast), 1631 lbp.difference, lbp.availableStretch, lbp.availableShrink); 1632 if (lbp.startIndent != 0) { 1633 lineArea.addTrait(Trait.START_INDENT, new Integer (lbp.startIndent)); 1634 } 1635 lineArea.setBPD(lbp.lineHeight); 1636 lineArea.setIPD(lbp.lineWidth); 1637 lineArea.addTrait(Trait.SPACE_BEFORE, new Integer (lbp.spaceBefore)); 1638 lineArea.addTrait(Trait.SPACE_AFTER, new Integer (lbp.spaceAfter)); 1639 alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline); 1640 1641 if (seq instanceof Paragraph) { 1642 Paragraph currPar = (Paragraph) seq; 1643 iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0; 1645 1646 if (iEndElement == (currPar.size() - 1)) { 1650 iEndElement -= currPar.ignoreAtEnd; 1651 lineArea.setIPD(lineArea.getIPD() - lastLineEndIndent.getValue(this)); 1652 } 1653 } 1654 1655 if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED 1657 || whiteSpaceTreament == EN_IGNORE 1658 || whiteSpaceTreament == EN_IGNORE_IF_BEFORE_LINEFEED) { 1659 seqIterator = seq.listIterator(iEndElement); 1661 tempElement = (KnuthElement) seqIterator.next(); 1662 if (tempElement.isGlue()) { 1663 iEndElement--; 1664 seqIterator.previous(); 1666 if (seqIterator.hasPrevious()) { 1667 tempElement = (KnuthElement) seqIterator.previous(); 1668 } else { 1669 tempElement = null; 1670 } 1671 } 1672 if (tempElement != null) { 1673 lastLM = tempElement.getLayoutManager(); 1674 } 1675 } 1676 1677 if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED 1679 || whiteSpaceTreament == EN_IGNORE 1680 || whiteSpaceTreament == EN_IGNORE_IF_AFTER_LINEFEED) { 1681 seqIterator = seq.listIterator(iStartElement); 1684 tempElement = (KnuthElement) seqIterator.next(); 1685 while (!tempElement.isBox() && seqIterator.hasNext()) { 1686 tempElement = (KnuthElement) seqIterator.next(); 1687 iStartElement++; 1688 } 1689 } 1690 PositionIterator inlinePosIter 1692 = new KnuthPossPosIter(seq, iStartElement, iEndElement + 1); 1693 1694 iStartElement = lbp.getLeafPos() + 1; 1695 if (iStartElement == seq.size()) { 1696 iStartElement = 0; 1698 } 1699 1700 LayoutContext lc = new LayoutContext(0); 1701 lc.setAlignmentContext(alignmentContext); 1702 lc.setSpaceAdjust(lbp.dAdjust); 1703 lc.setIPDAdjust(lbp.ipdAdjust); 1704 lc.setLeadingSpace(new SpaceSpecifier(true)); 1705 lc.setTrailingSpace(new SpaceSpecifier(false)); 1706 lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); 1707 1708 1713 if (false && textAlignment == EN_JUSTIFY) { 1714 int updatedDifference = context.getStackLimit().opt 1716 - lbp.lineWidth + lbp.difference; 1717 double updatedRatio = 0.0; 1718 if (updatedDifference > 0) { 1719 updatedRatio = (float) updatedDifference / lbp.availableStretch; 1720 } else if (updatedDifference < 0) { 1721 updatedRatio = (float) updatedDifference / lbp.availableShrink; 1722 } 1723 lc.setIPDAdjust(updatedRatio); 1724 } else if (false && textAlignment == EN_CENTER) { 1727 int updatedIndent = lbp.startIndent 1729 + (context.getStackLimit().opt - lbp.lineWidth) / 2; 1730 lineArea.addTrait(Trait.START_INDENT, new Integer (updatedIndent)); 1731 } else if (false && textAlignment == EN_END) { 1732 int updatedIndent = lbp.startIndent 1734 + (context.getStackLimit().opt - lbp.lineWidth); 1735 lineArea.addTrait(Trait.START_INDENT, new Integer (updatedIndent)); 1736 } 1737 1738 setCurrentArea(lineArea); 1739 setChildContext(lc); 1740 LayoutManager childLM; 1741 while ((childLM = inlinePosIter.getNextChildLM()) != null) { 1742 lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM)); 1743 childLM.addAreas(inlinePosIter, lc); 1744 lc.setLeadingSpace(lc.getTrailingSpace()); 1745 lc.setTrailingSpace(new SpaceSpecifier(false)); 1746 } 1747 1748 if (context.getSpaceAfter() > 0 1751 && (!context.isLastArea() || !isLastPosition)) { 1752 lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter()); 1753 } 1754 lineArea.finalise(); 1755 parentLM.addChildArea(lineArea); 1756 } 1757 1758 1764 private void addBlockArea(LayoutContext context, Position pos, boolean isLastPosition) { 1765 1771 List positionList = new ArrayList (1); 1772 Position innerPosition; 1773 innerPosition = ((NonLeafPosition) pos).getPosition(); 1774 positionList.add(innerPosition); 1775 1776 LayoutManager lastLM = null; 1778 if (isLastPosition) { 1779 lastLM = innerPosition.getLM(); 1780 } 1781 1782 LineArea lineArea = new LineArea(); 1783 setCurrentArea(lineArea); 1784 LayoutContext lc = new LayoutContext(0); 1785 lc.setAlignmentContext(alignmentContext); 1786 setChildContext(lc); 1787 1788 PositionIterator childPosIter = new StackingIter(positionList.listIterator()); 1789 LayoutContext blocklc = new LayoutContext(0); 1790 blocklc.setLeadingSpace(new SpaceSpecifier(true)); 1791 blocklc.setTrailingSpace(new SpaceSpecifier(false)); 1792 blocklc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); 1793 LayoutManager childLM; 1794 while ((childLM = childPosIter.getNextChildLM()) != null) { 1795 blocklc.setFlags(LayoutContext.LAST_AREA, 1797 (context.isLastArea() && childLM == lastLM)); 1798 blocklc.setStackLimit(context.getStackLimit()); 1799 childLM.addAreas(childPosIter, blocklc); 1801 blocklc.setLeadingSpace(blocklc.getTrailingSpace()); 1802 blocklc.setTrailingSpace(new SpaceSpecifier(false)); 1803 } 1804 lineArea.updateExtentsFromChildren(); 1805 parentLM.addChildArea(lineArea); 1806 } 1807 1808 1811 public void addChildArea(Area childArea) { 1812 if (childArea instanceof InlineArea) { 1814 Area parent = getCurrentArea(); 1815 if (getContext().resolveLeadingSpace()) { 1816 addSpace(parent, 1817 getContext().getLeadingSpace().resolve(false), 1818 getContext().getSpaceAdjust()); 1819 } 1820 parent.addChildArea(childArea); 1821 } 1822 } 1823 1824 1826 1829 public boolean getGeneratesBlockArea() { 1830 return true; 1831 } 1832 1833 1836 public boolean getGeneratesLineArea() { 1837 return true; 1838 } 1839} 1840 1841 | Popular Tags |