logicalLeftSelectionGap and logicalRightSelectionGap call availableLogicalWidth(...
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Apr 2013 00:18:27 +0000 (00:18 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Apr 2013 00:18:27 +0000 (00:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=113479

Reviewed by David Hyatt.

Introduced LogicalSelectionOffsetCaches to cache the containing blocks and their logical left and right
selection offsets in computing selection gaps. An instance of this class stores the containing block for
each position type and caches their logical selection offsets when none of their block ancestors up until
its nearest selection root do no have any floating objects or regions and exclusions.

When blockSelectionGaps recurses to another level, it creates a new cache instance by "inheriting"
(like RenderStyle) from the old cache, overriding those containing blocks that are replaced by "this".

This eliminates the need to traverse containing block ancestors in RenderBlock::logicalLeftSelectionOffset
and RenderBlock::logicalRightSelectionOffset, and improves WebKit's performance by roughly 20%.

Performance Tests: Interactive/SelectAll.html

* GNUmakefile.list.am:
* Target.pri:
* WebCore.xcodeproj/project.pbxproj:

* rendering/LogicalSelectionOffsetCaches.h: Added.
(WebCore::isContainingBlockCandidateForAbsolutelyPositionedObject): Moved from RenderObject.h.
(WebCore::isNonRenderBlockInline): Ditto.
(WebCore::containingBlockForFixedPosition): Extracted from RenderObject::containingBlock.
(WebCore::containingBlockForAbsolutePosition): Ditto.
(WebCore::containingBlockForObjectInFlow): Ditto.

(WebCore::LogicalSelectionOffsetCaches): Added.
(WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::ContainingBlockInfo): Added.
(WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::setBlock): Added. m_hasFloatsOrRegions is
or'ed with itself when ContainingBlockInfo is copy constructed since m_hasFloatsOrRegions needs be true
for a block when any of its containing block ancestors have floats or regions.
(WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::block): Added.
(WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::cache): Added.
(WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::logicalLeftSelectionOffset): Added. Caches
the logical selection offset if it hasn't.
(WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::logicalRightSelectionOffset): Ditto.

(WebCore::LogicalSelectionOffsetCaches::LogicalSelectionOffsetCaches): The first constructor is used
for a selection root. The second one is used for inheriting from another cache. In the latter case,
copy all containing block information except ones that need to be overridden by this block.
(WebCore::LogicalSelectionOffsetCaches::containingBlockInfo): Returns a ContainingBlockInfo based on
object's position value.

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::selectionGapRectsForRepaint):
(WebCore::RenderBlock::paintSelection):
(WebCore::RenderBlock::selectionGaps):
(WebCore::RenderBlock::inlineSelectionGaps):
(WebCore::RenderBlock::blockSelectionGaps): Exit before instantiating a new LogicalSelectionOffsetCaches
if there is no child to recurse.
(WebCore::RenderBlock::blockSelectionGap):
(WebCore::RenderBlock::logicalLeftSelectionGap):
(WebCore::RenderBlock::logicalRightSelectionGap):
(WebCore::RenderBlock::logicalLeftSelectionOffset): Use LogicalSelectionOffsetCaches to get its containing
block and its logical selection offset.
(WebCore::RenderBlock::logicalRightSelectionOffset): Ditto.

* rendering/RenderBlock.h:
(WebCore::RenderBlock):

* rendering/RenderObject.cpp:
(WebCore::RenderObject::containingBlock): Extracted code into LogicalSelectionOffsetCaches.h.

* rendering/RootInlineBox.cpp:
(WebCore::RootInlineBox::lineSelectionGap):

* rendering/RootInlineBox.h:
(WebCore::RootInlineBox):

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

Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/rendering/LogicalSelectionOffsetCaches.h [new file with mode: 0644]
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RootInlineBox.cpp
Source/WebCore/rendering/RootInlineBox.h

index 96edbd25c8c4f2e033233f78a1b9896787fd379f..c267c802b749d53c7c5de621f498f0e1af45fa55 100644 (file)
@@ -1,3 +1,77 @@
+2013-04-22  Ryosuke Niwa  <rniwa@webkit.org>
+
+        logicalLeftSelectionGap and logicalRightSelectionGap call availableLogicalWidth() multiple times
+        https://bugs.webkit.org/show_bug.cgi?id=113479
+
+        Reviewed by David Hyatt.
+
+        Introduced LogicalSelectionOffsetCaches to cache the containing blocks and their logical left and right
+        selection offsets in computing selection gaps. An instance of this class stores the containing block for
+        each position type and caches their logical selection offsets when none of their block ancestors up until
+        its nearest selection root do no have any floating objects or regions and exclusions.
+
+        When blockSelectionGaps recurses to another level, it creates a new cache instance by "inheriting"
+        (like RenderStyle) from the old cache, overriding those containing blocks that are replaced by "this".
+
+        This eliminates the need to traverse containing block ancestors in RenderBlock::logicalLeftSelectionOffset
+        and RenderBlock::logicalRightSelectionOffset, and improves WebKit's performance by roughly 20%.
+
+        Performance Tests: Interactive/SelectAll.html
+
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * rendering/LogicalSelectionOffsetCaches.h: Added.
+        (WebCore::isContainingBlockCandidateForAbsolutelyPositionedObject): Moved from RenderObject.h.
+        (WebCore::isNonRenderBlockInline): Ditto.
+        (WebCore::containingBlockForFixedPosition): Extracted from RenderObject::containingBlock.
+        (WebCore::containingBlockForAbsolutePosition): Ditto.
+        (WebCore::containingBlockForObjectInFlow): Ditto.
+
+        (WebCore::LogicalSelectionOffsetCaches): Added.
+        (WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::ContainingBlockInfo): Added.
+        (WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::setBlock): Added. m_hasFloatsOrRegions is
+        or'ed with itself when ContainingBlockInfo is copy constructed since m_hasFloatsOrRegions needs be true
+        for a block when any of its containing block ancestors have floats or regions.
+        (WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::block): Added.
+        (WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::cache): Added.
+        (WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::logicalLeftSelectionOffset): Added. Caches
+        the logical selection offset if it hasn't.
+        (WebCore::LogicalSelectionOffsetCaches::ContainingBlockInfo::logicalRightSelectionOffset): Ditto.
+
+        (WebCore::LogicalSelectionOffsetCaches::LogicalSelectionOffsetCaches): The first constructor is used
+        for a selection root. The second one is used for inheriting from another cache. In the latter case,
+        copy all containing block information except ones that need to be overridden by this block.
+        (WebCore::LogicalSelectionOffsetCaches::containingBlockInfo): Returns a ContainingBlockInfo based on
+        object's position value.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::selectionGapRectsForRepaint):
+        (WebCore::RenderBlock::paintSelection):
+        (WebCore::RenderBlock::selectionGaps):
+        (WebCore::RenderBlock::inlineSelectionGaps):
+        (WebCore::RenderBlock::blockSelectionGaps): Exit before instantiating a new LogicalSelectionOffsetCaches
+        if there is no child to recurse.
+        (WebCore::RenderBlock::blockSelectionGap):
+        (WebCore::RenderBlock::logicalLeftSelectionGap):
+        (WebCore::RenderBlock::logicalRightSelectionGap):
+        (WebCore::RenderBlock::logicalLeftSelectionOffset): Use LogicalSelectionOffsetCaches to get its containing
+        block and its logical selection offset.
+        (WebCore::RenderBlock::logicalRightSelectionOffset): Ditto.
+
+        * rendering/RenderBlock.h:
+        (WebCore::RenderBlock):
+
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::containingBlock): Extracted code into LogicalSelectionOffsetCaches.h.
+
+        * rendering/RootInlineBox.cpp:
+        (WebCore::RootInlineBox::lineSelectionGap):
+
+        * rendering/RootInlineBox.h:
+        (WebCore::RootInlineBox):
+
 2013-04-23  Eric Carlson  <eric.carlson@apple.com>
 
         [Mac] forced subtitle track should change when audio track language changes
index 8bdb1bdb5a8feaf3b151f1d047cc11f23546d60e..b0e834f3ca8d0830b27ddc8d9b09c07f842babb2 100644 (file)
@@ -4440,6 +4440,7 @@ webcore_sources += \
        Source/WebCore/rendering/InlineTextBox.h \
        Source/WebCore/rendering/LayoutState.cpp \
        Source/WebCore/rendering/LayoutState.h \
+       Source/WebCore/rendering/LogicalSelectionOffsetCaches.h \
        Source/WebCore/rendering/LayoutRepainter.h \
        Source/WebCore/rendering/LayoutRepainter.cpp \
        Source/WebCore/rendering/OverlapTestRequestClient.h \
index e8f79d4e2027f39c99bc96837086be8e3fd59473..ec6841abbf1301d9ec322f542a085b7c30010553 100644 (file)
@@ -2448,8 +2448,9 @@ HEADERS += \
     rendering/InlineBox.h \
     rendering/InlineFlowBox.h \
     rendering/InlineTextBox.h \
-    rendering/LayoutState.h \
     rendering/LayoutRepainter.h \
+    rendering/LayoutState.h \
+    rendering/LogicalSelectionOffsetCaches.h \
     rendering/mathml/RenderMathMLBlock.h \
     rendering/mathml/RenderMathMLFenced.h \
     rendering/mathml/RenderMathMLFraction.h \
index 15597252db96105380484aa409504c3c04340330..46b6e0aaaaa7aad4f9487d82cfa7f43fadd64a8e 100644 (file)
                9B6C41531344949000085B62 /* StringWithDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B6C41521344949000085B62 /* StringWithDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9B7E78BD16F16CC600126914 /* HTMLTreeBuilderSimulator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B7E78BA16F16CAE00126914 /* HTMLTreeBuilderSimulator.cpp */; };
                9B7E78BE16F16CC800126914 /* HTMLTreeBuilderSimulator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B7E78BB16F16CAE00126914 /* HTMLTreeBuilderSimulator.h */; };
+               9BA273F4172206BB0097CE47 /* LogicalSelectionOffsetCaches.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BA273F3172206BB0097CE47 /* LogicalSelectionOffsetCaches.h */; };
                9BAB6C6C12550631001626D4 /* EditingStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BAB6C6A12550631001626D4 /* EditingStyle.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9BAB6C6D12550631001626D4 /* EditingStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BAB6C6B12550631001626D4 /* EditingStyle.cpp */; };
                9BAF3B2412C1A39800014BF1 /* WritingDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BAF3B2312C1A39800014BF1 /* WritingDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9B6C41521344949000085B62 /* StringWithDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringWithDirection.h; sourceTree = "<group>"; };
                9B7E78BA16F16CAE00126914 /* HTMLTreeBuilderSimulator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLTreeBuilderSimulator.cpp; path = parser/HTMLTreeBuilderSimulator.cpp; sourceTree = "<group>"; };
                9B7E78BB16F16CAE00126914 /* HTMLTreeBuilderSimulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTMLTreeBuilderSimulator.h; path = parser/HTMLTreeBuilderSimulator.h; sourceTree = "<group>"; };
+               9BA273F3172206BB0097CE47 /* LogicalSelectionOffsetCaches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogicalSelectionOffsetCaches.h; sourceTree = "<group>"; };
                9BAB6C6A12550631001626D4 /* EditingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingStyle.h; sourceTree = "<group>"; };
                9BAB6C6B12550631001626D4 /* EditingStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditingStyle.cpp; sourceTree = "<group>"; };
                9BAF3B2312C1A39800014BF1 /* WritingDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WritingDirection.h; sourceTree = "<group>"; };
                FABE72F31059C1EB00D999DD /* mathtags.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mathtags.in; sourceTree = "<group>"; };
                FABE72FB1059C21100D999DD /* MathMLElementFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathMLElementFactory.cpp; sourceTree = "<group>"; };
                FABE72FC1059C21100D999DD /* MathMLNames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathMLNames.cpp; sourceTree = "<group>"; };
-               FB1A66D917225A6600BAA7AF /* CustomFilterColorParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterColorParameter.h; path = filters/CustomFilterColorParameter.h; sourceTree = "<group>"; };
                FB0B75EE1723428500F05D2A /* WebKitCSSMatFunctionValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebKitCSSMatFunctionValue.cpp; sourceTree = "<group>"; };
                FB0B75EF1723428500F05D2A /* WebKitCSSMatFunctionValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitCSSMatFunctionValue.h; sourceTree = "<group>"; };
+               FB1A66D917225A6600BAA7AF /* CustomFilterColorParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterColorParameter.h; path = filters/CustomFilterColorParameter.h; sourceTree = "<group>"; };
                FB2C15C2165D64900039C9F8 /* CachedSVGDocumentReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedSVGDocumentReference.h; sourceTree = "<group>"; };
                FB3056C1169E5DAC0096A232 /* CSSGroupingRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSGroupingRule.h; sourceTree = "<group>"; };
                FB484F4A171F821E00040755 /* TransformFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TransformFunctions.cpp; sourceTree = "<group>"; };
                                A120ACA013F9983700FE4AC7 /* LayoutRepainter.h */,
                                2D9066040BE141D400956998 /* LayoutState.cpp */,
                                2D9066050BE141D400956998 /* LayoutState.h */,
+                               9BA273F3172206BB0097CE47 /* LogicalSelectionOffsetCaches.h */,
                                3774ABA30FA21EB400AD7DE9 /* OverlapTestRequestClient.h */,
                                9377AB9F15DEFEEF0031FD04 /* Pagination.h */,
                                0885067D11DA045B00182B98 /* PaintInfo.h */,
                                935207BE09BD410A00F2038D /* LocalizedStrings.h in Headers */,
                                BCE1C41B0D982980003B02F2 /* Location.h in Headers */,
                                A8239E0109B3CF8A00B60641 /* Logging.h in Headers */,
+                               9BA273F4172206BB0097CE47 /* LogicalSelectionOffsetCaches.h in Headers */,
                                E187056316E54A0D00585E97 /* MainThreadTask.h in Headers */,
                                1A8F6BC60DB55CDC001DB794 /* ManifestParser.h in Headers */,
                                93309DF8099E64920056E581 /* markup.h in Headers */,
diff --git a/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h
new file mode 100644 (file)
index 0000000..3434395
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef LogicalSelectionOffsetCaches_h
+#define LogicalSelectionOffsetCaches_h
+
+#include "RenderBlock.h"
+
+namespace WebCore {
+
+static inline bool isContainingBlockCandidateForAbsolutelyPositionedObject(RenderObject* object)
+{
+    return object->style()->position() != StaticPosition
+        || (object->hasTransform() && object->isRenderBlock())
+#if ENABLE(SVG)
+        || object->isSVGForeignObject()
+#endif
+        || object->isRenderView();
+}
+
+static inline bool isNonRenderBlockInline(RenderObject* object)
+{
+    return (object->isInline() && !object->isReplaced()) || !object->isRenderBlock();
+}
+
+static inline RenderObject* containingBlockForFixedPosition(RenderObject* parent)
+{
+    RenderObject* object = parent;
+    while (object && !object->canContainFixedPositionObjects())
+        object = object->parent();
+    ASSERT(!object || !object->isAnonymousBlock());
+    return object;
+}
+
+static inline RenderObject* containingBlockForAbsolutePosition(RenderObject* parent)
+{
+    RenderObject* object = parent;
+    while (object && !isContainingBlockCandidateForAbsolutelyPositionedObject(object))
+        object = object->parent();
+    
+    // For a relatively positioned inline, return its nearest non-anonymous containing block,
+    // not the inline itself, to avoid having a positioned objects list in all RenderInlines
+    // and use RenderBlock* as RenderObject::containingBlock's return type.
+    // Use RenderBlock::container() to obtain the inline.
+    if (object->isRenderInline())
+        object = object->containingBlock();
+    
+    while (object && object->isAnonymousBlock())
+        object = object->containingBlock();
+    
+    return object;
+}
+
+static inline RenderObject* containingBlockForObjectInFlow(RenderObject* parent)
+{
+    RenderObject* object = parent;
+    while (object && isNonRenderBlockInline(object))
+        object = object->parent();
+    return object;
+}
+
+class LogicalSelectionOffsetCaches {
+public:
+    class ContainingBlockInfo {
+    public:
+        ContainingBlockInfo()
+            : m_block(0)
+            , m_cache(0)
+            , m_hasFloatsOrFlowThreads(false)
+            , m_cachedLogicalLeftSelectionOffset(false)
+            , m_cachedLogicalRightSelectionOffset(false)
+        { }
+
+        void setBlock(RenderBlock* block, const LogicalSelectionOffsetCaches* cache)
+        {
+            m_block = block;
+            m_hasFloatsOrFlowThreads = m_hasFloatsOrFlowThreads || m_block->containsFloats() || m_block->flowThreadContainingBlock();
+            m_cache = cache;
+            m_cachedLogicalLeftSelectionOffset = false;
+            m_cachedLogicalRightSelectionOffset = false;
+        }
+
+        RenderBlock* block() const { return m_block; }
+        const LogicalSelectionOffsetCaches* cache() const { return m_cache; }
+
+        LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) const
+        {
+            ASSERT(m_cache);
+            if (m_hasFloatsOrFlowThreads || !m_cachedLogicalLeftSelectionOffset) {
+                m_cachedLogicalLeftSelectionOffset = true;
+                m_logicalLeftSelectionOffset = m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache);
+            } else
+                ASSERT(m_logicalLeftSelectionOffset == m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache));
+            return m_logicalLeftSelectionOffset;
+        }
+
+        LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) const
+        {
+            ASSERT(m_cache);
+            if (m_hasFloatsOrFlowThreads || !m_cachedLogicalRightSelectionOffset) {
+                m_cachedLogicalRightSelectionOffset = true;
+                m_logicalRightSelectionOffset = m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache);
+            } else
+                ASSERT(m_logicalRightSelectionOffset == m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache));
+            return m_logicalRightSelectionOffset;
+        }
+
+    private:
+        RenderBlock* m_block;
+        const LogicalSelectionOffsetCaches* m_cache;
+        bool m_hasFloatsOrFlowThreads : 1;
+        mutable bool m_cachedLogicalLeftSelectionOffset : 1;
+        mutable bool m_cachedLogicalRightSelectionOffset : 1;
+        mutable LayoutUnit m_logicalLeftSelectionOffset;
+        mutable LayoutUnit m_logicalRightSelectionOffset;
+        
+    };
+
+    LogicalSelectionOffsetCaches(RenderBlock* rootBlock)
+    {
+        ASSERT(rootBlock->isSelectionRoot());
+        RenderObject* parent = rootBlock->parent();
+
+        // LogicalSelectionOffsetCaches should not be used on an orphaned tree.
+        m_containingBlockForFixedPosition.setBlock(toRenderBlock(containingBlockForFixedPosition(parent)), 0);
+        m_containingBlockForAbsolutePosition.setBlock(toRenderBlock(containingBlockForAbsolutePosition(parent)), 0);
+        m_containingBlockForInflowPosition.setBlock(toRenderBlock(containingBlockForObjectInFlow(parent)), 0);
+    }
+
+    LogicalSelectionOffsetCaches(RenderBlock* block, const LogicalSelectionOffsetCaches& cache)
+        : m_containingBlockForFixedPosition(cache.m_containingBlockForFixedPosition)
+        , m_containingBlockForAbsolutePosition(cache.m_containingBlockForAbsolutePosition)
+        , m_parentCache(&cache)
+    {
+        if (block->canContainFixedPositionObjects())
+            m_containingBlockForFixedPosition.setBlock(block, &cache);
+
+        if (isContainingBlockCandidateForAbsolutelyPositionedObject(block) && !block->isRenderInline() && !block->isAnonymousBlock())
+            m_containingBlockForFixedPosition.setBlock(block, &cache);
+
+        m_containingBlockForInflowPosition.setBlock(block, &cache);
+    }
+
+    const ContainingBlockInfo& containingBlockInfo(RenderBlock* block) const
+    {
+        EPosition position = block->style()->position();
+        if (position == FixedPosition) {
+            ASSERT(block->containingBlock() == m_containingBlockForFixedPosition.block());
+            return m_containingBlockForFixedPosition;
+        }
+        if (position == AbsolutePosition) {
+            ASSERT(block->containingBlock() == m_containingBlockForAbsolutePosition.block());
+            return m_containingBlockForAbsolutePosition;
+        }
+        ASSERT(block->containingBlock() == m_containingBlockForInflowPosition.block());
+        return m_containingBlockForInflowPosition;
+    }
+
+private:
+    ContainingBlockInfo m_containingBlockForFixedPosition;
+    ContainingBlockInfo m_containingBlockForAbsolutePosition;
+    ContainingBlockInfo m_containingBlockForInflowPosition;
+    const LogicalSelectionOffsetCaches* m_parentCache;
+};
+
+} // namespace WebCore
+
+#endif // LogicalSelectionOffsetCaches_h
index 3b092bb17ec2fdef415046508dde89275214e39b..31bfb0ca869f04ed3876add9932f6efad5b86959 100644 (file)
@@ -41,6 +41,7 @@
 #include "InlineIterator.h"
 #include "InlineTextBox.h"
 #include "LayoutRepainter.h"
+#include "LogicalSelectionOffsetCaches.h"
 #include "OverflowEvent.h"
 #include "PODFreeListArena.h"
 #include "Page.h"
@@ -3397,22 +3398,24 @@ GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject*
     if (hasOverflowClip())
         offsetFromRepaintContainer -= scrolledContentOffset();
 
+    LogicalSelectionOffsetCaches cache(this);
     LayoutUnit lastTop = 0;
-    LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
-    LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
+    LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
+    LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
     
-    return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
+    return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight, cache);
 }
 
 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
     if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
+        LogicalSelectionOffsetCaches cache(this);
         LayoutUnit lastTop = 0;
-        LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
-        LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
+        LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
+        LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
         GraphicsContextStateSaver stateSaver(*paintInfo.context);
 
-        LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
+        LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, cache, &paintInfo);
         if (!gapRectsBounds.isEmpty()) {
             if (RenderLayer* layer = enclosingLayer()) {
                 gapRectsBounds.moveBy(-paintOffset);
@@ -3464,7 +3467,7 @@ LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPh
 }
 
 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                    LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+    LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
     // Clip out floating and positioned objects when painting selection gaps.
@@ -3501,25 +3504,27 @@ GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& r
     if (hasColumns() || hasTransform() || style()->columnSpan()) {
         // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
         lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
-        lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
-        lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
+        lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
+        lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
         return result;
     }
 
     if (childrenInline())
-        result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
+        result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
     else
-        result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
+        result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
 
     // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
-    if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
-        result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 
-                                             logicalHeight(), paintInfo));
+    if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) {
+        result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
+            lastLogicalTop, lastLogicalLeft, lastLogicalRight, logicalHeight(), cache, paintInfo));
+    }
+
     return result;
 }
 
 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                          LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+    LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     GapRects result;
 
@@ -3530,8 +3535,8 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
             // Go ahead and update our lastLogicalTop to be the bottom of the block.  <hr>s or empty blocks with height can trip this
             // case.
             lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
-            lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
-            lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
+            lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
+            lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
         }
         return result;
     }
@@ -3547,15 +3552,14 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
 
         if (!containsStart && !lastSelectedLine &&
             selectionState() != SelectionStart && selectionState() != SelectionBoth)
-            result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 
-                                                 selTop, paintInfo));
+            result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
         
         LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
         logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
         LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
         if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
             || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
-            result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
+            result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
 
         lastSelectedLine = curr;
     }
@@ -3567,20 +3571,25 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
     if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
         // Go ahead and update our lastY to be the bottom of the last selected line.
         lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
-        lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
-        lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
+        lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
+        lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
     }
     return result;
 }
 
 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                         LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+    LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     GapRects result;
 
     // Go ahead and jump right to the first block child that contains some selected objects.
     RenderBox* curr;
     for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
+    
+    if (!curr)
+        return result;
+
+    LogicalSelectionOffsetCaches childCache(this, cache);
 
     for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
         SelectionState childState = curr->selectionState();
@@ -3602,10 +3611,11 @@ GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoi
         bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
         if (fillBlockGaps) {
             // We need to fill the vertical gap above this object.
-            if (childState == SelectionEnd || childState == SelectionInside)
+            if (childState == SelectionEnd || childState == SelectionInside) {
                 // Fill the gap above the object.
-                result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 
-                                                     curr->logicalTop(), paintInfo));
+                result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
+                    lastLogicalTop, lastLogicalLeft, lastLogicalRight, curr->logicalTop(), cache, paintInfo));
+            }
 
             // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past*
             // our object.  We know this if the selection did not end inside our object.
@@ -3617,26 +3627,27 @@ GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoi
             getSelectionGapInfo(childState, leftGap, rightGap);
 
             if (leftGap)
-                result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
+                result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
             if (rightGap)
-                result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
+                result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
 
             // Update lastLogicalTop to be just underneath the object.  lastLogicalLeft and lastLogicalRight extend as far as
             // they can without bumping into floating or positioned objects.  Ideally they will go right up
             // to the border of the root selection block.
             lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
-            lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
-            lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
-        } else if (childState != SelectionNone)
+            lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom(), cache);
+            lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom(), cache);
+        } else if (childState != SelectionNone) {
             // We must be a block that has some selected object inside it.  Go ahead and recur.
             result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()), 
-                                                            lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
+                lastLogicalTop, lastLogicalLeft, lastLogicalRight, childCache, paintInfo));
+        }
     }
     return result;
 }
 
 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                          LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
+    LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     LayoutUnit logicalTop = lastLogicalTop;
     LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
@@ -3644,8 +3655,8 @@ LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPo
         return LayoutRect();
 
     // Get the selection offsets for the bottom of the gap
-    LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
-    LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
+    LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom, cache));
+    LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom, cache));
     LayoutUnit logicalWidth = logicalRight - logicalLeft;
     if (logicalWidth <= 0)
         return LayoutRect();
@@ -3657,11 +3668,12 @@ LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPo
 }
 
 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                                RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
+    RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
-    LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
-    LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
+    LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
+    LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft),
+        min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
     LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
     if (rootBlockLogicalWidth <= 0)
         return LayoutRect();
@@ -3673,11 +3685,12 @@ LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const La
 }
 
 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                                 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
+    RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
-    LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
-    LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
+    LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight),
+        max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
+    LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
     LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
     if (rootBlockLogicalWidth <= 0)
         return LayoutRect();
@@ -3699,37 +3712,45 @@ void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool&
                (state == RenderObject::SelectionEnd && !ltr);
 }
 
-LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
+LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
 {
     LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
     if (logicalLeft == logicalLeftOffsetForContent()) {
-        if (rootBlock != this)
-            // The border can potentially be further extended by our containingBlock().
-            return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
+        if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
+            return cache.containingBlockInfo(this).logicalLeftSelectionOffset(rootBlock, position + logicalTop());
         return logicalLeft;
     } else {
         RenderBlock* cb = this;
+        const LogicalSelectionOffsetCaches* currentCache = &cache;
         while (cb != rootBlock) {
             logicalLeft += cb->logicalLeft();
-            cb = cb->containingBlock();
+
+            ASSERT(currentCache);
+            const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
+            cb = info.block();
+            currentCache = info.cache();
         }
     }
     return logicalLeft;
 }
 
-LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
+LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
 {
     LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
     if (logicalRight == logicalRightOffsetForContent()) {
-        if (rootBlock != this)
-            // The border can potentially be further extended by our containingBlock().
-            return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
+        if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
+            return cache.containingBlockInfo(this).logicalRightSelectionOffset(rootBlock, position + logicalTop());
         return logicalRight;
     } else {
         RenderBlock* cb = this;
+        const LogicalSelectionOffsetCaches* currentCache = &cache;
         while (cb != rootBlock) {
             logicalRight += cb->logicalLeft();
-            cb = cb->containingBlock();
+
+            ASSERT(currentCache);
+            const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
+            cb = info.block();
+            currentCache = info.cache();
         }
     }
     return logicalRight;
index 45ab9135e4af175ba4ea6dc352879e4788c49e1e..93f95161dfd312bfd6278c6b8c91818839f839da 100644 (file)
@@ -46,6 +46,7 @@ class InlineIterator;
 class LayoutStateMaintainer;
 class LineLayoutState;
 class LineWidth;
+class LogicalSelectionOffsetCaches;
 class RenderInline;
 class RenderText;
 
@@ -243,9 +244,9 @@ public:
 
     GapRects selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer);
     LayoutRect logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                       RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo*);
+        RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
     LayoutRect logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                        RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo*);
+        RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
     void getSelectionGapInfo(SelectionState, bool& leftGap, bool& rightGap);
     RenderBlock* blockBeforeWithinSelectionRoot(LayoutSize& offset) const;
 
@@ -925,15 +926,17 @@ private:
     virtual bool shouldPaintSelectionGaps() const;
     bool isSelectionRoot() const;
     GapRects selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                           LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* = 0);
+        LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo* = 0);
     GapRects inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo*);
+        LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
     GapRects blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo*);
+        LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
     LayoutRect blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
-                                 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo*);
-    LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position);
-    LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position);
+        LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const LogicalSelectionOffsetCaches&, const PaintInfo*);
+    LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches&);
+    LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches&);
+    
+    friend class LogicalSelectionOffsetCaches;
 
     virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const;
     virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const;
index 27b676f181d8864502d887e8014e1ac1bf0779e4..00935e13c70cbbace46a1087b4cca6a0efa684bd 100644 (file)
@@ -44,6 +44,7 @@
 #include "HTMLElement.h"
 #include "HTMLNames.h"
 #include "HitTestResult.h"
+#include "LogicalSelectionOffsetCaches.h"
 #include "Page.h"
 #include "RenderArena.h"
 #include "RenderCounter.h"
@@ -767,48 +768,18 @@ void RenderObject::setLayerNeedsFullRepaintForPositionedMovementLayout()
     toRenderLayerModelObject(this)->layer()->setRepaintStatus(NeedsFullRepaintForPositionedMovementLayout);
 }
 
-static inline bool isContainingBlockCandidateForAbsolutelyPositionedObject(RenderObject* object)
-{
-    return object->style()->position() != StaticPosition
-        || (object->hasTransform() && object->isRenderBlock())
-#if ENABLE(SVG)
-        || object->isSVGForeignObject()
-#endif
-        || object->isRenderView();
-}
-
-static inline bool isNonRenderBlockInline(RenderObject* object)
-{
-    return (object->isInline() && !object->isReplaced()) || !object->isRenderBlock();
-}
-
 RenderBlock* RenderObject::containingBlock() const
 {
     RenderObject* o = parent();
     if (!o && isRenderScrollbarPart())
         o = toRenderScrollbarPart(this)->rendererOwningScrollbar();
 
-    if (!isText() && m_style->position() == FixedPosition) {
-        while (o && !o->canContainFixedPositionObjects())
-            o = o->parent();
-        ASSERT(!o || !o->isAnonymousBlock());
-    } else if (!isText() && m_style->position() == AbsolutePosition) {
-        while (o && !isContainingBlockCandidateForAbsolutelyPositionedObject(o))
-            o = o->parent();
-
-        // For a relatively positioned inline, return its nearest non-anonymous containing block,
-        // not the inline itself, to avoid having a positioned objects list in all RenderInlines
-        // and use RenderBlock* as this function's return type.
-        // Use RenderBlock::container() to obtain the inline.
-        if (o && o->isRenderInline())
-            o = o->containingBlock();
-
-        while (o && o->isAnonymousBlock())
-            o = o->containingBlock();
-    } else {
-        while (o && isNonRenderBlockInline(o))
-            o = o->parent();
-    }
+    if (!isText() && m_style->position() == FixedPosition)
+        o = containingBlockForFixedPosition(o);
+    else if (!isText() && m_style->position() == AbsolutePosition)
+        o = containingBlockForAbsolutePosition(o);
+    else
+        o = containingBlockForObjectInFlow(o);
 
     if (!o || !o->isRenderBlock())
         return 0; // This can still happen in case of an orphaned tree
index 6655c4334e46a1e285e71cd62475f09a38593fff..105f2f760d1a6e53574f67e3c021bd93f69cd420 100644 (file)
@@ -29,6 +29,7 @@
 #include "GraphicsContext.h"
 #include "HitTestResult.h"
 #include "InlineTextBox.h"
+#include "LogicalSelectionOffsetCaches.h"
 #include "Page.h"
 #include "PaintInfo.h"
 #include "RenderArena.h"
@@ -466,8 +467,8 @@ LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const
     return lineSnapAdjustment(newPageLogicalTop - (blockOffset + lineTopWithLeading()));
 }
 
-GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 
-                                         LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo* paintInfo)
+GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
+    LayoutUnit selTop, LayoutUnit selHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
 {
     RenderObject::SelectionState lineState = selectionState();
 
@@ -478,12 +479,14 @@ GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoi
 
     InlineBox* firstBox = firstSelectedBox();
     InlineBox* lastBox = lastSelectedBox();
-    if (leftGap)
-        result.uniteLeft(block()->logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
-                                                          firstBox->parent()->renderer(), firstBox->logicalLeft(), selTop, selHeight, paintInfo));
-    if (rightGap)
-        result.uniteRight(block()->logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
-                                                            lastBox->parent()->renderer(), lastBox->logicalRight(), selTop, selHeight, paintInfo));
+    if (leftGap) {
+        result.uniteLeft(block()->logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, firstBox->parent()->renderer(), firstBox->logicalLeft(),
+            selTop, selHeight, cache, paintInfo));
+    }
+    if (rightGap) {
+        result.uniteRight(block()->logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastBox->parent()->renderer(), lastBox->logicalRight(),
+            selTop, selHeight, cache, paintInfo));
+    }
 
     // When dealing with bidi text, a non-contiguous selection region is possible.
     // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
index 766e3705aea5442414ba3641e7d8ef213d0ab488..f867745da44cde2f25079812a5c1d565962c587c 100644 (file)
@@ -28,6 +28,7 @@ namespace WebCore {
 
 class EllipsisBox;
 class HitTestResult;
+class LogicalSelectionOffsetCaches;
 class RenderRegion;
 
 struct BidiStatus;
@@ -131,7 +132,8 @@ public:
     InlineBox* firstSelectedBox();
     InlineBox* lastSelectedBox();
 
-    GapRects lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo*);
+    GapRects lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
+        LayoutUnit selTop, LayoutUnit selHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
 
     RenderBlock* block() const;