https://bugs.webkit.org/show_bug.cgi?id=57916
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Apr 2011 18:20:52 +0000 (18:20 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Apr 2011 18:20:52 +0000 (18:20 +0000)
Reviewed by Dan Bernstein.

Implement an optimization to the line box tree to cull out most of the intermediate
line boxes that can occur between the root line box and the leaves of the tree (images
and text).

Source/WebCore:

RenderInlines now have a boolean member, m_alwaysCreateLineBoxes,
that starts off as false. Only if it gets flipped to true will there be any line boxes
created for that RenderInline.

* page/FocusController.cpp:
(WebCore::FocusController::advanceFocusDirectionally):
Adjust the ordering of updateLayout calls to make sure rects aren't queried unless layout
is up to date.

* page/SpatialNavigation.cpp:
(WebCore::hasOffscreenRect):
(WebCore::nodeRectInAbsoluteCoordinates):
Add asserts in spatial navigation code to catch any future bad queries that might be made
for rectangles without layout being up to date.

* platform/graphics/FloatRect.cpp:
(WebCore::FloatRect::uniteIfNonZero):
* platform/graphics/FloatRect.h:
* platform/graphics/IntRect.cpp:
(WebCore::IntRect::uniteIfNonZero):
* platform/graphics/IntRect.h:
Add a new unite function that is useful for the render tree to FloatRect and IntRect.  This
version allows rect unites to happen if either width or height is nonzero.

* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::addNodeToRectBasedTestResult):
Make sure rect-based hit testing properly adds in culled inline ancestors to the set of nodes
if content inside those inlines is hit.

* rendering/InlineBox.h:
(WebCore::InlineBox::logicalFrameRect):
Fix a bug in this function for obtaining the logical frame rect of an inline box.

* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::addToLine):
addToLine now also checks line gap in the line box tree optimization checks.

(WebCore::InlineFlowBox::addTextBoxVisualOverflow):
(WebCore::InlineFlowBox::computeOverflow):
* rendering/InlineFlowBox.h:
Rewritten to add the text box overflow to the text box itself.

 * rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::destroy):
Destroy has been changed to call a helper function to remove and destroy the line boxes that
is now called from one additional spot.

(WebCore::InlineTextBox::logicalOverflowRect):
(WebCore::InlineTextBox::setLogicalOverflowRect):
Text boxes now cache their own overflow in a global hash table.

(WebCore::InlineTextBox::baselinePosition):
(WebCore::InlineTextBox::lineHeight):
Changed to not assume that the parent line box's renderer is the RenderText's immediate
parent, since intermediate line boxes may have been culled.

(WebCore::InlineTextBox::paint):
Paint now properly checks only the text box overflow instead of the parent line box's overflow.

* rendering/InlineTextBox.h:
(WebCore::InlineTextBox::logicalTopVisualOverflow):
(WebCore::InlineTextBox::logicalBottomVisualOverflow):
(WebCore::InlineTextBox::logicalLeftVisualOverflow):
(WebCore::InlineTextBox::logicalRightVisualOverflow):
New accessors to obtain overflow for inline text boxes.

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::updateFirstLetter):
updateFirstLetter now removes text boxes from the line box tree before it destroys them, since those
text boxes may not have anything in between them and the block that contains the inline first letter
container.

* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlock::createLineBoxes):
The culling optimization is done here.  Only if the RenderInline says that boxes are allowed will they
be created.

(WebCore::RenderBlock::layoutInlineChildren):
The state of the RenderInline is updated here, in case it is discovered that line boxes are now needed.
This is done before any lines are built.

* rendering/RenderInline.cpp:
(WebCore::RenderInline::RenderInline):
The new m_alwaysCreateLineBoxes flag has been added to the constructor.

(WebCore::RenderInline::styleDidChange):
An initial update of the m_alwaysCreateLineBoxes happens here for things that can be checked immediately
(like having a layer, borders, padding, margins or backgrounds).  Some checks that depend on examining
the RenderInline's parent (including first line styles) happen later in layoutInlineChildren.

(WebCore::RenderInline::updateAlwaysCreateLineBoxes):
The function called by layoutInlineChildren to check parent and child style differences (e.g., font,
vertical alignment, line height, etc.).

(WebCore::RenderInline::absoluteRects):
(WebCore::RenderInline::culledInlineAbsoluteRects):
absoluteRects calls culledInlineAbsoluteRects when m_alwaysCreateLineBoxes is false.

(WebCore::RenderInline::absoluteQuads):
(WebCore::RenderInline::culledInlineAbsoluteQuads):
absoluteQuads calls culledInlineAbsoluteQuads when m_alwaysCreateLineBoxes is false.

(WebCore::RenderInline::offsetLeft):
(WebCore::RenderInline::offsetTop):
offsetLeft and offsetTop now check descendant renderers when m_alwaysCreateLineBoxes is false.

(WebCore::RenderInline::linesBoundingBox):
(WebCore::RenderInline::culledInlineBoundingBox):
lineBoundingBox calls culledInlineBoundingBox when m_alwaysCreateLineBoxes is false.

(WebCore::RenderInline::culledInlineFirstLineBox):
(WebCore::RenderInline::culledInlineLastLineBox):
Helpers that return the first and last line box descendants. Used by firstLineBoxIncludingCulling and
lastLineBoxIncludingCulling (which are in turn called by offsetLeft and offsetTop).

(WebCore::RenderInline::culledInlineVisualOverflowBoundingBox):
(WebCore::RenderInline::linesVisualOverflowBoundingBox):
linesVisualOverflowBoundingBox calls culledInlineVisualOverflowBoundingBox when m_alwaysCreateLineBoxes is false.

(WebCore::RenderInline::clippedOverflowRectForRepaint):
The initial bailout check is now done using firstLineBoxIncludingCulling instead of just firstLineBox.

(WebCore::RenderInline::dirtyLineBoxes):
dirtyLineBoxes now crawls into descendants to figure out which root lines to dirty when
m_alwaysCreateLineBoxes is false.

(WebCore::RenderInline::createAndAppendInlineFlowBox):
Clear the m_alwaysCreateLineBoxes if a box gets added anyway. This happens for leaf inline flows and also
when line-box-contain is set to an unusual value.

(WebCore::RenderInline::addFocusRingRects):
Used culledInlineAbsoluteRects in place of the line box walk when m_alwaysCreateLineBoxes is false.

* rendering/RenderInline.h:
(WebCore::RenderInline::firstLineBoxIncludingCulling):
(WebCore::RenderInline::lastLineBoxIncludingCulling):
Helpers used in a few places (like offsetLeft and offsetTop), mostly in places where the existence of a box
is all that needs checking.

(WebCore::RenderInline::alwaysCreateLineBoxes):
(WebCore::RenderInline::setAlwaysCreateLineBoxes):
Functions for getting and setting the m_alwaysCreateLineBoxes flag.

* rendering/RenderLineBoxList.cpp:
(WebCore::RenderLineBoxList::dirtyLinesFromChangedChild):
Modified to use firstLineBoxIncludingCulling and lastLineBoxIncludingCulling to ensure the right set of
lines get dirtied.

* rendering/RenderText.cpp:
(WebCore::RenderText::removeAndDestroyTextBoxes):
New helper invoked by destroy and also from updateFirstLetter.

(WebCore::RenderText::destroy):
Changed to call removeAndDestroyTextBoxes.

(WebCore::RenderText::absoluteRects):
Fixed to be properly physical instead of logical.

(WebCore::RenderText::linesVisualOverflowBoundingBox):
New implementation for RenderText that gives the bounding box of the text boxes including overflow from
shadows, glyphs, text-stroke, etc.  Used by RenderInline::culledInlineVisualOverflowBoundingBox.

* rendering/RenderText.h:
* rendering/svg/RenderSVGInline.cpp:
(WebCore::RenderSVGInline::RenderSVGInline):
RenderSVGInline always sets m_alwaysCreateLineBoxes to true so that SVG is unaffected by this optimization.

* rendering/svg/SVGRootInlineBox.cpp:
(WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes):
(WebCore::SVGRootInlineBox::layoutChildBoxes):
Move the isInlineFlowBox asserts to after the generated content skips, since the generated content boxes are
now InlineTextBoxes (the enclosing InlineFlowBoxes got culled).

LayoutTests:

RenderInlines now have a boolean member, m_alwaysCreateLineBoxes,
that starts off as false. Only if it gets flipped to true will there be any line boxes
created for that RenderInline.

* platform/mac/fast/blockflow/text-orientation-basic-expected.txt:
* platform/mac/fast/text/capitalize-empty-generated-string-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@83075 268f45cc-cd09-0410-ab3c-d52691b4dbfc

26 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/fast/blockflow/text-orientation-basic-expected.txt
LayoutTests/platform/mac/fast/text/capitalize-empty-generated-string-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/page/FocusController.cpp
Source/WebCore/page/SpatialNavigation.cpp
Source/WebCore/platform/graphics/FloatRect.cpp
Source/WebCore/platform/graphics/FloatRect.h
Source/WebCore/platform/graphics/FontMetrics.h
Source/WebCore/platform/graphics/IntRect.cpp
Source/WebCore/platform/graphics/IntRect.h
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/InlineBox.h
Source/WebCore/rendering/InlineFlowBox.cpp
Source/WebCore/rendering/InlineFlowBox.h
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/InlineTextBox.h
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlockLineLayout.cpp
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderInline.h
Source/WebCore/rendering/RenderLineBoxList.cpp
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/RenderText.h
Source/WebCore/rendering/svg/RenderSVGInline.cpp
Source/WebCore/rendering/svg/SVGRootInlineBox.cpp

index 42e4078..0b3a8da 100644 (file)
@@ -1,3 +1,20 @@
+2011-04-06  David Hyatt  <hyatt@apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        https://bugs.webkit.org/show_bug.cgi?id=57916
+        
+        Implement an optimization to the line box tree to cull out most of the intermediate
+        line boxes that can occur between the root line box and the leaves of the tree (images
+        and text).
+
+        RenderInlines now have a boolean member, m_alwaysCreateLineBoxes,
+        that starts off as false. Only if it gets flipped to true will there be any line boxes
+        created for that RenderInline.
+
+        * platform/mac/fast/blockflow/text-orientation-basic-expected.txt:
+        * platform/mac/fast/text/capitalize-empty-generated-string-expected.txt:
+
 2011-04-06  MORITA Hajime  <morrita@google.com>
 
         Unreviewed expectations udpate for gtk port that follows r83065.
index ca6dbe8..ff11234 100644 (file)
@@ -26,7 +26,7 @@ layer at (0,0) size 785x704
           RenderInline {SPAN} at (0,0) size 40x254
             RenderText {#text} at (44,1) size 40x254
               text run at (44,1) width 254: "Hello world"
-          RenderBR {BR} at (64,254) size 0x1
+          RenderBR {BR} at (52,254) size 0x1
           RenderInline {SPAN} at (0,0) size 36x199
             RenderText {#text} at (94,1) size 36x199
               text run at (94,1) width 199: "Hello world"
@@ -44,7 +44,7 @@ layer at (0,0) size 785x704
           RenderInline {SPAN} at (0,0) size 40x255
             RenderText {#text} at (44,1) size 40x255
               text run at (44,1) width 255: "Hello world"
-          RenderBR {BR} at (64,256) size 0x0
+          RenderBR {BR} at (52,256) size 0x0
           RenderInline {SPAN} at (0,0) size 36x198
             RenderText {#text} at (94,1) size 36x198
               text run at (94,1) width 198: "Hello world"
index 22e22e6..31811d5 100644 (file)
@@ -22,7 +22,7 @@ layer at (0,0) size 800x600
           RenderText {#text} at (0,0) size 46x18
             text run at (0,0) width 46: "Lorem "
           RenderInline {SPAN} at (0,0) size 39x18
-            RenderInline (generated) at (0,0) size 0x18
+            RenderInline (generated) at (0,0) size 0x0
               RenderText at (0,0) size 0x0
             RenderText {#text} at (46,0) size 39x18
               text run at (46,0) width 39: "Ipsum"
@@ -38,7 +38,7 @@ layer at (0,0) size 800x600
           RenderText {#text} at (0,0) size 23x18
             text run at (0,0) width 23: "Lor"
           RenderInline {SPAN} at (0,0) size 62x18
-            RenderInline (generated) at (0,0) size 0x18
+            RenderInline (generated) at (0,0) size 0x0
               RenderText at (0,0) size 0x0
             RenderText {#text} at (23,0) size 62x18
               text run at (23,0) width 62: "em Ipsum"
index cb3128c..64f3044 100644 (file)
@@ -1,3 +1,186 @@
+2011-04-06  David Hyatt  <hyatt@apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        https://bugs.webkit.org/show_bug.cgi?id=57916
+        
+        Implement an optimization to the line box tree to cull out most of the intermediate
+        line boxes that can occur between the root line box and the leaves of the tree (images
+        and text).
+
+        RenderInlines now have a boolean member, m_alwaysCreateLineBoxes,
+        that starts off as false. Only if it gets flipped to true will there be any line boxes
+        created for that RenderInline.
+        
+        * page/FocusController.cpp:
+        (WebCore::FocusController::advanceFocusDirectionally):
+        Adjust the ordering of updateLayout calls to make sure rects aren't queried unless layout
+        is up to date.
+
+        * page/SpatialNavigation.cpp:
+        (WebCore::hasOffscreenRect):
+        (WebCore::nodeRectInAbsoluteCoordinates):
+        Add asserts in spatial navigation code to catch any future bad queries that might be made
+        for rectangles without layout being up to date.
+
+        * platform/graphics/FloatRect.cpp:
+        (WebCore::FloatRect::uniteIfNonZero):
+        * platform/graphics/FloatRect.h:
+        * platform/graphics/IntRect.cpp:
+        (WebCore::IntRect::uniteIfNonZero):
+        * platform/graphics/IntRect.h:
+        Add a new unite function that is useful for the render tree to FloatRect and IntRect.  This
+        version allows rect unites to happen if either width or height is nonzero.
+
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::addNodeToRectBasedTestResult):
+        Make sure rect-based hit testing properly adds in culled inline ancestors to the set of nodes
+        if content inside those inlines is hit.
+
+        * rendering/InlineBox.h:
+        (WebCore::InlineBox::logicalFrameRect):
+        Fix a bug in this function for obtaining the logical frame rect of an inline box.
+
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::addToLine):
+        addToLine now also checks line gap in the line box tree optimization checks.
+    
+        (WebCore::InlineFlowBox::addTextBoxVisualOverflow):
+        (WebCore::InlineFlowBox::computeOverflow):
+        * rendering/InlineFlowBox.h:
+        Rewritten to add the text box overflow to the text box itself.
+
+         * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::destroy):
+        Destroy has been changed to call a helper function to remove and destroy the line boxes that
+        is now called from one additional spot.
+
+        (WebCore::InlineTextBox::logicalOverflowRect):
+        (WebCore::InlineTextBox::setLogicalOverflowRect):
+        Text boxes now cache their own overflow in a global hash table.
+
+        (WebCore::InlineTextBox::baselinePosition):
+        (WebCore::InlineTextBox::lineHeight):
+        Changed to not assume that the parent line box's renderer is the RenderText's immediate
+        parent, since intermediate line boxes may have been culled.
+
+        (WebCore::InlineTextBox::paint):
+        Paint now properly checks only the text box overflow instead of the parent line box's overflow.
+
+        * rendering/InlineTextBox.h:
+        (WebCore::InlineTextBox::logicalTopVisualOverflow):
+        (WebCore::InlineTextBox::logicalBottomVisualOverflow):
+        (WebCore::InlineTextBox::logicalLeftVisualOverflow):
+        (WebCore::InlineTextBox::logicalRightVisualOverflow):
+        New accessors to obtain overflow for inline text boxes.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::updateFirstLetter):
+        updateFirstLetter now removes text boxes from the line box tree before it destroys them, since those
+        text boxes may not have anything in between them and the block that contains the inline first letter
+        container.
+
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlock::createLineBoxes):
+        The culling optimization is done here.  Only if the RenderInline says that boxes are allowed will they
+        be created.
+
+        (WebCore::RenderBlock::layoutInlineChildren):
+        The state of the RenderInline is updated here, in case it is discovered that line boxes are now needed.
+        This is done before any lines are built.
+
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::RenderInline):
+        The new m_alwaysCreateLineBoxes flag has been added to the constructor.
+
+        (WebCore::RenderInline::styleDidChange):
+        An initial update of the m_alwaysCreateLineBoxes happens here for things that can be checked immediately
+        (like having a layer, borders, padding, margins or backgrounds).  Some checks that depend on examining
+        the RenderInline's parent (including first line styles) happen later in layoutInlineChildren.
+
+        (WebCore::RenderInline::updateAlwaysCreateLineBoxes):
+        The function called by layoutInlineChildren to check parent and child style differences (e.g., font,
+        vertical alignment, line height, etc.).
+
+        (WebCore::RenderInline::absoluteRects):
+        (WebCore::RenderInline::culledInlineAbsoluteRects):
+        absoluteRects calls culledInlineAbsoluteRects when m_alwaysCreateLineBoxes is false.
+
+        (WebCore::RenderInline::absoluteQuads):
+        (WebCore::RenderInline::culledInlineAbsoluteQuads):
+        absoluteQuads calls culledInlineAbsoluteQuads when m_alwaysCreateLineBoxes is false.
+
+        (WebCore::RenderInline::offsetLeft):
+        (WebCore::RenderInline::offsetTop):
+        offsetLeft and offsetTop now check descendant renderers when m_alwaysCreateLineBoxes is false.
+
+        (WebCore::RenderInline::linesBoundingBox):
+        (WebCore::RenderInline::culledInlineBoundingBox):
+        lineBoundingBox calls culledInlineBoundingBox when m_alwaysCreateLineBoxes is false.
+
+        (WebCore::RenderInline::culledInlineFirstLineBox):
+        (WebCore::RenderInline::culledInlineLastLineBox):
+        Helpers that return the first and last line box descendants. Used by firstLineBoxIncludingCulling and
+        lastLineBoxIncludingCulling (which are in turn called by offsetLeft and offsetTop).
+
+        (WebCore::RenderInline::culledInlineVisualOverflowBoundingBox):
+        (WebCore::RenderInline::linesVisualOverflowBoundingBox):
+        linesVisualOverflowBoundingBox calls culledInlineVisualOverflowBoundingBox when m_alwaysCreateLineBoxes is false.
+
+        (WebCore::RenderInline::clippedOverflowRectForRepaint):
+        The initial bailout check is now done using firstLineBoxIncludingCulling instead of just firstLineBox.
+
+        (WebCore::RenderInline::dirtyLineBoxes):
+        dirtyLineBoxes now crawls into descendants to figure out which root lines to dirty when
+        m_alwaysCreateLineBoxes is false.
+
+        (WebCore::RenderInline::createAndAppendInlineFlowBox):
+        Clear the m_alwaysCreateLineBoxes if a box gets added anyway. This happens for leaf inline flows and also
+        when line-box-contain is set to an unusual value.
+
+        (WebCore::RenderInline::addFocusRingRects):
+        Used culledInlineAbsoluteRects in place of the line box walk when m_alwaysCreateLineBoxes is false.
+
+        * rendering/RenderInline.h:
+        (WebCore::RenderInline::firstLineBoxIncludingCulling):
+        (WebCore::RenderInline::lastLineBoxIncludingCulling):
+        Helpers used in a few places (like offsetLeft and offsetTop), mostly in places where the existence of a box
+        is all that needs checking.
+
+        (WebCore::RenderInline::alwaysCreateLineBoxes):
+        (WebCore::RenderInline::setAlwaysCreateLineBoxes):
+        Functions for getting and setting the m_alwaysCreateLineBoxes flag.
+
+        * rendering/RenderLineBoxList.cpp:
+        (WebCore::RenderLineBoxList::dirtyLinesFromChangedChild):
+        Modified to use firstLineBoxIncludingCulling and lastLineBoxIncludingCulling to ensure the right set of
+        lines get dirtied.
+
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::removeAndDestroyTextBoxes):
+        New helper invoked by destroy and also from updateFirstLetter.
+
+        (WebCore::RenderText::destroy):
+        Changed to call removeAndDestroyTextBoxes.
+
+        (WebCore::RenderText::absoluteRects):
+        Fixed to be properly physical instead of logical.
+
+        (WebCore::RenderText::linesVisualOverflowBoundingBox):
+        New implementation for RenderText that gives the bounding box of the text boxes including overflow from
+        shadows, glyphs, text-stroke, etc.  Used by RenderInline::culledInlineVisualOverflowBoundingBox.
+
+        * rendering/RenderText.h:
+        * rendering/svg/RenderSVGInline.cpp:
+        (WebCore::RenderSVGInline::RenderSVGInline):
+        RenderSVGInline always sets m_alwaysCreateLineBoxes to true so that SVG is unaffected by this optimization.
+
+        * rendering/svg/SVGRootInlineBox.cpp:
+        (WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes):
+        (WebCore::SVGRootInlineBox::layoutChildBoxes):
+        Move the isInlineFlowBox asserts to after the generated content skips, since the generated content boxes are
+        now InlineTextBoxes (the enclosing InlineFlowBoxes got culled).
+
 2011-04-05  Enrica Casucci  <enrica@apple.com>
 
         Reviewed by Darin Adler.
index 48acff1..5b91eeb 100644 (file)
@@ -597,6 +597,9 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa
     Node* focusedNode = focusedDocument->focusedNode();
     Node* container = focusedDocument;
 
+    if (container->isDocumentNode())
+        static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
+        
     // Figure out the starting rect.
     IntRect startingRect;
     if (focusedNode) {
@@ -612,11 +615,11 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa
 
     bool consumed = false;
     do {
-        if (container->isDocumentNode())
-            static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
         consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event);
         startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
         container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container);
+        if (container && container->isDocumentNode())
+            static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
     } while (!consumed && container);
 
     return consumed;
index 15d3639..26b24aa 100644 (file)
@@ -300,6 +300,8 @@ bool hasOffscreenRect(Node* node, FocusDirection direction)
     if (!frameView)
         return true;
 
+    ASSERT(!frameView->needsLayout());
+
     IntRect containerViewportRect = frameView->visibleContentRect();
     // We want to select a node if it is currently off screen, but will be
     // exposed after we scroll. Adjust the viewport to post-scrolling position.
@@ -517,7 +519,7 @@ static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect& ini
 
 IntRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder)
 {
-    ASSERT(node && node->renderer());
+    ASSERT(node && node->renderer() && !node->document()->view()->needsLayout());
 
     if (node->isDocumentNode())
         return frameRectInAbsoluteCoordinates(static_cast<Document*>(node)->frame());
index 36f3d3a..0587a1f 100644 (file)
@@ -97,6 +97,24 @@ void FloatRect::unite(const FloatRect& other)
     setLocationAndSizeFromEdges(l, t, r, b);
 }
 
+void FloatRect::uniteIfNonZero(const FloatRect& other)
+{
+    // Handle empty special cases first.
+    if (!other.width() && !other.height())
+        return;
+    if (!width() && !height()) {
+        *this = other;
+        return;
+    }
+
+    float left = min(x(), other.x());
+    float top = min(y(), other.y());
+    float right = max(maxX(), other.maxX());
+    float bottom = max(maxY(), other.maxY());
+
+    setLocationAndSizeFromEdges(left, top, right, bottom);
+}
+
 void FloatRect::scale(float sx, float sy)
 {
     m_location.setX(x() * sx);
index bd23476..18ac9cf 100644 (file)
@@ -112,6 +112,7 @@ public:
 
     void intersect(const FloatRect&);
     void unite(const FloatRect&);
+    void uniteIfNonZero(const FloatRect&);
 
     // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version
     // is really checking for containment of 1x1 rect, but that doesn't make sense with floats.
index 89c5545..367f004 100644 (file)
@@ -96,6 +96,11 @@ public:
     int lineGap() const { return lroundf(m_lineGap); }
     int lineSpacing() const { return lroundf(m_lineSpacing); }
 
+    bool hasIdenticalAscentDescentAndLineGap(const FontMetrics& other) const
+    {
+        return ascent() == other.ascent() && descent() == other.descent() && lineGap() == other.lineGap();
+    }
+
 private:
     friend class SimpleFontData;
 
index 7591c41..9507406 100644 (file)
@@ -96,6 +96,27 @@ void IntRect::unite(const IntRect& other)
     m_size.setHeight(b - t);
 }
 
+void IntRect::uniteIfNonZero(const IntRect& other)
+{
+    // Handle empty special cases first.
+    if (!other.width() && !other.height())
+        return;
+    if (!width() && !height()) {
+        *this = other;
+        return;
+    }
+
+    int left = min(x(), other.x());
+    int top = min(y(), other.y());
+    int right = max(maxX(), other.maxX());
+    int bottom = max(maxY(), other.maxY());
+
+    m_location.setX(left);
+    m_location.setY(top);
+    m_size.setWidth(right - left);
+    m_size.setHeight(bottom - top);
+}
+
 void IntRect::scale(float s)
 {
     m_location.setX((int)(x() * s));
index c413e7a..d62ebba 100644 (file)
@@ -144,6 +144,7 @@ public:
 
     void intersect(const IntRect&);
     void unite(const IntRect&);
+    void uniteIfNonZero(const IntRect&);
 
     void inflateX(int dx)
     {
index e5638c9..77ccc4b 100644 (file)
@@ -32,6 +32,7 @@
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "RenderImage.h"
+#include "RenderInline.h"
 #include "Scrollbar.h"
 #include "SelectionController.h"
 
@@ -544,6 +545,20 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const
     node = node->shadowAncestorNode();
     mutableRectBasedTestResult().add(node);
 
+    if (node->renderer()->isInline()) {
+        for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) {
+            if (!curr->isRenderInline())
+                break;
+            
+            // We need to make sure the nodes for culled inlines get included.
+            RenderInline* currInline = toRenderInline(curr);
+            if (currInline->alwaysCreateLineBoxes())
+                break;
+            
+            if (currInline->visibleToHitTesting() && currInline->node())
+                mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode());
+        }
+    }
     return !rect.contains(rectForPoint(x, y));
 }
 
@@ -561,6 +576,20 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const
     node = node->shadowAncestorNode();
     mutableRectBasedTestResult().add(node);
 
+    if (node->renderer()->isInline()) {
+        for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) {
+            if (!curr->isRenderInline())
+                break;
+            
+            // We need to make sure the nodes for culled inlines get included.
+            RenderInline* currInline = toRenderInline(curr);
+            if (currInline->alwaysCreateLineBoxes())
+                break;
+            
+            if (currInline->visibleToHitTesting() && currInline->node())
+                mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode());
+        }
+    }
     return !rect.contains(rectForPoint(x, y));
 }
 
index e448cad..8989a77 100644 (file)
@@ -263,7 +263,7 @@ public:
     // The logical height is our extent in the block flow direction, i.e., height for horizontal text and width for vertical text.
     int logicalHeight() const;
 
-    FloatRect logicalFrameRect() const { return isHorizontal() ? IntRect(m_x, m_y, m_logicalWidth, logicalHeight()) : IntRect(m_y, m_x, logicalHeight(), m_logicalWidth); }
+    FloatRect logicalFrameRect() const { return isHorizontal() ? IntRect(m_x, m_y, m_logicalWidth, logicalHeight()) : IntRect(m_y, m_x, m_logicalWidth, logicalHeight()); }
 
     virtual int baselinePosition(FontBaseline baselineType) const { return boxModelObject()->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
     virtual int lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
index 5763815..1a7a2cf 100644 (file)
@@ -97,7 +97,8 @@ void InlineFlowBox::addToLine(InlineBox* child)
     child->setFirstLineStyleBit(m_firstLine);
     child->setIsHorizontal(isHorizontal());
     if (child->isText()) {
-        m_hasTextChildren = true;
+        if (child->renderer()->parent() == renderer())
+            m_hasTextChildren = true;
         m_hasTextDescendants = true;
     } else if (child->isInlineFlowBox()) {
         if (static_cast<InlineFlowBox*>(child)->hasTextDescendants())
@@ -111,12 +112,13 @@ void InlineFlowBox::addToLine(InlineBox* child)
         if (child->renderer()->isReplaced())
             shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
         else if (child->isText()) {
-            if (child->renderer()->isBR()) {
-                if (parentStyle->font().fontMetrics().ascent() != childStyle->font().fontMetrics().ascent()
-                    || parentStyle->font().fontMetrics().descent() != childStyle->font().fontMetrics().descent() || parentStyle->lineHeight() != childStyle->lineHeight()
+            if (child->renderer()->isBR() || child->renderer()->parent() != renderer()) {
+                if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
+                    || parentStyle->lineHeight() != childStyle->lineHeight()
                     || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE)
                     shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
-            } else if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone)
+            }
+            if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone)
                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
         } else {
             if (child->renderer()->isBR()) {
@@ -127,8 +129,9 @@ void InlineFlowBox::addToLine(InlineBox* child)
                 ASSERT(isInlineFlowBox());
                 InlineFlowBox* childFlowBox = static_cast<InlineFlowBox*>(child);
                 // Check the child's bit, and then also check for differences in font, line-height, vertical-align
-                if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline() || parentStyle->font().fontMetrics().ascent() != childStyle->font().fontMetrics().ascent()
-                    || parentStyle->font().fontMetrics().descent() != childStyle->font().fontMetrics().descent() || parentStyle->lineHeight() != childStyle->lineHeight()
+                if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline()
+                    || !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
+                    || parentStyle->lineHeight() != childStyle->lineHeight()
                     || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE
                     || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine())
                     shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
@@ -732,12 +735,12 @@ inline void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOver
                                     logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
 }
 
-inline void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, IntRect& logicalVisualOverflow)
+inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, IntRect& logicalVisualOverflow)
 {
     if (textBox->knownToHaveNoOverflow())
         return;
 
-    RenderStyle* style = renderer()->style(m_firstLine);
+    RenderStyle* style = textBox->renderer()->style(m_firstLine);
     
     GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox);
     GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second;
@@ -788,6 +791,8 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox
     
     logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
                                     logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
+                                    
+    textBox->setLogicalOverflowRect(logicalVisualOverflow);
 }
 
 inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow)
@@ -835,7 +840,9 @@ void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, GlyphOverflowAn
             RenderText* rt = toRenderText(text->renderer());
             if (rt->isBR())
                 continue;
-            addTextBoxVisualOverflow(text, textBoxDataMap, logicalVisualOverflow);
+            IntRect textBoxOverflow(enclosingIntRect(text->logicalFrameRect()));
+            addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow);
+            logicalVisualOverflow.unite(textBoxOverflow);
         } else  if (curr->renderer()->isRenderInline()) {
             InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
             flow->computeOverflow(lineTop, lineBottom, textBoxDataMap);
index f4c1897..d68eb6a 100644 (file)
@@ -272,7 +272,7 @@ public:
 
 private:
     void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow);
-    void addTextBoxVisualOverflow(const InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow);
+    void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow);
     void addReplacedChildOverflow(const InlineBox*, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow);
 
 protected:
index d2d0fcd..5815b8b 100644 (file)
@@ -48,20 +48,49 @@ using namespace std;
 
 namespace WebCore {
 
+typedef WTF::HashMap<const InlineTextBox*, IntRect> InlineTextBoxOverflowMap;
+static InlineTextBoxOverflowMap* gTextBoxesWithOverflow;
+
+void InlineTextBox::destroy(RenderArena* arena)
+{
+    if (!m_knownToHaveNoOverflow && gTextBoxesWithOverflow)
+        gTextBoxesWithOverflow->remove(this);
+    InlineBox::destroy(arena);
+}
+
+IntRect InlineTextBox::logicalOverflowRect() const
+{
+    if (m_knownToHaveNoOverflow || !gTextBoxesWithOverflow)
+        return enclosingIntRect(logicalFrameRect());
+    return gTextBoxesWithOverflow->get(this);
+}
+
+void InlineTextBox::setLogicalOverflowRect(const IntRect& rect)
+{
+    ASSERT(!m_knownToHaveNoOverflow);
+    if (!gTextBoxesWithOverflow)
+        gTextBoxesWithOverflow = new InlineTextBoxOverflowMap;
+    gTextBoxesWithOverflow->add(this, rect);
+}
+
 int InlineTextBox::baselinePosition(FontBaseline baselineType) const
 {
     if (!isText() || !parent())
         return 0;
-    return parent()->baselinePosition(baselineType);
+    if (parent()->renderer() == renderer()->parent())
+        return parent()->baselinePosition(baselineType);
+    return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
 }
     
 int InlineTextBox::lineHeight() const
 {
-    if (!isText() || !parent())
+    if (!isText() || !renderer()->parent())
         return 0;
     if (m_renderer->isBR())
         return toRenderBR(m_renderer)->lineHeight(m_firstLine);
-    return parent()->lineHeight();
+    if (parent()->renderer() == renderer()->parent())
+        return parent()->lineHeight();
+    return toRenderBoxModelObject(renderer()->parent())->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
 }
 
 int InlineTextBox::selectionTop()
@@ -435,7 +464,7 @@ static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirecti
         : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY());
 }
 
-void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int lineBottom)
+void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty, int /*lineTop*/, int /*lineBottom*/)
 {
     if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE ||
         m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len)
@@ -443,17 +472,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int
 
     ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);
 
-    int logicalLeftOverflow = 0;
-    int logicalRightOverflow = 0;
-    if (!knownToHaveNoOverflow()) {
-        // FIXME: Technically we're potentially incorporating other visual overflow that had nothing to do with us.
-        // Would it be simpler to just check our own shadow and stroke overflow by hand here?
-        IntRect parentVisualOverflow = parent()->logicalVisualOverflowRect(lineTop, lineBottom);
-        logicalLeftOverflow = parent()->logicalLeft() - parentVisualOverflow.x();
-        logicalRightOverflow = parentVisualOverflow.maxX() - parent()->logicalRight();
-    }
-    int logicalStart = logicalLeft() - logicalLeftOverflow + (isHorizontal() ? tx : ty);
-    int logicalExtent = logicalWidth() + logicalLeftOverflow + logicalRightOverflow;
+    int logicalLeftSide = logicalLeftVisualOverflow();
+    int logicalRightSide = logicalRightVisualOverflow();
+    int logicalStart = logicalLeftSide + (isHorizontal() ? tx : ty);
+    int logicalExtent = logicalRightSide - logicalLeftSide;
     
     int paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rect.maxY();
     int paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect.y();
index ad9e9a5..1878c9f 100644 (file)
@@ -51,6 +51,8 @@ public:
     {
     }
 
+    virtual void destroy(RenderArena*);
+
     InlineTextBox* prevTextBox() const { return m_prevTextBox; }
     InlineTextBox* nextTextBox() const { return m_nextTextBox; }
     void setNextTextBox(InlineTextBox* n) { m_nextTextBox = n; }
@@ -80,6 +82,13 @@ public:
 
     bool getEmphasisMarkPosition(RenderStyle*, TextEmphasisPosition&) const;
 
+    IntRect logicalOverflowRect() const;
+    void setLogicalOverflowRect(const IntRect&);
+    int logicalTopVisualOverflow() const { return logicalOverflowRect().y(); }
+    int logicalBottomVisualOverflow() const { return logicalOverflowRect().maxY(); }
+    int logicalLeftVisualOverflow() const { return logicalOverflowRect().x(); }
+    int logicalRightVisualOverflow() const { return logicalOverflowRect().maxX(); }
+    
 private:
     int selectionTop();
     int selectionBottom();
index 7baeb20..0f0165e 100644 (file)
@@ -5326,7 +5326,7 @@ void RenderBlock::updateFirstLetter()
             view()->disableLayoutState();
             while (RenderObject* child = firstLetter->firstChild()) {
                 if (child->isText())
-                    toRenderText(child)->dirtyLineBoxes(true);
+                    toRenderText(child)->removeAndDestroyTextBoxes();
                 firstLetter->removeChild(child);
                 newFirstLetter->addChild(child, 0);
             }
index 4e77123..7bdde1f 100644 (file)
@@ -213,8 +213,10 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I
     do {
         ASSERT(obj->isRenderInline() || obj == this);
         
+        RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
+
         // Get the last box we made for this render object.
-        parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox();
+        parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
 
         // If this box or its ancestor is constructed then it is from a previous line, and we need
         // to make a new box for our line.  If this box or its ancestor is unconstructed but it has
@@ -222,7 +224,9 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I
         // as well.  In this situation our inline has actually been split in two on
         // the same line (this can happen with very fancy language mixtures).
         bool constructedNewBox = false;
-        if (!parentBox || parentIsConstructedOrHaveNext(parentBox)) {
+        bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
+        bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
+        if (allowedToConstructNewBox && !canUseExistingParentBox) {
             // We need to make a new box for this render object.  Once
             // made, we need to place it at the end of the current line.
             InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
@@ -235,19 +239,21 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I
             constructedNewBox = true;
         }
 
-        if (!result)
-            result = parentBox;
+        if (constructedNewBox || canUseExistingParentBox) {
+            if (!result)
+                result = parentBox;
 
-        // If we have hit the block itself, then |box| represents the root
-        // inline box for the line, and it doesn't have to be appended to any parent
-        // inline.
-        if (childBox)
-            parentBox->addToLine(childBox);
+            // If we have hit the block itself, then |box| represents the root
+            // inline box for the line, and it doesn't have to be appended to any parent
+            // inline.
+            if (childBox)
+                parentBox->addToLine(childBox);
 
-        if (!constructedNewBox || obj == this)
-            break;
+            if (!constructedNewBox || obj == this)
+                break;
 
-        childBox = parentBox;        
+            childBox = parentBox;        
+        }
 
         // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
         // intermediate inline flows.
@@ -760,6 +766,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
                     o->layoutIfNeeded();
                 }
             } else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
+                if (!o->isText())
+                    toRenderInline(o)->updateAlwaysCreateLineBoxes();
                 if (fullLayout || o->selfNeedsLayout())
                     dirtyLineBoxesForRenderer(o, fullLayout);
                 o->setNeedsLayout(false);
index 3a268d1..df78916 100644 (file)
@@ -27,6 +27,7 @@
 #include "FloatQuad.h"
 #include "GraphicsContext.h"
 #include "HitTestResult.h"
+#include "InlineTextBox.h"
 #include "Page.h"
 #include "RenderArena.h"
 #include "RenderBlock.h"
@@ -47,6 +48,7 @@ namespace WebCore {
 RenderInline::RenderInline(Node* node)
     : RenderBoxModelObject(node)
     , m_lineHeight(-1)
+    , m_alwaysCreateLineBoxes(false)
 {
     setChildrenInline(true);
 }
@@ -144,6 +146,15 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
 
     m_lineHeight = -1;
 
+    if (!m_alwaysCreateLineBoxes) {
+        bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || style()->hasPadding() || style()->hasMargin() || style()->hasOutline();
+        if (oldStyle && alwaysCreateLineBoxes) {
+            dirtyLineBoxes(false);
+            setNeedsLayout(true);
+        }
+        m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
+    }
+
     // Update pseudos for :before and :after now.
     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
         children()->updateBeforeAfterContent(this, BEFORE);
@@ -151,6 +162,39 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
     }
 }
 
+void RenderInline::updateAlwaysCreateLineBoxes()
+{
+    // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
+    // background color will only cause a layout on the first rollover.
+    if (m_alwaysCreateLineBoxes)
+        return;
+
+    RenderStyle* parentStyle = parent()->style();
+    RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
+    bool checkFonts = document()->inNoQuirksMode();
+    bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
+        || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
+        || style()->verticalAlign() != BASELINE
+        || style()->textEmphasisMark() != TextEmphasisMarkNone
+        || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
+        || parentStyle->lineHeight() != style()->lineHeight()));
+
+    if (!alwaysCreateLineBoxes && checkFonts && document()->usesFirstLineRules()) {
+        // Have to check the first line style as well.
+        parentStyle = parent()->style(true);
+        RenderStyle* childStyle = style(true);
+        alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
+        || parentStyle->font().fontMetrics().lineGap() != childStyle->font().fontMetrics().lineGap()
+        || childStyle->verticalAlign() != BASELINE
+        || parentStyle->lineHeight() != childStyle->lineHeight();
+    }
+
+    if (alwaysCreateLineBoxes) {
+        dirtyLineBoxes(false);
+        m_alwaysCreateLineBoxes = true;
+    }
+}
+
 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
 {
     if (continuation())
@@ -424,9 +468,11 @@ void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
 
 void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
 {
-    if (InlineFlowBox* curr = firstLineBox()) {
+    if (!alwaysCreateLineBoxes())
+        culledInlineAbsoluteRects(this, rects, IntSize(tx, ty));
+    else if (InlineFlowBox* curr = firstLineBox()) {
         for (; curr; curr = curr->nextLineBox())
-            rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->logicalWidth(), curr->logicalHeight()));
+            rects.append(enclosingIntRect(FloatRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())));
     } else
         rects.append(IntRect(tx, ty, 0, 0));
 
@@ -441,11 +487,76 @@ void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
     }
 }
 
+void RenderInline::culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>& rects, const IntSize& offset)
+{
+    bool isHorizontal = style()->isHorizontalWritingMode();
+    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (curr->isFloatingOrPositioned())
+            continue;
+            
+        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
+        // direction (aligned to the root box's baseline).
+        if (curr->isBox()) {
+            RenderBox* currBox = toRenderBox(curr);
+            if (currBox->inlineBoxWrapper()) {
+                RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
+                int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                FloatRect result;
+                if (isHorizontal)
+                    result = FloatRect(offset.width() + currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), offset.height() + logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight);
+                else
+                    result = FloatRect(offset.width() + logicalTop, offset.height() + currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom());
+                rects.append(enclosingIntRect(result));
+            }
+        } else if (curr->isRenderInline()) {
+            // If the child doesn't need line boxes either, then we can recur.
+            RenderInline* currInline = toRenderInline(curr);
+            if (!currInline->alwaysCreateLineBoxes())
+                currInline->culledInlineAbsoluteRects(container, rects, offset);
+            else {
+                for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
+                    RootInlineBox* rootBox = childLine->root();
+                    int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                    int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                    FloatRect result;
+                    if (isHorizontal)
+                        result = FloatRect(offset.width() + childLine->x() - childLine->marginLogicalLeft(),
+                            offset.height() + logicalTop,
+                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
+                            logicalHeight);
+                    else
+                        result = FloatRect(offset.width() + logicalTop,
+                            offset.height() + childLine->y() - childLine->marginLogicalLeft(),
+                            logicalHeight,
+                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
+                    rects.append(enclosingIntRect(result));
+                }
+            }
+        } else if (curr->isText()) {
+            RenderText* currText = toRenderText(curr);
+            for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
+                RootInlineBox* rootBox = childText->root();
+                int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                FloatRect result;
+                if (isHorizontal)
+                    result = FloatRect(offset.width() + childText->x(), offset.height() + logicalTop, childText->logicalWidth(), logicalHeight);
+                else
+                    result = FloatRect(offset.width() + logicalTop, offset.height() + childText->y(), logicalHeight, childText->logicalWidth());
+                rects.append(enclosingIntRect(result));
+            }
+        }
+    }
+}
+
 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads)
 {
-    if (InlineFlowBox* curr = firstLineBox()) {
+    if (!alwaysCreateLineBoxes())
+        culledInlineAbsoluteQuads(this, quads);
+    else if (InlineFlowBox* curr = firstLineBox()) {
         for (; curr; curr = curr->nextLineBox()) {
-            FloatRect localRect(curr->x(), curr->y(), curr->logicalWidth(), curr->logicalHeight());
+            FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
             quads.append(localToAbsoluteQuad(localRect));
         }
     } else
@@ -455,19 +566,82 @@ void RenderInline::absoluteQuads(Vector<FloatQuad>& quads)
         continuation()->absoluteQuads(quads);
 }
 
+void RenderInline::culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>& quads)
+{
+    bool isHorizontal = style()->isHorizontalWritingMode();
+    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (curr->isFloatingOrPositioned())
+            continue;
+            
+        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
+        // direction (aligned to the root box's baseline).
+        if (curr->isBox()) {
+            RenderBox* currBox = toRenderBox(curr);
+            if (currBox->inlineBoxWrapper()) {
+                RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
+                int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                FloatRect result;
+                if (isHorizontal)
+                    result = FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight);
+                else
+                    result = FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom());
+                quads.append(localToAbsoluteQuad(result));
+            }
+        } else if (curr->isRenderInline()) {
+            // If the child doesn't need line boxes either, then we can recur.
+            RenderInline* currInline = toRenderInline(curr);
+            if (!currInline->alwaysCreateLineBoxes())
+                currInline->culledInlineAbsoluteQuads(container, quads);
+            else {
+                for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
+                    RootInlineBox* rootBox = childLine->root();
+                    int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                    int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                    FloatRect result;
+                    if (isHorizontal)
+                        result = FloatRect(childLine->x() - childLine->marginLogicalLeft(),
+                            logicalTop,
+                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
+                            logicalHeight);
+                    else
+                        result = FloatRect(logicalTop,
+                            childLine->y() - childLine->marginLogicalLeft(),
+                            logicalHeight,
+                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
+                    quads.append(localToAbsoluteQuad(result));
+                }
+            }
+        } else if (curr->isText()) {
+            RenderText* currText = toRenderText(curr);
+            for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
+                RootInlineBox* rootBox = childText->root();
+                int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                FloatRect result;
+                if (isHorizontal)
+                    result = FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight);
+                else
+                    result = FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth());
+                quads.append(localToAbsoluteQuad(result));
+            }
+        }
+    }
+}
+
 int RenderInline::offsetLeft() const
 {
     int x = RenderBoxModelObject::offsetLeft();
-    if (firstLineBox())
-        x += firstLineBox()->x();
+    if (InlineBox* firstBox = firstLineBoxIncludingCulling())
+        x += firstBox->x();
     return x;
 }
 
 int RenderInline::offsetTop() const
 {
     int y = RenderBoxModelObject::offsetTop();
-    if (firstLineBox())
-        y += firstLineBox()->y();
+    if (InlineBox* firstBox = firstLineBoxIncludingCulling())
+        y += firstBox->y();
     return y;
 }
 
@@ -565,6 +739,11 @@ VisiblePosition RenderInline::positionForPoint(const IntPoint& point)
 
 IntRect RenderInline::linesBoundingBox() const
 {
+    if (!alwaysCreateLineBoxes()) {
+        ASSERT(!firstLineBox());
+        return enclosingIntRect(culledInlineBoundingBox(this));
+    }
+
     IntRect result;
     
     // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero.  We have been
@@ -594,28 +773,180 @@ IntRect RenderInline::linesBoundingBox() const
     return result;
 }
 
+FloatRect RenderInline::culledInlineBoundingBox(const RenderInline* container) const
+{
+    FloatRect result;
+    bool isHorizontal = style()->isHorizontalWritingMode();
+    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (curr->isFloatingOrPositioned())
+            continue;
+            
+        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
+        // direction (aligned to the root box's baseline).
+        if (curr->isBox()) {
+            RenderBox* currBox = toRenderBox(curr);
+            if (currBox->inlineBoxWrapper()) {
+                RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
+                int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                if (isHorizontal)
+                    result.uniteIfNonZero(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight));
+                else
+                    result.uniteIfNonZero(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom()));
+            }
+        } else if (curr->isRenderInline()) {
+            // If the child doesn't need line boxes either, then we can recur.
+            RenderInline* currInline = toRenderInline(curr);
+            if (!currInline->alwaysCreateLineBoxes())
+                result.uniteIfNonZero(currInline->culledInlineBoundingBox(container));
+            else {
+                for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
+                    RootInlineBox* rootBox = childLine->root();
+                    int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                    int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                    if (isHorizontal)
+                        result.uniteIfNonZero(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
+                            logicalTop,
+                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
+                            logicalHeight));
+                    else
+                        result.uniteIfNonZero(FloatRect(logicalTop,
+                            childLine->y() - childLine->marginLogicalLeft(),
+                            logicalHeight,
+                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
+                                     
+                }
+            }
+        } else if (curr->isText()) {
+            RenderText* currText = toRenderText(curr);
+            for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
+                RootInlineBox* rootBox = childText->root();
+                int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
+                int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
+                if (isHorizontal)
+                    result.uniteIfNonZero(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
+                else
+                    result.uniteIfNonZero(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
+            }
+        }
+    }
+    return enclosingIntRect(result);
+}
+
+InlineBox* RenderInline::culledInlineFirstLineBox() const
+{
+    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (curr->isFloatingOrPositioned())
+            continue;
+            
+        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
+        // direction (aligned to the root box's baseline).
+        if (curr->isBox()) {
+            RenderBox* currBox = toRenderBox(curr);
+            if (currBox->inlineBoxWrapper())
+                return currBox->inlineBoxWrapper();
+        } else if (curr->isRenderInline()) {
+            RenderInline* currInline = toRenderInline(curr);
+            InlineBox* result = currInline->firstLineBoxIncludingCulling();
+            if (result)
+                return result;
+        } else if (curr->isText()) {
+            RenderText* currText = toRenderText(curr);
+            if (currText->firstTextBox())
+                return currText->firstTextBox();
+        }
+    }
+    return 0;
+}
+
+InlineBox* RenderInline::culledInlineLastLineBox() const
+{
+    for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
+        if (curr->isFloatingOrPositioned())
+            continue;
+            
+        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
+        // direction (aligned to the root box's baseline).
+        if (curr->isBox()) {
+            RenderBox* currBox = toRenderBox(curr);
+            if (currBox->inlineBoxWrapper())
+                return currBox->inlineBoxWrapper();
+        } else if (curr->isRenderInline()) {
+            RenderInline* currInline = toRenderInline(curr);
+            InlineBox* result = currInline->lastLineBoxIncludingCulling();
+            if (result)
+                return result;
+        } else if (curr->isText()) {
+            RenderText* currText = toRenderText(curr);
+            if (currText->lastTextBox())
+                return currText->lastTextBox();
+        }
+    }
+    return 0;
+}
+
+IntRect RenderInline::culledInlineVisualOverflowBoundingBox() const
+{
+    IntRect result(culledInlineBoundingBox(this));
+    bool isHorizontal = style()->isHorizontalWritingMode();
+    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (curr->isFloatingOrPositioned())
+            continue;
+            
+        // For overflow we just have to propagate by hand and recompute it all.
+        if (curr->isBox()) {
+            RenderBox* currBox = toRenderBox(curr);
+            if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
+                IntRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
+                if (isHorizontal) {
+                    logicalRect.move(currBox->x(), currBox->y());
+                    result.uniteIfNonZero(logicalRect);
+                } else {
+                    logicalRect.move(currBox->y(), currBox->x());
+                    result.uniteIfNonZero(logicalRect.transposedRect());
+                }
+            }
+        } else if (curr->isRenderInline()) {
+            // If the child doesn't need line boxes either, then we can recur.
+            RenderInline* currInline = toRenderInline(curr);
+            if (!currInline->alwaysCreateLineBoxes())
+                result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
+            else if (!currInline->hasSelfPaintingLayer())
+                result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
+        } else if (curr->isText()) {
+            // FIXME; Overflow from text boxes is lost. We will need to cache this information in
+            // InlineTextBoxes.
+            RenderText* currText = toRenderText(curr);
+            result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
+        }
+    }
+    return result;
+}
+
 IntRect RenderInline::linesVisualOverflowBoundingBox() const
 {
+    if (!alwaysCreateLineBoxes())
+        return culledInlineVisualOverflowBoundingBox();
+
     if (!firstLineBox() || !lastLineBox())
         return IntRect();
 
     // Return the width of the minimal left side and the maximal right side.
-    float logicalLeftSide = numeric_limits<int>::max();
-    float logicalRightSide = numeric_limits<int>::min();
+    int logicalLeftSide = numeric_limits<int>::max();
+    int logicalRightSide = numeric_limits<int>::min();
     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
-        logicalLeftSide = min(logicalLeftSide, static_cast<float>(curr->logicalLeftVisualOverflow()));
-        logicalRightSide = max(logicalRightSide, static_cast<float>(curr->logicalRightVisualOverflow()));
+        logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
+        logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
     }
 
     RootInlineBox* firstRootBox = firstLineBox()->root();
     RootInlineBox* lastRootBox = lastLineBox()->root();
     
-    float logicalLeft = firstLineBox()->logicalLeftVisualOverflow();
-    float logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
-    float logicalWidth = logicalRightSide - logicalLeftSide;
-    float logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
+    int logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
+    int logicalWidth = logicalRightSide - logicalLeftSide;
+    int logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
     
-    IntRect rect = enclosingIntRect(FloatRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
+    IntRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
     if (!style()->isHorizontalWritingMode())
         rect = rect.transposedRect();
     return rect;
@@ -626,7 +957,7 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repain
     // Only run-ins are allowed in here during layout.
     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
 
-    if (!firstLineBox() && !continuation())
+    if (!firstLineBoxIncludingCulling() && !continuation())
         return IntRect();
 
     // Find our leftmost position.
@@ -894,9 +1225,33 @@ void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& po
 
 void RenderInline::dirtyLineBoxes(bool fullLayout)
 {
-    if (fullLayout)
+    if (fullLayout) {
         m_lineBoxes.deleteLineBoxes(renderArena());
-    else
+        return;
+    }
+
+    if (!alwaysCreateLineBoxes()) {
+        // We have to grovel into our children in order to dirty the appropriate lines.
+        for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+            if (curr->isFloatingOrPositioned())
+                continue;
+            if (curr->isBox() && !curr->needsLayout()) {
+                RenderBox* currBox = toRenderBox(curr);
+                if (currBox->inlineBoxWrapper())
+                    currBox->inlineBoxWrapper()->root()->markDirty();
+            } else if (!curr->selfNeedsLayout()) {
+                if (curr->isRenderInline()) {
+                    RenderInline* currInline = toRenderInline(curr);
+                    for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
+                        childLine->root()->markDirty();
+                } else if (curr->isText()) {
+                    RenderText* currText = toRenderText(curr);
+                    for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
+                        childText->root()->markDirty();
+                }
+            }
+        }
+    } else
         m_lineBoxes.dirtyLineBoxes();
 }
 
@@ -907,6 +1262,7 @@ InlineFlowBox* RenderInline::createInlineFlowBox()
 
 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
 {
+    setAlwaysCreateLineBoxes();
     InlineFlowBox* flowBox = createInlineFlowBox();
     m_lineBoxes.appendLineBox(flowBox);
     return flowBox;
@@ -983,13 +1339,11 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
 
 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
 {
-    for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
-        RootInlineBox* root = curr->root();
-        int top = max(root->lineTop(), curr->logicalTop());
-        int bottom = min(root->lineBottom(), curr->logicalBottom());
-        IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top);
-        if (!rect.isEmpty())
-            rects.append(rect);
+    if (!alwaysCreateLineBoxes())
+        culledInlineAbsoluteRects(this, rects, IntSize(tx, ty));
+    else {
+        for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
+            rects.append(enclosingIntRect(FloatRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())));
     }
 
     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
@@ -1000,7 +1354,7 @@ void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
                 pos = curr->localToAbsolute();
             else if (curr->isBox())
                 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
-           curr->addFocusRingRects(rects, pos.x(), pos.y());
+            curr->addFocusRingRects(rects, pos.x(), pos.y());
         }
     }
 
index 08ac002..dc3eaea 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef RenderInline_h
 #define RenderInline_h
 
+#include "InlineFlowBox.h"
 #include "RenderBoxModelObject.h"
 #include "RenderLineBoxList.h"
 
@@ -64,6 +65,8 @@ public:
 
     InlineFlowBox* firstLineBox() const { return m_lineBoxes.firstLineBox(); }
     InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); }
+    InlineBox* firstLineBoxIncludingCulling() const { return alwaysCreateLineBoxes() ? firstLineBox() : culledInlineFirstLineBox(); }
+    InlineBox* lastLineBoxIncludingCulling() const { return alwaysCreateLineBoxes() ? lastLineBox() : culledInlineLastLineBox(); }
 
     virtual RenderBoxModelObject* virtualContinuation() const { return continuation(); }
     RenderInline* inlineElementContinuation() const;
@@ -78,6 +81,10 @@ public:
     using RenderBoxModelObject::continuation;
     using RenderBoxModelObject::setContinuation;
 
+    bool alwaysCreateLineBoxes() const { return m_alwaysCreateLineBoxes; }
+    void setAlwaysCreateLineBoxes() { m_alwaysCreateLineBoxes = true; }
+    void updateAlwaysCreateLineBoxes();
+
 protected:
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
 
@@ -91,6 +98,13 @@ private:
 
     virtual bool isRenderInline() const { return true; }
 
+    FloatRect culledInlineBoundingBox(const RenderInline* container) const;
+    IntRect culledInlineVisualOverflowBoundingBox() const;
+    InlineBox* culledInlineFirstLineBox() const;
+    InlineBox* culledInlineLastLineBox() const;
+    void culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>&, const IntSize&);
+    void culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>&);
+
     void addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild);
     virtual void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild = 0);
 
@@ -154,7 +168,8 @@ private:
     RenderObjectChildList m_children;
     RenderLineBoxList m_lineBoxes;   // All of the line boxes created for this inline flow.  For example, <i>Hello<br>world.</i> will have two <i> line boxes.
 
-    mutable int m_lineHeight;
+    mutable int m_lineHeight : 31;
+    bool m_alwaysCreateLineBoxes : 1;
 };
 
 inline RenderInline* toRenderInline(RenderObject* object)
index f719fb8..32f133c 100644 (file)
@@ -317,8 +317,11 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend
     if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isBlockFlow())))
         return;
 
+    RenderInline* inlineContainer = container->isRenderInline() ? toRenderInline(container) : 0;
+    InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox();
+
     // If we have no first line box, then just bail early.
-    if (!firstLineBox()) {
+    if (!firstBox) {
         // For an empty inline, go ahead and propagate the check up to our parent, unless the parent
         // is already dirty.
         if (container->isInline() && !container->parent()->selfNeedsLayout())
@@ -344,16 +347,16 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend
             if (textBox)
                 box = textBox->root();
         } else if (curr->isRenderInline()) {
-            InlineFlowBox* flowBox = toRenderInline(curr)->lastLineBox();
-            if (flowBox)
-                box = flowBox->root();
+            InlineBox* lastSiblingBox = toRenderInline(curr)->lastLineBoxIncludingCulling();
+            if (lastSiblingBox)
+                box = lastSiblingBox->root();
         }
 
         if (box)
             break;
     }
     if (!box)
-        box = firstLineBox()->root();
+        box = firstBox->root();
 
     // If we found a line box, then dirty it.
     if (box) {
index e660875..234b825 100644 (file)
@@ -177,7 +177,7 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
     }
 }
 
-void RenderText::destroy()
+void RenderText::removeAndDestroyTextBoxes()
 {
     if (!documentBeingDestroyed()) {
         if (firstTextBox()) {
@@ -192,6 +192,11 @@ void RenderText::destroy()
             parent()->dirtyLinesFromChangedChild(this);
     }
     deleteTextBoxes();
+}
+
+void RenderText::destroy()
+{
+    removeAndDestroyTextBoxes();
     RenderObject::destroy();
 }
 
@@ -268,7 +273,7 @@ PassRefPtr<StringImpl> RenderText::originalText() const
 void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
 {
     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
-        rects.append(IntRect(tx + box->x(), ty + box->y(), box->logicalWidth(), box->logicalHeight()));
+        rects.append(enclosingIntRect(FloatRect(tx + box->x(), ty + box->y(), box->width(), box->height())));
 }
 
 void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight)
@@ -1300,6 +1305,29 @@ IntRect RenderText::linesBoundingBox() const
     return result;
 }
 
+IntRect RenderText::linesVisualOverflowBoundingBox() const
+{
+    if (!firstTextBox())
+        return IntRect();
+
+    // Return the width of the minimal left side and the maximal right side.
+    int logicalLeftSide = numeric_limits<int>::max();
+    int logicalRightSide = numeric_limits<int>::min();
+    for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
+        logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
+        logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
+    }
+    
+    int logicalTop = firstTextBox()->logicalTopVisualOverflow();
+    int logicalWidth = logicalRightSide - logicalLeftSide;
+    int logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
+    
+    IntRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
+    if (!style()->isHorizontalWritingMode())
+        rect = rect.transposedRect();
+    return rect;
+}
+
 IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
 {
     RenderObject* cb = containingBlock();
index 7fa3518..2008dad 100644 (file)
@@ -85,6 +85,7 @@ public:
                            float& minW, float& maxW, bool& stripFrontSpaces);
 
     virtual IntRect linesBoundingBox() const;
+    IntRect linesVisualOverflowBoundingBox() const;
 
     FloatPoint firstRunOrigin() const;
     float firstRunX() const;
@@ -127,6 +128,8 @@ public:
     
     bool knownToHaveNoOverflowAndNoFallbackFonts() const { return m_knownToHaveNoOverflowAndNoFallbackFonts; }
 
+    void removeAndDestroyTextBoxes();
+
 protected:
     virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
index 543d14b..02a85ce 100644 (file)
@@ -33,6 +33,7 @@ namespace WebCore {
 RenderSVGInline::RenderSVGInline(Node* n)
     : RenderInline(n)
 {
+    setAlwaysCreateLineBoxes();
 }
 
 InlineFlowBox* RenderSVGInline::createInlineFlowBox()
index 35222d1..a6be507 100644 (file)
@@ -103,13 +103,13 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText
             SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
             characterLayout.layoutInlineTextBox(textBox);
         } else {
-            ASSERT(child->isInlineFlowBox());
-
             // Skip generated content.
             Node* node = child->renderer()->node();
             if (!node)
                 continue;
 
+            ASSERT(child->isInlineFlowBox());
+
             SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
             bool isTextPath = node->hasTagName(SVGNames::textPathTag);
             if (isTextPath) {
@@ -146,12 +146,12 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start)
             textBox->setLogicalWidth(boxRect.width());
             textBox->setLogicalHeight(boxRect.height());
         } else {
-            ASSERT(child->isInlineFlowBox());
-
             // Skip generated content.
             if (!child->renderer()->node())
                 continue;
 
+            ASSERT(child->isInlineFlowBox());
+
             SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
             layoutChildBoxes(flowBox);