1 21 24 package org.lobobrowser.html.renderer; 25 26 import java.awt.*; 27 import java.awt.event.MouseEvent ; 28 import java.util.*; 29 30 import org.lobobrowser.html.*; 31 import org.lobobrowser.html.style.CSS2PropertiesImpl; 32 import org.lobobrowser.html.style.HtmlValues; 33 import org.lobobrowser.html.style.RenderState; 34 import org.lobobrowser.html.domimpl.*; 35 import org.w3c.dom.*; 36 import java.util.logging.*; 37 38 48 public class RBlockViewport extends BaseRCollection { 49 53 public static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0); 54 private static final Logger logger = Logger.getLogger(RBlockViewport.class.getName()); 55 56 private final ArrayList seqRenderables = new ArrayList(); 57 private final RenderableContainer container; 59 private final int listNesting; 60 private final UserAgentContext userAgentContext; 61 private final HtmlRendererContext rendererContext; 62 private final FrameContext frameContext; 63 64 private SortedSet positionedRenderables; 65 private RLine currentLine; 67 private int maxX; 68 private int maxY; 69 private int desiredWidth; private int desiredHeight; private int availContentHeight; private int availContentWidth; private int yLimit; 75 private int otherOrdinal; 76 private Insets paddingInsets; 77 private boolean overrideNoWrap; 78 79 private boolean skipParagraphBreakBefore; 81 private static final Map elementLayout = new HashMap(); 83 84 static { 85 Map el = elementLayout; 86 EmLayout em = new EmLayout(); 87 el.put("I", em); 88 el.put("EM", em); 89 el.put("CITE", em); 90 el.put("H1", new HLayout(24)); 91 el.put("H2", new HLayout(18)); 92 el.put("H3", new HLayout(15)); 93 el.put("H4", new HLayout(12)); 94 el.put("H5", new HLayout(10)); 95 el.put("H6", new HLayout(8)); 96 StrongLayout strong = new StrongLayout(); 97 el.put("B", strong); 98 el.put("STRONG", strong); 99 el.put("TH", strong); 100 el.put("U", new ULayout()); 101 el.put("STRIKE", new StrikeLayout()); 102 el.put("BR", new BrLayout()); 103 el.put("P", new PLayout()); 104 el.put("NOSCRIPT", new NoScriptLayout()); 105 NopLayout nop = new NopLayout(); 106 el.put("SCRIPT", nop); 107 el.put("HEAD", nop); 108 el.put("TITLE", nop); 109 el.put("META", nop); 110 el.put("STYLE", nop); 111 el.put("LINK", nop); 112 el.put("IMG", new ImgLayout()); 113 el.put("TABLE", new TableLayout()); 114 ChildrenLayout children = new ChildrenLayout(); 115 el.put("HTML", children); 116 AnchorLayout anchor = new AnchorLayout(); 117 el.put("A", anchor); 118 el.put("ANCHOR", anchor); 119 el.put("INPUT", new InputLayout2()); 120 el.put("TEXTAREA", new TextAreaLayout2()); 121 el.put("SELECT", new SelectLayout()); 122 ListItemLayout list = new ListItemLayout(); 123 el.put("UL", list); 124 el.put("OL", list); 125 el.put("LI", list); 126 CommonBlockLayout cbl = new CommonBlockLayout(); 127 el.put("PRE", cbl); 128 el.put("CENTER", cbl); 129 el.put("CAPTION", cbl); 130 DivLayout div = new DivLayout(); 131 el.put("DIV", div); 132 el.put("BODY", div); 133 el.put("DL", div); 134 el.put("DT", div); 135 BlockQuoteLayout bq = new BlockQuoteLayout(); 136 el.put("BLOCKQUOTE", bq); 137 el.put("DD", bq); 138 el.put("HR", new HrLayout()); 139 el.put("SPAN", new SpanLayout()); 140 ObjectLayout ol = new ObjectLayout(false, true); 141 el.put("OBJECT", new ObjectLayout(true, true)); 142 el.put("APPLET", ol); 143 el.put("EMBED", ol); 144 el.put("IFRAME", new IFrameLayout()); 145 } 146 147 155 public RBlockViewport(ModelNode modelNode, RenderableContainer container, int listNesting, UserAgentContext pcontext, HtmlRendererContext rcontext, FrameContext frameContext, RCollection parent) { 156 super(container, modelNode); 157 this.parent = parent; 158 this.userAgentContext = pcontext; 159 this.rendererContext = rcontext; 160 this.frameContext = frameContext; 161 this.container = container; 162 this.listNesting = listNesting; 163 this.layoutUpTreeCanBeInvalidated = true; 165 } 166 167 public void invalidateLayoutLocal() { 168 this.layoutUpTreeCanBeInvalidated = true; 171 } 172 173 public int getAvailContentWidth() { 174 return this.availContentWidth; 175 } 176 177 184 public void layout(int desiredWidth, int desiredHeight, Insets paddingInsets, NodeImpl rootNode, int yLimit, FloatingBounds floatBounds) { 185 if(!EventQueue.isDispatchThread() && logger.isLoggable(Level.INFO)) { 188 logger.warning("layout(): Invoked outside GUI dispatch thread."); 189 } 190 RenderableContainer container = this.container; 191 this.paddingInsets = paddingInsets; 192 this.yLimit = yLimit; 193 this.desiredHeight = desiredHeight; 194 this.desiredWidth = desiredWidth; 195 this.floatBounds = floatBounds; 196 197 this.maxX = paddingInsets.left; 199 this.maxY = paddingInsets.top; 200 201 int availw = desiredWidth - paddingInsets.left - paddingInsets.right; 202 if(availw < 0) { 203 availw = 0; 204 } 205 int availh = desiredHeight - paddingInsets.top - paddingInsets.bottom; 206 if(availh == 0) { 207 availh = 0; 208 } 209 this.availContentHeight = availh; 210 this.availContentWidth = availw; 211 Dimension desiredSize = new Dimension(desiredWidth, desiredHeight); 212 213 this.layoutPass(desiredSize, rootNode); 215 Collection delayedPairs = container.getDelayedPairs(); 216 if(delayedPairs != null && delayedPairs.size() > 0) { 217 Collection dpcopy = new LinkedList(); 218 dpcopy.addAll(delayedPairs); 219 Iterator i = dpcopy.iterator(); 221 while(i.hasNext()) { 222 DelayedPair pair = (DelayedPair) i.next(); 223 if(pair.targetParent == container) { 224 if(pair.alignment != 0) { 225 this.positionFloat(pair); 226 this.layoutPass(desiredSize, rootNode); 233 } 234 } 235 } 236 i = dpcopy.iterator(); 238 while(i.hasNext()) { 239 DelayedPair pair = (DelayedPair) i.next(); 240 if(pair.targetParent == container) { 241 if(pair.alignment == 0) { 242 this.importNonFloat(pair); 243 } 244 else { 245 this.addFloat(pair); 246 } 247 } 248 } 249 } 250 251 RLine lastLine = this.currentLine; 253 Rectangle lastBounds = lastLine.getBounds(); 254 int lastTopX = lastBounds.x + lastBounds.width; 255 if(lastTopX > this.maxX) { 256 this.maxX = lastTopX; 257 } 258 int lastTopY = lastBounds.y + lastBounds.height; 259 int maxY = this.maxY; 260 if(lastTopY > maxY) { 261 this.maxY = maxY = lastTopY; 262 } 263 this.width = paddingInsets.right + this.maxX; 264 this.height = paddingInsets.bottom + maxY; 265 } 266 267 private void layoutPass(Dimension desiredSize, NodeImpl rootNode) { 268 RenderableContainer container = this.container; 269 container.clearDelayedPairs(); 270 this.otherOrdinal = 0; 271 272 ArrayList renderables = this.seqRenderables; 274 renderables.clear(); 275 276 this.positionedRenderables = null; 278 279 Insets paddingInsets = this.paddingInsets; 281 282 this.currentLine = this.addLine(rootNode, paddingInsets, null); 284 this.skipParagraphBreakBefore = true; 285 286 this.layoutChildren(container, desiredSize, paddingInsets, rootNode); 289 290 } 298 299 306 public void align(int alignXPercent, int alignYPercent, int canvasWidth, int canvasHeight, Insets paddingInsets) { 307 int prevMaxX = this.maxX; 309 int prevMaxY = this.maxY; 310 if(alignXPercent > 0) { 312 ArrayList renderables = this.seqRenderables; 313 int availLineWidth = canvasWidth - paddingInsets.left - paddingInsets.right; 314 int numRenderables = renderables.size(); 315 for(int i = 0; i < numRenderables; i++) { 316 Object r = renderables.get(i); 317 if(r instanceof BoundableRenderable) { 318 BoundableRenderable line = (BoundableRenderable) r; 319 int y = line.getY(); 320 int leftOffset = this.fetchLeftOffset(y); 321 int rightOffset = this.fetchRightOffset(y); 322 int actualAvailWidth = availLineWidth - leftOffset - rightOffset; 323 int difference = actualAvailWidth - line.getWidth(); 324 if(difference > 0) { 325 int shift = (difference * alignXPercent) / 100; 326 int newX = paddingInsets.left + leftOffset + shift; 327 line.setX(newX); 328 if(newX + line.getWidth() > this.maxX) { 329 this.maxX = newX + line.getWidth(); 330 } 331 } 332 } 333 } 334 } 335 336 if(alignYPercent > 0) { 338 int availContentHeight = canvasHeight - paddingInsets.top - paddingInsets.bottom; 339 int usedHeight = this.maxY - paddingInsets.top; 340 int difference = availContentHeight - usedHeight; 341 if(difference > 0) { 342 int shift = (difference * alignYPercent) / 100; 343 Iterator renderables = this.seqRenderables.iterator(); 345 while(renderables.hasNext()) { 346 Object r = renderables.next(); 347 if(r instanceof BoundableRenderable) { 348 BoundableRenderable line = (BoundableRenderable) r; 349 int newY = line.getY() + shift; 350 line.setY(newY); 351 if(newY + line.getHeight() > this.maxY) { 352 this.maxY = newY + line.getHeight(); 353 } 354 } 355 } 356 357 Set others = this.positionedRenderables; 360 if(others != null) { 361 Iterator i2 = others.iterator(); 362 while(i2.hasNext()) { 363 PositionedRenderable pr = (PositionedRenderable) i2.next(); 364 if(pr.verticalAlignable) { 365 BoundableRenderable br = pr.renderable; 366 int newY = br.getY() + shift; 367 br.setY(newY); 368 if(newY + br.getHeight() > this.maxY) { 369 this.maxY = newY + br.getHeight(); 370 } 371 } 372 } 373 } 374 } 375 } 376 if(prevMaxX != this.maxX) { 377 this.width += (this.maxX - prevMaxX); 378 } 379 if(prevMaxY != this.maxY) { 380 this.height += (this.maxY - prevMaxY); 381 } 382 } 383 384 399 private RLine addLine(ModelNode startNode, Insets insets, RLine prevLine) { 400 int newLineY = prevLine == null ? insets.top : prevLine.y + prevLine.height; 401 this.checkY(newLineY); 402 int leftOffset = this.fetchLeftOffset(newLineY); 403 int insetsl = insets.left; 404 int newX = insetsl + leftOffset; 405 int newMaxWidth = this.availContentWidth - this.fetchRightOffset(newLineY) - leftOffset; 406 RLine rline; 407 if(prevLine == null) { 408 RenderState rs = this.modelNode.getRenderState(); 410 int textIndent = rs == null ? 0 : rs.getTextIndent(this.availContentWidth); 411 if(textIndent != 0) { 412 newX += textIndent; 413 } 414 rline = new RLine(startNode, this.container, newX, newLineY, newMaxWidth, 0); 415 } 416 else { 417 if(prevLine.x + prevLine.width > this.maxX) { 418 this.maxX = prevLine.x + prevLine.width; 419 } 420 rline = new RLine(startNode, this.container, newX, newLineY, newMaxWidth, 0); 421 } 422 rline.setParent(this); 423 this.seqRenderables.add(rline); 424 this.currentLine = rline; 425 return rline; 426 } 427 428 private void layoutMarkup(RenderableContainer container, Dimension containerSize, Insets insets, NodeImpl node) { 429 RenderState rs = node.getRenderState(); 433 Insets marginInsets = null; 434 Insets paddingInsets = null; 435 if(rs != null) { 436 marginInsets = rs.getMarginInsets(); 437 paddingInsets = rs.getPaddingInsets(); 438 } 439 int leftSpacing = 0; 440 int rightSpacing = 0; 441 if(marginInsets != null) { 442 leftSpacing += marginInsets.left; 443 rightSpacing += marginInsets.right; 444 } 445 if(paddingInsets != null) { 446 leftSpacing += paddingInsets.left; 447 rightSpacing += paddingInsets.right; 448 } 449 if(leftSpacing > 0) { 450 RLine line = this.currentLine; 451 line.addSpacing(new RSpacing(node, this.container, leftSpacing, line.height)); 452 } 453 this.layoutChildren(container, containerSize, insets, node); 454 if(rightSpacing > 0) { 455 RLine line = this.currentLine; 456 line.addSpacing(new RSpacing(node, this.container, rightSpacing, line.height)); 457 } 458 } 459 460 private void layoutChildren(RenderableContainer container, Dimension containerSize, Insets insets, NodeImpl node) { 461 NodeImpl[] childrenArray = node.getChildrenArray(); 462 if(childrenArray != null) { 463 int length = childrenArray.length; 464 for(int i = 0; i < length; i++) { 465 NodeImpl child = childrenArray[i]; 466 short nodeType = child.getNodeType(); 467 if(nodeType == Node.TEXT_NODE) { 468 this.layoutText(container, containerSize, insets, child); 469 } 470 else if(nodeType == Node.ELEMENT_NODE) { 471 String nodeName = child.getNodeName().toUpperCase(); 472 this.currentLine.addStyleChanger(new RStyleChanger(child)); 473 MarkupLayout ml = (MarkupLayout) elementLayout.get(nodeName); 474 if(ml != null) { 475 ml.layoutMarkup(this, container, containerSize, insets, (HTMLElementImpl) child); 476 } 477 else { 478 this.layoutMarkup(container, containerSize, insets, child); 479 } 480 this.currentLine.addStyleChanger(new RStyleChanger(node)); 481 } 482 else if(nodeType == Node.COMMENT_NODE) { 483 } 485 else { 486 throw new IllegalStateException ("Unknown node: " + child); 487 } 488 } 489 } 490 } 491 492 private final void positionRBlock(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, RBlock renderable) { 493 if(!this.addElsewhereIfPositioned(container, containerSize, insets, renderable, markupElement, false, true, false)) { 495 RLine line = this.currentLine; 497 int newY = line.getY() + line.getHeight(); 498 Insets paddingInsets = this.paddingInsets; 500 int newX = paddingInsets == null ? 0 : paddingInsets.left; 501 renderable.setOrigin(newX, newY); 502 FloatingBounds currentBounds = this.floatBounds; 503 RBlockViewport targetViewport = renderable.getRBlockViewport(); 504 FloatingBounds childBounds = currentBounds == null ? null : new OffsetFloatingBounds(currentBounds, this, this.paddingInsets, targetViewport, targetViewport.paddingInsets); 505 renderable.layout(this.availContentWidth, this.availContentHeight, true, false, childBounds, newY); 506 this.addAsSeqBlock(containerSize, insets, renderable, false, false, 0); 507 } 508 } 509 510 private final void positionRElement(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, RElement renderable, boolean usesAlignAttribute) { 511 if(!this.addElsewhereIfPositioned(container, containerSize, insets, renderable, markupElement, usesAlignAttribute, true, false)) { 512 renderable.layout(this.availContentWidth, this.availContentHeight, false, false); 513 this.addAsSeqBlock(containerSize, insets, renderable, false, false, 0); 514 } 515 } 516 517 private final void layoutRBlock(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, Insets defaultMarginInsets) { 518 RBlock renderable = (RBlock) markupElement.getUINode(); 519 if(renderable == null) { 520 renderable = new RBlock(markupElement, this.listNesting, this.userAgentContext, this.rendererContext, this.frameContext, this.container, RBlock.OVERFLOW_NONE); 521 markupElement.setUINode(renderable); 522 } 523 renderable.setOriginalParent(this); 524 renderable.setDefaultMarginInsets(defaultMarginInsets); 525 this.positionRBlock(container, containerSize, insets, markupElement, renderable); 526 } 527 528 private final void layoutRTable(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 529 RElement renderable = (RElement) markupElement.getUINode(); 530 if(renderable == null) { 531 renderable = new RTable(markupElement, this.userAgentContext, this.rendererContext, this.frameContext, container); 532 markupElement.setUINode((UINode) renderable); 533 } 534 renderable.setOriginalParent(this); 535 renderable.layout(this.availContentWidth, this.availContentHeight, false, false); 536 this.positionRElement(container, containerSize, insets, markupElement, renderable, markupElement instanceof HTMLTableElementImpl); 537 } 538 539 private final void layoutListItem(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 540 RListItem renderable = (RListItem) markupElement.getUINode(); 541 if(renderable == null) { 542 renderable = new RListItem(markupElement, this.listNesting, this.userAgentContext, this.rendererContext, this.frameContext, this.container, null); 543 markupElement.setUINode(renderable); 544 } 545 renderable.setOriginalParent(this); 546 this.positionRBlock(container, containerSize, insets, markupElement, renderable); 547 } 548 549 private final void layoutList(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 550 RList renderable = (RList) markupElement.getUINode(); 551 if(renderable == null) { 552 renderable = new RList(markupElement, this.listNesting, this.userAgentContext, this.rendererContext, this.frameContext, this.container, null); 553 markupElement.setUINode(renderable); 554 } 555 renderable.setOriginalParent(this); 556 this.positionRBlock(container, containerSize, insets, markupElement, renderable); 557 } 558 559 591 private void addParagraphBreak(RenderableContainer container, Dimension containerSize, Insets insets, ModelNode startNode) { 592 this.addLineBreak(container, containerSize, insets, startNode); 593 this.addLineBreak(container, containerSize, insets, startNode); 594 } 595 596 private void addLineBreak(RenderableContainer container, Dimension containerSize, Insets insets, ModelNode startNode) { 597 RLine line = this.currentLine; 598 if(line.getHeight() == 0) { 599 RenderState rs = startNode.getRenderState(); 600 int fontHeight = rs.getFontMetrics().getHeight(); 601 line.setHeight(fontHeight); 602 } 603 this.currentLine = this.addLine(startNode, insets, this.currentLine); 604 } 605 606 private boolean addElsewhereIfFloat(RenderableContainer container, Dimension containerSize, Insets insets, RElement renderable, HTMLElementImpl element, boolean usesAlignAttribute, CSS2PropertiesImpl style, boolean layout) { 607 String align = null; 609 if(style != null) { 610 align = style.getFloat(); 611 if(align != null && align.length() == 0) { 612 align = null; 613 } 614 } 615 if(align == null && usesAlignAttribute) { 616 align = element.getAttribute("align"); 617 } 618 if(align != null) { 619 if("left".equalsIgnoreCase(align)) { 620 this.addToLeftMargin(renderable, layout); 621 return true; 622 } 623 else if("right".equalsIgnoreCase(align)) { 624 this.addToRightMargin(renderable, layout); 625 return true; 626 } 627 else { 628 } 630 } 631 return false; 632 } 633 634 final RBlockViewport getParentViewport(ExportedRenderable er) { 635 if(er.alignment == 0) { 636 return this.getParentViewport(); 637 } 638 else { 639 return this.getParentViewportForAlign(); 640 } 641 } 642 643 final boolean isImportable(ExportedRenderable er) { 644 if(er.alignment == 0) { 645 return this.positionsAbsolutes(); 646 } 647 else { 648 return this.getParentViewportForAlign() == null; 649 } 650 } 651 652 final RBlockViewport getParentViewport() { 653 RCollection parent = this.getOriginalOrCurrentParent(); 655 while(parent != null && !(parent instanceof RBlockViewport)) { 656 parent = parent.getOriginalOrCurrentParent(); 657 } 658 return (RBlockViewport) parent; 659 } 660 661 final RBlockViewport getParentViewportForAlign() { 662 Object parent = this.getOriginalOrCurrentParent(); 664 if(parent instanceof RBlock) { 665 RBlock block = (RBlock) parent; 666 if(!block.couldBeScrollable()) { 667 parent = ((BaseElementRenderable) parent).getOriginalOrCurrentParent(); 668 if(parent instanceof RBlockViewport) { 669 return (RBlockViewport) parent; 670 } 671 } 672 } 673 return null; 674 } 675 676 680 final boolean positionsAbsolutes() { 681 ModelNode node = this.getModelNode(); 682 if(node instanceof HTMLElementImpl) { 683 HTMLElementImpl element = (HTMLElementImpl) node; 684 CSS2PropertiesImpl style = element.getCurrentStyle(); 685 if(style != null) { 686 String position = style.getPosition(); 687 return position != null && (position.equalsIgnoreCase("absolute") || position.equalsIgnoreCase("fixed") || position.equalsIgnoreCase("relative")); 688 } 689 else { 690 return false; 691 } 692 } 693 else if(node instanceof HTMLDocumentImpl) { 694 return true; 695 } 696 else { 697 return false; 698 } 699 } 700 701 711 private boolean addElsewhereIfPositioned(RenderableContainer container, Dimension containerSize, Insets insets, RElement renderable, HTMLElementImpl element, boolean usesAlignAttribute, boolean layout, boolean obeysMargins) { 712 CSS2PropertiesImpl style = element.getCurrentStyle(); 714 String position = null; 715 if(style != null) { 716 position = style.getPosition(); 717 if(position != null && position.length() == 0) { 718 position = null; 719 } 720 } 721 boolean absolute = position != null && "absolute".equalsIgnoreCase(position); 722 boolean relative = position != null && "relative".equalsIgnoreCase(position); 723 if(absolute || relative) { 724 if(layout) { 725 if(relative) { 727 renderable.layout(this.availContentWidth, this.availContentHeight, true, false); 728 } 729 else { 730 renderable.layout(this.availContentWidth, this.availContentHeight, false, false); 731 } 732 } 733 RenderState rs = element.getRenderState(); 734 String leftText = style.getLeft(); 735 RLine line = this.currentLine; 736 int lineBottomY = line == null ? 0 : line.getY() + line.getHeight(); 737 int newLeft; 738 if(leftText != null) { 739 newLeft = HtmlValues.getPixelSize(leftText, rs, 0, this.availContentWidth); 740 } 741 else { 742 String rightText = style.getRight(); 743 if(rightText != null) { 744 int right = HtmlValues.getPixelSize(rightText, rs, 0, this.availContentWidth); 745 newLeft = containerSize.width - right - renderable.getWidth(); 746 } 749 else { 750 newLeft = 0; 751 } 752 } 753 int newTop = relative ? 0 : lineBottomY; 754 String topText = style.getTop(); 755 if(topText != null) { 756 newTop = HtmlValues.getPixelSize(topText, rs, newTop, this.availContentHeight); 757 } 758 else { 759 String bottomText = style.getBottom(); 760 if(bottomText != null) { 761 int bottom = HtmlValues.getPixelSize(bottomText, rs, 0, this.availContentHeight); 762 newTop = containerSize.height - bottom - renderable.getHeight(); 763 if(!relative && newTop < 0) { 764 newTop = 0; 765 } 766 } 767 } 768 if(relative) { 769 boolean added = false; 771 if(!this.addElsewhereIfFloat(container, containerSize, insets, renderable, element, usesAlignAttribute, style, false)) { 772 this.addAsSeqBlock(containerSize, insets, renderable, true, obeysMargins, 0); 774 } 775 else { 776 added = true; 777 } 778 renderable.setOrigin(renderable.getX() + newLeft, renderable.getY() + newTop); 780 if(!added) { 782 this.addPositionedRenderable(renderable, true); 783 } 784 } 785 else { 786 this.scheduleAbsDelayedPair(renderable, newLeft, newTop, 0); 789 return true; 791 } 792 int newBottomY = renderable.getY() + renderable.getHeight(); 793 this.checkY(newBottomY); 794 if(newBottomY > this.maxY) { 795 this.maxY = newBottomY; 796 } 797 return true; 798 } 799 else { 800 if(this.addElsewhereIfFloat(container, containerSize, insets, renderable, element, usesAlignAttribute, style, layout)) { 801 return true; 802 } 803 } 804 return false; 805 } 806 807 private boolean isPositionedElsewhere() { 808 ModelNode node = this.modelNode; 809 if(node instanceof HTMLElementImpl) { 810 CSS2PropertiesImpl style = ((HTMLElementImpl) node).getCurrentStyle(); 811 if(style != null) { 812 String position = style.getPosition(); 813 if(position != null) { 814 if("absolute".equalsIgnoreCase(position) || "relative".equalsIgnoreCase(position)) { 815 return true; 817 } 818 } 819 String floatText = style.getFloat(); 820 if(floatText != null) { 821 if("left".equalsIgnoreCase(floatText) || "right".equalsIgnoreCase(floatText)) { 822 return true; 823 } 824 } 825 } 826 } 827 return false; 828 } 829 830 833 private void addRenderableToLineCheckStyle(RenderableContainer container, Dimension containerSize, Insets insets, RElement renderable, HTMLElementImpl element, boolean usesAlignAttribute) { 834 if(this.addElsewhereIfPositioned(container, containerSize, insets, renderable, element, usesAlignAttribute, false, true)) { 835 return; 836 } 837 this.addRenderableToLine(container, insets, renderable); 838 } 839 840 private void addRenderableToLine(RenderableContainer container, Insets insets, Renderable renderable) { 841 RenderState rs = renderable.getModelNode().getRenderState(); 843 int whiteSpace = this.overrideNoWrap ? RenderState.WS_NOWRAP : rs.getWhiteSpace(); 844 boolean allowOverflow = whiteSpace == RenderState.WS_NOWRAP || whiteSpace == RenderState.WS_PRE; 845 this.skipParagraphBreakBefore = false; 846 RLine line = this.currentLine; 847 try { 848 line.add(renderable, allowOverflow); 849 } catch(OverflowException oe) { 850 this.addLine(renderable.getModelNode(), insets, line); 851 Collection renderables = oe.getRenderables(); 852 Iterator i = renderables.iterator(); 853 while(i.hasNext()) { 854 Renderable r = (Renderable) i.next(); 855 this.addRenderableToLine(container, insets, r); 856 } 857 } 858 if(renderable instanceof RUIControl) { 859 this.container.add(((RUIControl) renderable).widget.getComponent()); 860 } 861 } 862 863 private void addWordToLine(RenderableContainer container, Insets insets, RWord renderable, boolean allowOverflow) { 864 this.skipParagraphBreakBefore = false; 866 RLine line = this.currentLine; 867 try { 868 line.addWord(renderable, allowOverflow); 869 } catch(OverflowException oe) { 870 this.addLine(renderable.getModelNode(), insets, line); 871 Collection renderables = oe.getRenderables(); 872 Iterator i = renderables.iterator(); 873 while(i.hasNext()) { 874 Renderable r = (Renderable) i.next(); 875 this.addRenderableToLine(container, insets, r); 876 } 877 } 878 } 879 880 private void addAsSeqBlockCheckStyle(Dimension containerSize, Insets insets, RElement block, HTMLElementImpl element, boolean usesAlignAttribute) { 881 if(this.addElsewhereIfPositioned(this.container, containerSize, insets, block, element, usesAlignAttribute, false, true)) { 882 return; 883 } 884 this.addAsSeqBlock(containerSize, insets, block, 0); 885 } 886 887 private void addAsSeqBlock(Dimension containerSize, Insets insets, BoundableRenderable block, int alignXPercent) { 888 this.addAsSeqBlock(containerSize, insets, block, false, true, alignXPercent); 889 } 890 891 private void addAsSeqBlock(Dimension containerSize, Insets insets, BoundableRenderable block, boolean fakeAdd, boolean obeysMargins, int alignXPercent) { 892 int insetsl = insets.left; 893 Collection sr = this.seqRenderables; 894 RLine prevLine = this.currentLine; 895 if(prevLine != null) { 896 if(prevLine.x + prevLine.width > this.maxX) { 897 this.maxX = prevLine.x + prevLine.width; 898 } 899 } 901 int newLineY = prevLine == null ? insets.top : prevLine.y + prevLine.height; 902 int blockX; 903 if(obeysMargins) { 904 int blockOffset = this.fetchLeftOffset(newLineY); 905 blockX = blockOffset + insetsl; 906 if(alignXPercent > 0) { 907 int offset = (this.availContentWidth - blockOffset - block.getWidth()) * alignXPercent / 100; 908 if(offset > 0) { 909 blockX += offset; 910 } 911 } 912 } 913 else { 914 blockX = insetsl; 916 if(alignXPercent > 0) { 917 int offset = (this.availContentWidth - block.getWidth()) * alignXPercent / 100; 918 if(offset > 0) { 919 blockX += offset; 920 } 921 } 922 } 923 block.setOrigin(blockX, newLineY); 924 if(!fakeAdd) { 925 sr.add(block); 926 block.setParent(this); 927 } 928 if(blockX + block.getWidth() > this.maxX) { 929 this.maxX = blockX + block.getWidth(); 930 } 931 newLineY += block.getHeight(); 932 this.checkY(newLineY); 933 int leftOffset = this.fetchLeftOffset(newLineY); 934 int newX = insetsl + leftOffset; 935 int newMaxWidth = containerSize.width - insetsl - insets.right - this.fetchRightOffset(newLineY) - leftOffset; 936 ModelNode lineNode = block.getModelNode().getParentModelNode(); 937 RLine newLine = new RLine(lineNode, this.container, newX, newLineY, newMaxWidth, 0); 938 newLine.setParent(this); 939 sr.add(newLine); 940 this.currentLine = newLine; 941 this.skipParagraphBreakBefore = false; 942 } 943 944 private void layoutText(RenderableContainer container, Dimension containerSize, Insets insets, NodeImpl textNode) { 945 RenderState renderState = textNode.getRenderState(); 946 if(renderState == null) { 947 throw new IllegalStateException ("RenderState is null for node " + textNode + " with parent " + textNode.getParentNode()); 948 } 949 FontMetrics fm = renderState.getFontMetrics(); 950 int descent = fm.getDescent(); 951 int ascentPlusLeading = fm.getAscent() + fm.getLeading(); 952 int wordHeight = fm.getHeight(); 953 int blankWidth = fm.charWidth(' '); 954 int whiteSpace = this.overrideNoWrap ? RenderState.WS_NOWRAP : renderState.getWhiteSpace(); 955 String text = textNode.getNodeValue(); 956 if(whiteSpace != RenderState.WS_PRE) { 957 boolean allowOverflow = whiteSpace == RenderState.WS_NOWRAP; 958 int length = text.length(); 959 StringBuffer word = new StringBuffer (12); 960 for(int i = 0; i < length; i++) { 961 char ch = text.charAt(i); 962 if(Character.isWhitespace(ch)) { 963 int wlen = word.length(); 964 if(wlen > 0) { 965 RWord rword = new RWord(textNode, word.toString(), container, fm, descent, ascentPlusLeading, wordHeight); 966 this.addWordToLine(container, insets, rword, allowOverflow); 967 word.delete(0, wlen); 968 } 969 RLine line = this.currentLine; 970 if(line.width > 0) { 971 RBlank rblank = new RBlank(textNode, fm, container, ascentPlusLeading, blankWidth, wordHeight); 972 line.addBlank(rblank); 973 } 974 for(i++; i < length; i++) { 975 ch = text.charAt(i); 976 if(!Character.isWhitespace(ch)) { 977 word.append(ch); 978 break; 979 } 980 } 981 } 982 else { 983 word.append(ch); 984 } 985 } 986 if(word.length() > 0) { 987 RWord rword = new RWord(textNode, word.toString(), container, fm, descent, ascentPlusLeading, wordHeight); 988 this.addWordToLine(container, insets, rword, allowOverflow); 989 } 990 } 991 else { 992 int length = text.length(); 993 boolean lastCharSlashR = false; 994 StringBuffer line = new StringBuffer (); 995 for(int i = 0; i < length; i++) { 996 char ch = text.charAt(i); 997 switch(ch) { 998 case '\r': 999 lastCharSlashR = true; 1000 break; 1001 case '\n': 1002 int llen = line.length(); 1003 if(llen > 0) { 1004 RWord rword = new RWord(textNode, line.toString(), container, fm, descent, ascentPlusLeading, wordHeight); 1005 this.addWordToLine(container, insets, rword, true); 1006 line.delete(0, line.length()); 1007 } 1008 this.addLine(textNode, insets, this.currentLine); 1009 break; 1010 default: 1011 if(lastCharSlashR) { 1012 line.append('\r'); 1013 lastCharSlashR = false; 1014 } 1015 line.append(ch); 1016 break; 1017 } 1018 } 1019 if(line.length() > 0) { 1020 RWord rword = new RWord(textNode, line.toString(), container, fm, descent, ascentPlusLeading, wordHeight); 1021 this.addWordToLine(container, insets, rword, true); 1022 } 1023 } 1024 } 1025 1026 1032 private void populateZIndexGroups(Collection others, Collection seqRenderables, ArrayList destination) { 1033 this.populateZIndexGroups(others, seqRenderables.iterator(), destination); 1034 } 1035 1036 1042 private void populateZIndexGroups(Collection others, Iterator seqRenderablesIterator, ArrayList destination) { 1043 Iterator i1 = others.iterator(); 1045 Renderable pending = null; 1046 while(i1.hasNext()) { 1047 PositionedRenderable pr = (PositionedRenderable) i1.next(); 1048 Renderable r = pr.renderable; 1049 if(r.getZIndex() >= 0) { 1050 pending = r; 1051 break; 1052 } 1053 destination.add(r); 1054 } 1055 Iterator i2 = seqRenderablesIterator; 1057 while(i2.hasNext()) { 1058 destination.add(i2.next()); 1059 } 1060 1061 if(pending != null) { 1063 destination.add(pending); 1064 while(i1.hasNext()) { 1065 PositionedRenderable pr = (PositionedRenderable) i1.next(); 1066 Renderable r = pr.renderable; 1067 destination.add(r); 1068 } 1069 } 1070 } 1071 1072 public Renderable[] getRenderablesArray() { 1073 SortedSet others = this.positionedRenderables; 1074 int othersSize = others == null ? 0 : others.size(); 1075 if(othersSize == 0) { 1076 return (Renderable[]) this.seqRenderables.toArray(Renderable.EMPTY_ARRAY); 1077 } 1078 else { 1079 ArrayList allRenderables = new ArrayList(); 1080 this.populateZIndexGroups(others, this.seqRenderables, allRenderables); 1081 return (Renderable[]) allRenderables.toArray(Renderable.EMPTY_ARRAY); 1082 } 1083 } 1084 1085 public Iterator getRenderables() { 1086 SortedSet others = this.positionedRenderables; 1087 if(others == null || others.size() == 0) { 1088 return this.seqRenderables.iterator(); 1089 } 1090 else { 1091 ArrayList allRenderables = new ArrayList(); 1092 this.populateZIndexGroups(others, this.seqRenderables, allRenderables); 1093 return allRenderables.iterator(); 1094 } 1095 } 1096 1097 public Iterator getRenderables(Rectangle clipBounds) { 1098 if(!EventQueue.isDispatchThread() && logger.isLoggable(Level.INFO)) { 1099 logger.warning("getRenderables(): Invoked outside GUI dispatch thread."); 1100 } 1101 Renderable[] array = (Renderable[]) this.seqRenderables.toArray(Renderable.EMPTY_ARRAY); 1102 Range range = MarkupUtilities.findRenderables(array, clipBounds, true); 1103 Iterator baseIterator = org.lobobrowser.util.ArrayUtilities.iterator(array, range.offset, range.length); 1104 SortedSet others = this.positionedRenderables; 1105 if(others == null || others.size() == 0) { 1106 return baseIterator; 1107 } 1108 else { 1109 ArrayList matches = new ArrayList(); 1110 Iterator i = others.iterator(); 1112 while(i.hasNext()) { 1113 PositionedRenderable pr = (PositionedRenderable) i.next(); 1114 Object r = pr.renderable; 1115 if(r instanceof BoundableRenderable) { 1116 BoundableRenderable br = (BoundableRenderable) r; 1117 Rectangle rbounds = br.getBounds(); 1118 if(clipBounds.intersects(rbounds)) { 1119 matches.add(pr); 1120 } 1121 } 1122 } 1123 if(matches.size() == 0) { 1124 return baseIterator; 1125 } 1126 else { 1127 ArrayList destination = new ArrayList(); 1128 this.populateZIndexGroups(matches, baseIterator, destination); 1129 return destination.iterator(); 1130 } 1131 } 1132 } 1133 1134 public BoundableRenderable getRenderable(java.awt.Point point) { 1135 Iterator i = this.getRenderables(point); 1136 return i == null ? null : (i.hasNext() ? (BoundableRenderable) i.next() : null); 1137 } 1138 1139 public Iterator getRenderables(java.awt.Point point) { 1140 if(!EventQueue.isDispatchThread() && logger.isLoggable(Level.INFO)) { 1141 logger.warning("getRenderable(): Invoked outside GUI dispatch thread."); 1142 } 1143 Collection result = null; 1144 SortedSet others = this.positionedRenderables; 1145 int size = others == null ? 0 : others.size(); 1146 PositionedRenderable[] otherArray = size == 0 ? null : (PositionedRenderable[]) others.toArray(PositionedRenderable.EMPTY_ARRAY); 1147 int index = 0; 1149 if(size != 0) { 1150 int px = point.x; 1151 int py = point.y; 1152 for(index = size; --index >= 0;) { 1154 PositionedRenderable pr = otherArray[index]; 1155 Renderable r = pr.renderable; 1156 if(r.getZIndex() < 0) { 1157 break; 1158 } 1159 if(r instanceof BoundableRenderable) { 1160 BoundableRenderable br = (BoundableRenderable) r; 1161 Rectangle rbounds = br.getBounds(); 1162 if(rbounds.contains(px, py)) { 1163 if(result == null) { 1164 result = new LinkedList(); 1165 } 1166 result.add(br); 1167 } 1168 } 1169 } 1170 } 1171 Renderable[] array = (Renderable[]) this.seqRenderables.toArray(Renderable.EMPTY_ARRAY); 1173 BoundableRenderable found = MarkupUtilities.findRenderable(array, point, true); 1174 if(found != null) { 1175 if(result == null) { 1176 result = new LinkedList(); 1177 } 1178 result.add(found); 1179 } 1180 if(size != 0) { 1182 int px = point.x; 1183 int py = point.y; 1184 for(; index >= 0; index--) { 1186 PositionedRenderable pr = otherArray[index]; 1187 Renderable r = pr.renderable; 1188 if(r instanceof BoundableRenderable) { 1189 BoundableRenderable br = (BoundableRenderable) r; 1190 Rectangle rbounds = br.getBounds(); 1191 if(rbounds.contains(px, py)) { 1192 if(result == null) { 1193 result = new LinkedList(); 1194 } 1195 result.add(br); 1196 } 1197 } 1198 } 1199 } 1200 return result == null ? null : result.iterator(); 1201 } 1202 1203 private RElement setupNewUIControl(RenderableContainer container, HTMLElementImpl element, UIControl control) { 1204 RElement renderable = new RUIControl(element, control, container, this.frameContext, this.userAgentContext); 1205 element.setUINode((UINode) renderable); 1206 return renderable; 1207 } 1208 1209 private final void addAlignableAsBlock(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, BoundableRenderable renderable) { 1210 boolean regularAdd = false; 1212 String align = markupElement.getAttribute("align"); 1213 if(align != null) { 1214 if("left".equalsIgnoreCase(align)) { 1215 this.addToLeftMargin(renderable, false); 1216 } 1217 else if("right".equalsIgnoreCase(align)) { 1218 this.addToRightMargin(renderable, false); 1219 } 1220 else { 1221 regularAdd = true; 1222 } 1223 } 1224 else { 1225 regularAdd = true; 1226 } 1227 if(regularAdd) { 1228 int alignXPercent = 0; 1229 if(align != null) { 1230 if("center".equalsIgnoreCase(align)) { 1231 alignXPercent = 50; 1232 } 1233 } 1234 this.addAsSeqBlock(containerSize, insets, renderable, alignXPercent); 1235 } 1236 } 1237 1238 private final void layoutHr(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1239 RElement renderable = (RElement) markupElement.getUINode(); 1240 if(renderable == null) { 1241 renderable = this.setupNewUIControl(container, markupElement, new HrControl(markupElement)); 1242 } 1243 renderable.layout(this.availContentWidth, this.availContentHeight, false, false); 1244 this.addAlignableAsBlock(container, containerSize, insets, markupElement, renderable); 1245 } 1246 1247 private final BaseInputControl createInputControl(HTMLBaseInputElement markupElement) { 1248 String type = markupElement.getAttribute("type"); 1249 if(type == null) { 1250 return new InputTextControl(markupElement); 1251 } 1252 type = type.toLowerCase(); 1253 if("text".equals(type) || type.length() == 0) { 1254 return new InputTextControl(markupElement); 1255 } 1256 else if("hidden".equals(type)) { 1257 return null; 1258 } 1259 else if("submit".equals(type)) { 1260 return new InputButtonControl(markupElement); 1261 } 1262 else if("password".equals(type)) { 1263 return new InputPasswordControl(markupElement); 1264 } 1265 else if("radio".equals(type)) { 1266 return new InputRadioControl(markupElement); 1267 } 1268 else if("checkbox".equals(type)) { 1269 return new InputCheckboxControl(markupElement); 1270 } 1271 else if("image".equals(type)) { 1272 return new InputImageControl(markupElement); 1273 } 1274 else if("reset".equals(type)) { 1275 return new InputButtonControl(markupElement); 1276 } 1277 else if("button".equals(type)) { 1278 return new InputButtonControl(markupElement); 1279 } 1280 else if("file".equals(type)) { 1281 return new InputFileControl(markupElement); 1282 } 1283 else { 1284 return null; 1285 } 1286 } 1287 1288 1291 1295 private final int fetchLeftOffset(int newLineY) { 1296 FloatingBounds floatBounds = this.floatBounds; 1297 return floatBounds == null ? 0 : floatBounds.getLeft(newLineY); 1298 } 1299 1300 private final int fetchRightOffset(int newLineY) { 1301 FloatingBounds floatBounds = this.floatBounds; 1302 return floatBounds == null ? 0 : floatBounds.getRight(newLineY); 1303 } 1304 1305 private final void checkLineOverflow() { 1306 RLine line = this.currentLine; 1307 int lineY = line.getY(); 1308 int leftOffset = this.fetchLeftOffset(lineY); 1309 int rightOffset = this.fetchRightOffset(lineY); 1310 Insets insets = this.paddingInsets; 1311 int newX = insets.left + leftOffset; 1312 int newMaxWidth = this.availContentWidth - rightOffset - leftOffset; 1313 if(newX != line.getX() || newMaxWidth != line.getWidth()) { 1314 try { 1315 line.adjustHorizontalBounds(newX, newMaxWidth); 1316 } catch(OverflowException oe) { 1317 Collection renderables = oe.getRenderables(); 1318 Iterator i = renderables.iterator(); 1319 RenderableContainer rc = this.container; 1320 boolean first = true; 1321 while(i.hasNext()) { 1322 Renderable r = (Renderable) i.next(); 1323 if(first) { 1324 first = false; 1325 this.addLine(r.getModelNode(), insets, line); 1326 } 1327 this.addRenderableToLine(rc, insets, r); 1328 } 1329 } 1330 } 1331 } 1332 1333 private static final SizeExceededException SEE = new SizeExceededException(); 1334 1335 private final void checkY(int y) { 1336 if(this.yLimit != -1 && y > this.yLimit) { 1337 throw SEE; 1338 } 1339 } 1340 1341 private final void addToRightMargin(BoundableRenderable brenderable, boolean layout) { 1342 brenderable.setOriginalParent(this); 1343 int availWidth = this.availContentWidth; 1344 int availHeight = this.availContentHeight; 1345 if(layout) { 1346 if(brenderable instanceof RElement) { 1347 ((RElement) brenderable).layout(availWidth, availHeight, false, false); 1348 } 1349 else { 1350 throw new IllegalStateException (); 1351 } 1352 } 1353 int width = brenderable.getWidth(); 1354 int y = this.currentLine.getBounds().y; 1355 int rightOffset = 0; 1356 Insets insets = this.paddingInsets; 1357 int x = insets.left + this.availContentWidth - rightOffset - width; 1358 if(x < 0) { 1359 x = 0; 1360 } 1361 this.scheduleFloatDelayedPair(brenderable, x, y, +1); 1362 } 1363 1364 private final void addToLeftMargin(BoundableRenderable brenderable, boolean layout) { 1365 brenderable.setOriginalParent(this); 1366 int availWidth = this.availContentWidth; 1367 int availHeight = this.availContentHeight; 1368 if(layout) { 1369 if(brenderable instanceof RElement) { 1370 ((RElement) brenderable).layout(availWidth, availHeight, false, false); 1371 } 1372 else { 1373 throw new IllegalStateException (); 1374 } 1375 } 1376 int y = this.currentLine.getBounds().y; 1377 int leftOffset = this.fetchLeftOffset(y); 1378 Insets insets = this.paddingInsets; 1379 int x = insets.left + leftOffset; 1380 this.scheduleFloatDelayedPair(brenderable, x, y, -1); 1381 } 1382 1383 1439 private FloatingBounds floatBounds = null; 1440 1441 private final void positionFloat(DelayedPair pair) { 1442 BoundableRenderable brenderable = pair.child; 1443 Point localPoint = brenderable == this ? new Point(pair.x, pair.y) : this.translateDescendentPoint(brenderable.getOriginalOrCurrentParent(), pair.x, pair.y); 1445 int width = brenderable.getWidth(); 1446 int height = brenderable.getHeight(); 1447 int y = localPoint.y; 1448 int newY = y + height; 1449 this.checkY(newY); 1450 if(newY > this.maxY) { 1451 this.maxY = newY; 1452 } 1453 int alignment = pair.alignment; 1454 FloatingBounds prevFloatBounds = this.floatBounds; 1455 int x; 1456 Insets paddingInsets = this.paddingInsets; 1457 int left = paddingInsets == null ? 0 : paddingInsets.left; 1458 if(prevFloatBounds != null) { 1459 x = alignment > 0 ? left + this.availContentWidth - prevFloatBounds.getRight(y) - width : left + prevFloatBounds.getLeft(y); 1460 } 1461 else { 1462 x = alignment > 0 ? left + this.availContentWidth - width : left; 1463 } 1464 if(x < left) { 1465 x = left; 1466 } 1467 int effectiveWidth = width; 1468 if(alignment > 0) { 1469 if(localPoint.x < x) { 1470 effectiveWidth += (x - localPoint.x); 1471 x = localPoint.x; 1472 } 1473 } 1474 else { 1475 if(localPoint.x > x) { 1476 effectiveWidth += (localPoint.x - x); 1477 x = localPoint.x; 1478 } 1479 } 1480 FloatingViewportBounds newFloatBounds = new FloatingViewportBounds(prevFloatBounds, alignment, y, effectiveWidth, height); 1481 this.floatBounds = newFloatBounds; 1482 brenderable.setOrigin(x, y); 1483 if(x + width > this.maxX) { 1484 this.maxX = x + width; 1485 } 1486 } 1487 1488 private final void addFloat(DelayedPair pair) { 1489 BoundableRenderable brenderable = pair.child; 1490 this.addPositionedRenderable(brenderable, true); 1491 } 1492 1493 1494 1501 private void scheduleAbsDelayedPair(BoundableRenderable renderable, int x, int y, int alignment) { 1502 RenderableContainer container = this.container; 1505 for(;;) { 1506 if(container instanceof Renderable) { 1507 Object node = ((Renderable) container).getModelNode(); 1508 if(node instanceof HTMLElementImpl) { 1509 HTMLElementImpl element = (HTMLElementImpl) node; 1510 CSS2PropertiesImpl style = element.getCurrentStyle(); 1511 if(style != null) { 1512 String position = style.getPosition(); 1513 if(position != null && (position.equalsIgnoreCase("absolute") || position.equalsIgnoreCase("fixed") || position.equalsIgnoreCase("relative"))) { 1514 break; 1515 } 1516 } 1517 RenderableContainer newContainer = container.getParentContainer(); 1518 if(newContainer == null) { 1519 break; 1520 } 1521 container = newContainer; 1522 } 1523 else { 1524 break; 1525 } 1526 } 1527 else { 1528 break; 1529 } 1530 } 1531 DelayedPair pair = new DelayedPair(alignment, container, renderable, x, y); 1532 this.container.addDelayedPair(pair); 1533 } 1534 1535 private void scheduleFloatDelayedPair(BoundableRenderable renderable, int x, int y, int alignment) { 1536 RenderableContainer targetContainer = this.container; 1539 RBlockViewport targetViewport = this; 1540 for(;;) { 1541 if(targetViewport.isPositionedElsewhere()) { 1542 break; 1543 } 1544 if(!(targetContainer instanceof RBlock)) { 1545 break; 1546 } 1547 RBlock rblock = (RBlock) targetContainer; 1548 Object parent = rblock.getOriginalOrCurrentParent(); 1549 if(!(parent instanceof RBlockViewport)) { 1550 break; 1551 } 1552 targetViewport = (RBlockViewport) parent; 1553 targetContainer = targetViewport.container; 1554 } 1555 DelayedPair pair = new DelayedPair(alignment, targetContainer, renderable, x, y); 1556 this.container.addDelayedPair(pair); 1557 } 1558 1559 void importNonFloat(DelayedPair pair) { 1560 BoundableRenderable r = pair.child; 1561 r.setOrigin(pair.x, pair.y); 1562 this.addPositionedRenderable(r, false); 1563 } 1566 1567 1574 1585 1596 1601 private final void addPositionedRenderable(BoundableRenderable renderable, boolean verticalAlignable) { 1602 SortedSet others = this.positionedRenderables; 1604 if(others == null) { 1605 others = new TreeSet(new ZIndexComparator()); 1606 this.positionedRenderables = others; 1607 } 1608 others.add(new PositionedRenderable(renderable, verticalAlignable, this.otherOrdinal++)); 1609 renderable.setParent(this); 1610 if(renderable instanceof RUIControl) { 1611 this.container.add(((RUIControl) renderable).widget.getComponent()); 1612 } 1613 } 1614 1615 public int getFirstLineHeight() { 1616 ArrayList renderables = this.seqRenderables; 1617 int size = renderables.size(); 1618 if(size == 0) { 1619 return 0; 1620 } 1621 BoundableRenderable br = (BoundableRenderable) renderables.get(0); 1622 return br.getHeight(); 1623 } 1624 1625 public int getFirstBaselineOffset() { 1626 ArrayList renderables = this.seqRenderables; 1627 Iterator i = renderables.iterator(); 1628 while(i.hasNext()) { 1629 Object r = i.next(); 1630 if(r instanceof RLine) { 1631 return ((RLine) r).getBaselineOffset(); 1632 } 1633 } 1634 return 0; 1635 } 1636 1637 1639 public RenderableSpot getLowestRenderableSpot(int x, int y) { 1640 BoundableRenderable br = this.getRenderable(new Point(x, y)); 1641 if(br != null) { 1642 return br.getLowestRenderableSpot(x - br.getX(), y - br.getY()); 1643 } 1644 else { 1645 return new RenderableSpot(this, x, y); 1646 } 1647 } 1648 1649 1652 public boolean onMouseClick(MouseEvent event, int x, int y) { 1653 Iterator i = this.getRenderables(new Point(x, y)); 1654 if(i != null) { 1655 while(i.hasNext()) { 1656 BoundableRenderable br = (BoundableRenderable) i.next(); 1657 if(br != null) { 1658 Rectangle bounds = br.getBounds(); 1659 if(!br.onMouseClick(event, x - bounds.x, y - bounds.y)) { 1660 return false; 1661 } 1662 } 1663 } 1664 } 1665 return true; 1666 } 1667 1668 public boolean onDoubleClick(MouseEvent event, int x, int y) { 1669 Iterator i = this.getRenderables(new Point(x, y)); 1670 if(i != null) { 1671 while(i.hasNext()) { 1672 BoundableRenderable br = (BoundableRenderable) i.next(); 1673 if(br != null) { 1674 Rectangle bounds = br.getBounds(); 1675 if(!br.onDoubleClick(event, x - bounds.x, y - bounds.y)) { 1676 return false; 1677 } 1678 } 1679 } 1680 } 1681 return true; 1682 } 1683 1684 1687 public boolean onMouseDisarmed(MouseEvent event) { 1688 BoundableRenderable br = this.armedRenderable; 1689 if(br != null) { 1690 try { 1691 return br.onMouseDisarmed(event); 1692 } finally { 1693 this.armedRenderable = null; 1694 } 1695 } 1696 else { 1697 return true; 1698 } 1699 } 1700 1701 private BoundableRenderable armedRenderable; 1702 1703 1706 public boolean onMousePressed(MouseEvent event, int x, int y) { 1707 Iterator i = this.getRenderables(new Point(x, y)); 1708 if(i != null) { 1709 while(i.hasNext()) { 1710 BoundableRenderable br = (BoundableRenderable) i.next(); 1711 if(br != null) { 1712 Rectangle bounds = br.getBounds(); 1713 if(!br.onMousePressed(event, x - bounds.x, y - bounds.y)) { 1714 this.armedRenderable = br; 1715 return false; 1716 } 1717 } 1718 } 1719 } 1720 return true; 1721 } 1722 1723 1726 public boolean onMouseReleased(MouseEvent event, int x, int y) { 1727 Iterator i = this.getRenderables(new Point(x, y)); 1728 if(i != null) { 1729 while(i.hasNext()) { 1730 BoundableRenderable br = (BoundableRenderable) i.next(); 1731 if(br != null) { 1732 Rectangle bounds = br.getBounds(); 1733 if(!br.onMouseReleased(event, x - bounds.x, y - bounds.y)) { 1734 BoundableRenderable oldArmedRenderable = this.armedRenderable; 1735 if(oldArmedRenderable != null && br != oldArmedRenderable) { 1736 oldArmedRenderable.onMouseDisarmed(event); 1737 this.armedRenderable = null; 1738 } 1739 return false; 1740 } 1741 } 1742 } 1743 } 1744 BoundableRenderable oldArmedRenderable = this.armedRenderable; 1745 if(oldArmedRenderable != null) { 1746 oldArmedRenderable.onMouseDisarmed(event); 1747 this.armedRenderable = null; 1748 } 1749 return true; 1750 } 1751 1752 public void paint(Graphics g) { 1753 Rectangle clipBounds = g.getClipBounds(); 1754 Iterator i = this.getRenderables(clipBounds); 1755 int renderableCount = 0; 1756 while(i.hasNext()) { 1757 renderableCount++; 1758 Object robj = i.next(); 1759 1760 1763 if(robj instanceof BoundableRenderable) { 1774 BoundableRenderable renderable = (BoundableRenderable) robj; 1775 renderable.paintTranslated(g); 1776 } 1778 else { 1779 ((Renderable) robj).paint(g); 1780 } 1781 } 1782 } 1783 1784 1786 private static class NopLayout implements MarkupLayout { 1787 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1788 } 1789 } 1790 1791 private static class NoScriptLayout implements MarkupLayout { 1792 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1793 UserAgentContext ucontext = bodyLayout.userAgentContext; 1794 if(!ucontext.isScriptingEnabled()) { 1795 bodyLayout.layoutMarkup(container, containerSize, insets, markupElement); 1796 } 1797 else { 1798 } 1800 } 1801 } 1802 1803 private static class ChildrenLayout implements MarkupLayout { 1804 1807 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1808 bodyLayout.layoutChildren(container, containerSize, insets, markupElement); 1809 } 1810 } 1811 1812 private static class HLayout extends CommonLayout { 1813 1814 public HLayout(int fontSize) { 1815 super(DISPLAY_BLOCK); 1816 } 1817 1818 1821 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1822 if(!bodyLayout.skipParagraphBreakBefore) { 1823 RLine currentLine = bodyLayout.currentLine; 1824 if(currentLine.width == 0) { 1825 bodyLayout.addLineBreak(container, containerSize, insets, markupElement); 1826 } 1827 else { 1828 bodyLayout.addParagraphBreak(container, containerSize, insets, markupElement); 1829 } 1830 bodyLayout.skipParagraphBreakBefore = true; 1831 } 1832 super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement); 1833 if(markupElement.hasChildNodes()) { 1834 bodyLayout.addLineBreak(container, containerSize, insets, markupElement); 1835 bodyLayout.skipParagraphBreakBefore = true; 1836 } 1837 } 1838 } 1839 1840 private static class PLayout extends CommonLayout { 1841 public PLayout() { 1842 super(DISPLAY_BLOCK); 1843 } 1844 1845 1848 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1849 if(!bodyLayout.skipParagraphBreakBefore) { 1850 RLine currentLine = bodyLayout.currentLine; 1851 if(currentLine.width == 0) { 1852 bodyLayout.addLineBreak(container, containerSize, insets, markupElement); 1853 } 1854 else { 1855 bodyLayout.addParagraphBreak(container, containerSize, insets, markupElement); 1856 } 1857 bodyLayout.skipParagraphBreakBefore = true; 1858 } 1859 super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement); 1860 if(markupElement.hasChildNodes()) { 1861 bodyLayout.addLineBreak(container, containerSize, insets, markupElement); 1862 bodyLayout.skipParagraphBreakBefore = true; 1863 } 1864 } 1865 } 1866 1867 private static class ListItemLayout extends CommonLayout { 1868 public ListItemLayout() { 1869 super(DISPLAY_LIST_ITEM); 1870 } 1871 } 1872 1873 private static class BrLayout implements MarkupLayout { 1874 1877 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1878 bodyLayout.addLineBreak(container, containerSize, insets, markupElement); 1879 } 1880 } 1881 1882 private static class HrLayout implements MarkupLayout { 1883 1886 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1887 bodyLayout.layoutHr(container, containerSize, insets, markupElement); 1888 } 1889 } 1890 1891 private static class TableLayout extends CommonLayout { 1892 public TableLayout() { 1893 super(DISPLAY_TABLE); 1894 } 1895 } 1896 1897 private static class CommonBlockLayout extends CommonLayout { 1898 public CommonBlockLayout() { 1899 super(DISPLAY_BLOCK); 1900 } 1901 } 1902 1903 1905 private static class DivLayout extends CommonLayout { 1906 public DivLayout() { 1907 super(DISPLAY_BLOCK); 1908 } 1909 } 1910 1911 private static class BlockQuoteLayout extends CommonLayout { 1912 public java.awt.Insets getDefaultMarginInsets() { 1913 return new Insets(0, 36, 0, 0); 1914 } 1915 1916 public BlockQuoteLayout() { 1917 super(DISPLAY_BLOCK); 1918 } 1919 } 1920 1921 private static class SpanLayout extends CommonLayout { 1922 public SpanLayout() { 1923 super(DISPLAY_INLINE); 1924 } 1925 } 1926 1927 private static class EmLayout extends CommonLayout { 1928 public EmLayout() { 1929 super(DISPLAY_INLINE); 1930 } 1931 1932 1935 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1936 super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement); 1937 } 1938 } 1939 1940 private static class ULayout extends CommonLayout { 1941 public ULayout() { 1942 super(DISPLAY_INLINE); 1943 } 1944 1945 1948 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1949 super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement); 1950 } 1951 } 1952 1953 private static class StrikeLayout extends CommonLayout { 1954 public StrikeLayout() { 1955 super(DISPLAY_INLINE); 1956 } 1957 } 1958 1959 private static class StrongLayout extends CommonLayout { 1960 public StrongLayout() { 1961 super(DISPLAY_INLINE); 1962 } 1963 } 1964 1965 private static class AnchorLayout extends CommonLayout { 1966 public AnchorLayout() { 1967 super(DISPLAY_INLINE); 1968 } 1969 } 1970 1971 private static class ObjectLayout extends CommonWidgetLayout { 1972 private boolean tryToRenderContent; 1973 1974 1978 public ObjectLayout(boolean tryToRenderContent, boolean usesAlignAttribute) { 1979 super(ADD_INLINE, usesAlignAttribute); 1980 this.tryToRenderContent = tryToRenderContent; 1981 } 1982 1983 1988 private final ThreadLocal htmlObject = new ThreadLocal (); 1989 1990 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 1991 HtmlObject ho = bodyLayout.rendererContext.getHtmlObject(markupElement); 1992 if(ho == null && this.tryToRenderContent) { 1993 bodyLayout.layoutMarkup(container, containerSize, insets, markupElement); 1995 } 1996 else if (ho != null) { 1997 this.htmlObject.set(ho); 1998 super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement); 1999 } 2000 } 2001 2002 protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) { 2003 HtmlObject ho = (HtmlObject) this.htmlObject.get(); 2004 UIControl uiControl = new UIControlWrapper(ho); 2005 RUIControl ruiControl = new RUIControl(markupElement, uiControl, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext); 2006 return ruiControl; 2007 } 2008 } 2009 2010 private static class ImgLayout extends CommonWidgetLayout { 2011 public ImgLayout() { 2012 super(ADD_INLINE, true); 2013 } 2014 2015 protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) { 2016 UIControl control = new ImgControl((HTMLImageElementImpl) markupElement); 2017 return new RUIControl(markupElement, control, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext); 2018 } 2019 } 2020 2021 private static class InputLayout2 extends CommonWidgetLayout { 2022 public InputLayout2() { 2023 super(ADD_INLINE, true); 2024 } 2025 2026 protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) { 2027 HTMLBaseInputElement bie = (HTMLBaseInputElement) markupElement; 2028 BaseInputControl uiControl = bodyLayout.createInputControl(bie); 2029 if(uiControl == null) { 2030 return null; 2031 } 2032 bie.setInputContext(uiControl); 2033 return new RUIControl(markupElement, uiControl, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext); 2034 } 2035 } 2036 2037 private static class SelectLayout extends CommonWidgetLayout { 2038 public SelectLayout() { 2039 super(ADD_INLINE, true); 2040 } 2041 2042 protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) { 2043 HTMLBaseInputElement bie = (HTMLBaseInputElement) markupElement; 2044 BaseInputControl uiControl = new InputSelectControl(bie); 2045 bie.setInputContext(uiControl); 2046 return new RUIControl(markupElement, uiControl, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext); 2047 } 2048 } 2049 2050 private static class TextAreaLayout2 extends CommonWidgetLayout { 2051 public TextAreaLayout2() { 2052 super(ADD_INLINE, true); 2053 } 2054 2055 protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) { 2056 HTMLBaseInputElement bie = (HTMLBaseInputElement) markupElement; 2057 BaseInputControl control = new InputTextAreaControl(bie); 2058 bie.setInputContext(control); 2059 return new RUIControl(markupElement, control, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext); 2060 } 2061 } 2062 2063 private static class IFrameLayout extends CommonWidgetLayout { 2064 public IFrameLayout() { 2065 super(ADD_INLINE, true); 2066 } 2067 2068 protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) { 2069 BrowserFrame frame = bodyLayout.rendererContext.createBrowserFrame(); 2070 ((HTMLIFrameElementImpl) markupElement).setBrowserFrame(frame); 2071 UIControl control = new BrowserFrameUIControl(markupElement, frame); 2072 return new RUIControl(markupElement, control, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext); 2073 } 2074 } 2075 2076 2078 2082 private static abstract class CommonWidgetLayout implements MarkupLayout { 2083 protected static final int ADD_INLINE = 0; 2084 protected static final int ADD_AS_BLOCK = 1; 2085 private final int method; 2086 private final boolean useAlignAttribute; 2087 2088 public CommonWidgetLayout(int method, boolean usesAlignAttribute) { 2089 this.method = method; 2090 this.useAlignAttribute = usesAlignAttribute; 2091 } 2092 2093 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 2094 CSS2PropertiesImpl style = markupElement.getCurrentStyle(); 2095 if(style != null) { 2096 String display = style.getDisplay(); 2097 if(display != null && "none".equalsIgnoreCase(display)) { 2098 return; 2099 } 2100 } 2101 UINode node = markupElement.getUINode(); 2102 RElement renderable = null; 2103 if(node == null) { 2104 renderable = this.createRenderable(bodyLayout, markupElement); 2105 if(renderable == null) { 2106 if(logger.isLoggable(Level.INFO)) { 2107 logger.info("layoutMarkup(): Don't know how to render " + markupElement + "."); 2108 } 2109 return; 2110 } 2111 markupElement.setUINode((UINode) renderable); 2112 } 2113 else { 2114 renderable = (RElement) node; 2115 } 2116 int availWidth = bodyLayout.availContentWidth; 2117 int heightAvailToRenderable = bodyLayout.availContentHeight; 2118 renderable.layout(availWidth, heightAvailToRenderable, false, false); 2119 switch(this.method) { 2120 case ADD_INLINE: 2121 bodyLayout.addRenderableToLineCheckStyle(container, containerSize, insets, renderable, markupElement, this.useAlignAttribute); 2122 break; 2123 case ADD_AS_BLOCK: 2124 bodyLayout.addAsSeqBlockCheckStyle(containerSize, insets, renderable, markupElement, this.useAlignAttribute); 2125 break; 2126 } 2127 } 2128 2129 protected abstract RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement); 2130 } 2131 2132 private static abstract class CommonLayout implements MarkupLayout { 2133 protected static final int DISPLAY_NONE = 0; 2134 protected static final int DISPLAY_INLINE = 1; 2135 protected static final int DISPLAY_BLOCK = 2; 2136 protected static final int DISPLAY_LIST_ITEM = 3; 2137 protected static final int DISPLAY_TABLE_ROW = 4; 2138 protected static final int DISPLAY_TABLE_CELL = 5; 2139 protected static final int DISPLAY_TABLE = 6; 2140 2141 private final int display; 2142 2143 public CommonLayout(int defaultDisplay) { 2144 this.display = defaultDisplay; 2145 } 2146 2147 2151 public java.awt.Insets getDefaultMarginInsets() { 2152 return null; 2153 } 2154 2155 public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) { 2156 RenderState rs = markupElement.getRenderState(); 2157 int display = rs == null ? this.display : rs.getDisplay(); 2158 switch(display) { 2159 case DISPLAY_NONE: 2160 break; 2162 case DISPLAY_BLOCK: 2163 bodyLayout.layoutRBlock(container, containerSize, insets, markupElement, this.getDefaultMarginInsets()); 2164 break; 2165 case DISPLAY_LIST_ITEM: 2166 String tagName = markupElement.getTagName(); 2167 if("UL".equalsIgnoreCase(tagName) || "OL".equalsIgnoreCase(tagName)) { 2168 bodyLayout.layoutList(container, containerSize, insets, markupElement); 2169 } 2170 else { 2171 bodyLayout.layoutListItem(container, containerSize, insets, markupElement); 2172 } 2173 break; 2174 case DISPLAY_TABLE: 2175 bodyLayout.layoutRTable(container, containerSize, insets, markupElement); 2176 break; 2177 default: 2178 bodyLayout.layoutMarkup(container, containerSize, insets, markupElement); 2180 break; 2181 } 2183 } 2184 } 2185 2186 public String toString() { 2187 return "RBlockViewport[node=" + this.modelNode + "]"; 2188 } 2189} 2190 | Popular Tags |