1 17 18 19 20 package org.apache.fop.layoutmgr.inline; 21 22 import java.util.ListIterator ; 23 import java.util.LinkedList ; 24 import java.util.List ; 25 26 import org.apache.commons.logging.Log; 27 import org.apache.commons.logging.LogFactory; 28 import org.apache.fop.area.Area; 29 import org.apache.fop.area.inline.InlineArea; 30 import org.apache.fop.area.inline.InlineBlockParent; 31 import org.apache.fop.area.inline.InlineParent; 32 import org.apache.fop.datatypes.Length; 33 import org.apache.fop.fo.flow.Inline; 34 import org.apache.fop.fo.flow.InlineLevel; 35 import org.apache.fop.fo.flow.Leader; 36 import org.apache.fop.fo.pagination.Title; 37 import org.apache.fop.fo.properties.CommonBorderPaddingBackground; 38 import org.apache.fop.fo.properties.CommonMarginInline; 39 import org.apache.fop.fo.properties.SpaceProperty; 40 import org.apache.fop.fonts.Font; 41 import org.apache.fop.layoutmgr.BlockKnuthSequence; 42 import org.apache.fop.layoutmgr.BlockLevelLayoutManager; 43 import org.apache.fop.layoutmgr.BreakElement; 44 import org.apache.fop.layoutmgr.KnuthBox; 45 import org.apache.fop.layoutmgr.KnuthSequence; 46 import org.apache.fop.layoutmgr.LayoutContext; 47 import org.apache.fop.layoutmgr.NonLeafPosition; 48 import org.apache.fop.layoutmgr.SpaceSpecifier; 49 import org.apache.fop.layoutmgr.TraitSetter; 50 import org.apache.fop.layoutmgr.LayoutManager; 51 import org.apache.fop.layoutmgr.Position; 52 import org.apache.fop.layoutmgr.PositionIterator; 53 import org.apache.fop.traits.MinOptMax; 54 import org.apache.fop.traits.SpaceVal; 55 56 60 public class InlineLayoutManager extends InlineStackingLayoutManager { 61 62 65 private static Log log = LogFactory.getLog(InlineLayoutManager.class); 66 67 private InlineLevel fobj; 68 69 private CommonMarginInline inlineProps = null; 70 private CommonBorderPaddingBackground borderProps = null; 71 72 private boolean areaCreated = false; 73 private LayoutManager lastChildLM = null; 75 private Position auxiliaryPosition; 76 77 private Font font; 78 79 80 protected Length alignmentAdjust; 81 82 protected int alignmentBaseline = EN_BASELINE; 83 84 protected Length baselineShift; 85 86 protected int dominantBaseline; 87 88 protected SpaceProperty lineHeight; 89 90 private AlignmentContext alignmentContext = null; 91 92 99 public InlineLayoutManager(InlineLevel node) { 101 super(node); 102 fobj = node; 103 } 104 105 private Inline getInlineFO() { 106 return (Inline)fobj; 107 } 108 109 110 public void initialize() { 111 int padding = 0; 112 font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo(), this); 113 lineHeight = fobj.getLineHeight(); 114 borderProps = fobj.getCommonBorderPaddingBackground(); 115 inlineProps = fobj.getCommonMarginInline(); 116 117 if (fobj instanceof Inline) { 118 alignmentAdjust = ((Inline)fobj).getAlignmentAdjust(); 119 alignmentBaseline = ((Inline)fobj).getAlignmentBaseline(); 120 baselineShift = ((Inline)fobj).getBaselineShift(); 121 dominantBaseline = ((Inline)fobj).getDominantBaseline(); 122 } else if (fobj instanceof Leader) { 123 alignmentAdjust = ((Leader)fobj).getAlignmentAdjust(); 124 alignmentBaseline = ((Leader)fobj).getAlignmentBaseline(); 125 baselineShift = ((Leader)fobj).getBaselineShift(); 126 dominantBaseline = ((Leader)fobj).getDominantBaseline(); 127 } 128 if (borderProps != null) { 129 padding = borderProps.getPadding(CommonBorderPaddingBackground.BEFORE, false, this); 130 padding += borderProps.getBorderWidth(CommonBorderPaddingBackground.BEFORE, 131 false); 132 padding += borderProps.getPadding(CommonBorderPaddingBackground.AFTER, false, this); 133 padding += borderProps.getBorderWidth(CommonBorderPaddingBackground.AFTER, false); 134 } 135 extraBPD = new MinOptMax(padding); 136 137 } 138 139 140 protected MinOptMax getExtraIPD(boolean isNotFirst, boolean isNotLast) { 141 int borderAndPadding = 0; 142 if (borderProps != null) { 143 borderAndPadding 144 = borderProps.getPadding(CommonBorderPaddingBackground.START, isNotFirst, this); 145 borderAndPadding 146 += borderProps.getBorderWidth(CommonBorderPaddingBackground.START, isNotFirst); 147 borderAndPadding 148 += borderProps.getPadding(CommonBorderPaddingBackground.END, isNotLast, this); 149 borderAndPadding 150 += borderProps.getBorderWidth(CommonBorderPaddingBackground.END, isNotLast); 151 } 152 return new MinOptMax(borderAndPadding); 153 } 154 155 156 157 protected boolean hasLeadingFence(boolean isNotFirst) { 158 return borderProps != null 159 && (borderProps.getPadding(CommonBorderPaddingBackground.START, isNotFirst, this) > 0 160 || borderProps.getBorderWidth(CommonBorderPaddingBackground.START, isNotFirst) > 0 161 ); 162 } 163 164 165 protected boolean hasTrailingFence(boolean isNotLast) { 166 return borderProps != null 167 && (borderProps.getPadding(CommonBorderPaddingBackground.END, isNotLast, this) > 0 168 || borderProps.getBorderWidth(CommonBorderPaddingBackground.END, isNotLast) > 0 169 ); 170 } 171 172 173 protected SpaceProperty getSpaceStart() { 174 return inlineProps != null ? inlineProps.spaceStart : null; 175 } 176 177 protected SpaceProperty getSpaceEnd() { 178 return inlineProps != null ? inlineProps.spaceEnd : null; 179 } 180 181 182 protected InlineArea createArea(boolean hasInlineParent) { 183 InlineArea area; 184 if (hasInlineParent) { 185 area = new InlineParent(); 186 area.setOffset(0); 187 } else { 188 area = new InlineBlockParent(); 189 } 190 if (fobj instanceof Inline) { 191 TraitSetter.setProducerID(area, getInlineFO().getId()); 192 } 193 return area; 194 } 195 196 199 protected void setTraits(boolean isNotFirst, boolean isNotLast) { 200 if (borderProps != null) { 201 TraitSetter.setBorderPaddingTraits(getCurrentArea(), 203 borderProps, isNotFirst, isNotLast, this); 204 TraitSetter.addBackground(getCurrentArea(), borderProps, this); 205 } 206 } 207 208 211 public boolean mustKeepTogether() { 213 return mustKeepTogether(this.getParent()); 214 } 215 216 private boolean mustKeepTogether(LayoutManager lm) { 217 if (lm instanceof BlockLevelLayoutManager) { 218 return ((BlockLevelLayoutManager) lm).mustKeepTogether(); 219 } else if (lm instanceof InlineLayoutManager) { 220 return ((InlineLayoutManager) lm).mustKeepTogether(); 221 } else { 222 return mustKeepTogether(lm.getParent()); 223 } 224 } 225 226 227 public LinkedList getNextKnuthElements(LayoutContext context, int alignment) { 228 LayoutManager curLM; 229 230 LinkedList returnedList; 232 233 LinkedList returnList = new LinkedList (); 235 KnuthSequence lastSequence = null; 236 237 SpaceSpecifier leadingSpace = context.getLeadingSpace(); 238 239 if (fobj instanceof Title) { 240 alignmentContext = new AlignmentContext(font, 241 lineHeight.getOptimum(this).getLength().getValue(this), 242 context.getWritingMode()); 243 244 } else { 245 alignmentContext = new AlignmentContext(font 246 , lineHeight.getOptimum(this).getLength().getValue(this) 247 , alignmentAdjust 248 , alignmentBaseline 249 , baselineShift 250 , dominantBaseline 251 , context.getAlignmentContext()); 252 } 253 254 childLC = new LayoutContext(context); 255 childLC.setAlignmentContext(alignmentContext); 256 257 if (context.startsNewArea()) { 258 if (getSpaceStart() != null) { 261 context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); 262 } 263 264 if (hasLeadingFence(!context.isFirstArea())) { 266 leadingSpace = new SpaceSpecifier(false); 268 } 269 clearPrevIPD(); } 272 273 StringBuffer trace = new StringBuffer ("InlineLM:"); 274 275 boolean borderAdded = false; 278 279 if (borderProps != null) { 280 childLC.setLineStartBorderAndPaddingWidth(context.getLineStartBorderAndPaddingWidth() 281 + borderProps.getPaddingStart(true, this) 282 + borderProps.getBorderStartWidth(true) 283 ); 284 childLC.setLineEndBorderAndPaddingWidth(context.getLineEndBorderAndPaddingWidth() 285 + borderProps.getPaddingEnd(true, this) 286 + borderProps.getBorderEndWidth(true) 287 ); 288 } 289 290 while ((curLM = (LayoutManager) getChildLM()) != null) { 291 if (!(curLM instanceof InlineLevelLayoutManager)) { 292 if (borderProps != null) { 295 childLC.setRefIPD(childLC.getRefIPD() 296 - borderProps.getPaddingStart(lastChildLM != null, this) 297 - borderProps.getBorderStartWidth(lastChildLM != null) 298 - borderProps.getPaddingEnd(hasNextChildLM(), this) 299 - borderProps.getBorderEndWidth(hasNextChildLM())); 300 } 301 } 302 returnedList = curLM.getNextKnuthElements(childLC, alignment); 304 if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) { 305 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); 306 } 307 if (returnedList == null) { 308 continue; 311 } 312 if (returnedList.size() == 0) { 313 continue; 314 } 315 if (curLM instanceof InlineLevelLayoutManager) { 316 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); 317 ListIterator seqIter = returnedList.listIterator(); 319 while (seqIter.hasNext()) { 320 KnuthSequence sequence = (KnuthSequence) seqIter.next(); 321 sequence.wrapPositions(this); 322 } 323 if (lastSequence != null && lastSequence.appendSequenceOrClose 324 ((KnuthSequence) returnedList.get(0))) { 325 returnedList.remove(0); 326 } 327 if (!borderAdded && returnedList.size() != 0) { 329 addKnuthElementsForBorderPaddingStart((KnuthSequence) returnedList.get(0)); 330 borderAdded = true; 331 } 332 returnList.addAll(returnedList); 333 } else { BlockKnuthSequence sequence = new BlockKnuthSequence(returnedList); 335 sequence.wrapPositions(this); 336 boolean appended = false; 337 if (lastSequence != null) { 338 if (lastSequence.canAppendSequence(sequence)) { 339 BreakElement bk = new BreakElement(new Position(this), 0, context); 340 boolean keepTogether = (mustKeepTogether() 341 || context.isKeepWithNextPending() 342 || childLC.isKeepWithPreviousPending()); 343 appended = lastSequence.appendSequenceOrClose(sequence, keepTogether, bk); 344 } else { 345 lastSequence.endSequence(); 346 } 347 } 348 if (!appended) { 349 if (!borderAdded) { 351 addKnuthElementsForBorderPaddingStart(sequence); 352 borderAdded = true; 353 } 354 returnList.add(sequence); 355 } 356 context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, 358 childLC.isKeepWithNextPending()); 359 childLC.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); 360 childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); 361 } 362 lastSequence = (KnuthSequence) returnList.getLast(); 363 lastChildLM = curLM; 364 } 365 366 if (lastSequence != null) { 367 addKnuthElementsForBorderPaddingEnd(lastSequence); 368 } 369 370 setFinished(true); 371 log.trace(trace); 372 return returnList.size() == 0 ? null : returnList; 373 } 374 375 384 public void addAreas(PositionIterator parentIter, 385 LayoutContext context) { 386 387 Position lastPos = null; 388 389 addId(); 390 391 setChildContext(new LayoutContext(context)); 393 if (hasLeadingFence(areaCreated)) { 395 getContext().setLeadingSpace(new SpaceSpecifier(false)); 396 getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); 397 } else { 398 getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, false); 399 } 400 401 if (getSpaceStart() != null) { 402 context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); 403 } 404 405 LinkedList positionList = new LinkedList (); 412 NonLeafPosition pos = null; 413 LayoutManager lastLM = null; while (parentIter.hasNext()) { 415 pos = (NonLeafPosition) parentIter.next(); 416 if (pos != null && pos.getPosition() != null) { 417 positionList.add(pos.getPosition()); 418 lastLM = pos.getPosition().getLM(); 419 lastPos = pos; 420 } 421 } 422 425 426 InlineArea parent = createArea(lastLM == null 427 || lastLM instanceof InlineLevelLayoutManager); 428 parent.setBPD(alignmentContext.getHeight()); 429 if (parent instanceof InlineParent) { 430 parent.setOffset(alignmentContext.getOffset()); 431 } else if (parent instanceof InlineBlockParent) { 432 if (borderProps != null) { 435 parent.setOffset(borderProps.getPaddingBefore(false, this) 436 + borderProps.getBorderBeforeWidth(false)); 437 } 438 } 439 setCurrentArea(parent); 440 441 StackingIter childPosIter 442 = new StackingIter(positionList.listIterator()); 443 444 LayoutManager prevLM = null; 445 LayoutManager childLM; 446 while ((childLM = childPosIter.getNextChildLM()) != null) { 447 getContext().setFlags(LayoutContext.LAST_AREA, 448 context.isLastArea() && childLM == lastLM); 449 childLM.addAreas(childPosIter, getContext()); 450 getContext().setLeadingSpace(getContext().getTrailingSpace()); 451 getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); 452 prevLM = childLM; 453 } 454 455 462 boolean isLast = (getContext().isLastArea() && prevLM == lastChildLM); 463 if (hasTrailingFence(isLast)) { 464 addSpace(getCurrentArea(), 465 getContext().getTrailingSpace().resolve(false), 466 getContext().getSpaceAdjust()); 467 context.setTrailingSpace(new SpaceSpecifier(false)); 468 } else { 469 context.setTrailingSpace(getContext().getTrailingSpace()); 471 } 472 if (context.getTrailingSpace() != null && getSpaceEnd() != null) { 474 context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd(), this)); 475 } 476 477 setTraits(areaCreated, lastPos == null || !isLast(lastPos)); 480 parentLM.addChildArea(getCurrentArea()); 481 482 context.setFlags(LayoutContext.LAST_AREA, isLast); 483 areaCreated = true; 484 } 485 486 487 public void addChildArea(Area childArea) { 488 Area parent = getCurrentArea(); 489 if (getContext().resolveLeadingSpace()) { 490 addSpace(parent, 491 getContext().getLeadingSpace().resolve(false), 492 getContext().getSpaceAdjust()); 493 } 494 parent.addChildArea(childArea); 495 } 496 497 498 public LinkedList getChangedKnuthElements(List oldList, int alignment) { 499 LinkedList returnedList = new LinkedList (); 500 addKnuthElementsForBorderPaddingStart(returnedList); 501 returnedList.addAll(super.getChangedKnuthElements(oldList, alignment)); 502 addKnuthElementsForBorderPaddingEnd(returnedList); 503 return returnedList; 504 } 505 506 510 protected void addKnuthElementsForBorderPaddingStart(List returnList) { 511 CommonBorderPaddingBackground borderAndPadding = fobj.getCommonBorderPaddingBackground(); 513 if (borderAndPadding != null) { 514 int ipStart = borderAndPadding.getBorderStartWidth(false) 515 + borderAndPadding.getPaddingStart(false, this); 516 if (ipStart > 0) { 517 returnList.add(0,new KnuthBox(ipStart, getAuxiliaryPosition(), true)); 518 } 519 } 520 } 521 522 526 protected void addKnuthElementsForBorderPaddingEnd(List returnList) { 527 CommonBorderPaddingBackground borderAndPadding = fobj.getCommonBorderPaddingBackground(); 529 if (borderAndPadding != null) { 530 int ipEnd = borderAndPadding.getBorderEndWidth(false) 531 + borderAndPadding.getPaddingEnd(false, this); 532 if (ipEnd > 0) { 533 returnList.add(new KnuthBox(ipEnd, getAuxiliaryPosition(), true)); 534 } 535 } 536 } 537 538 539 protected Position getAuxiliaryPosition() { 540 this.auxiliaryPosition = new NonLeafPosition(this, null); 543 return this.auxiliaryPosition; 545 } 546 547 548 protected void addId() { 549 if (fobj instanceof Inline) { 550 getPSLM().addIDToPage(getInlineFO().getId()); 551 } 552 } 553 554 } 555 556 | Popular Tags |