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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@149007 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 96edbd2..c267c80 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -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
diff --git a/Source/WebCore/GNUmakefile.list.am b/Source/WebCore/GNUmakefile.list.am
index 8bdb1bd..b0e834f 100644
--- a/Source/WebCore/GNUmakefile.list.am
+++ b/Source/WebCore/GNUmakefile.list.am
@@ -4440,6 +4440,7 @@
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 \
diff --git a/Source/WebCore/Target.pri b/Source/WebCore/Target.pri
index e8f79d4..ec6841a 100644
--- a/Source/WebCore/Target.pri
+++ b/Source/WebCore/Target.pri
@@ -2448,8 +2448,9 @@
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 \
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index 1559725..46b6e0a 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -3308,6 +3308,7 @@
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, ); }; };
@@ -9784,6 +9785,7 @@
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>"; };
@@ -12601,9 +12603,9 @@
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>"; };
@@ -20022,6 +20024,7 @@
A120ACA013F9983700FE4AC7 /* LayoutRepainter.h */,
2D9066040BE141D400956998 /* LayoutState.cpp */,
2D9066050BE141D400956998 /* LayoutState.h */,
+ 9BA273F3172206BB0097CE47 /* LogicalSelectionOffsetCaches.h */,
3774ABA30FA21EB400AD7DE9 /* OverlapTestRequestClient.h */,
9377AB9F15DEFEEF0031FD04 /* Pagination.h */,
0885067D11DA045B00182B98 /* PaintInfo.h */,
@@ -22883,6 +22886,7 @@
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
index 0000000..3434395
--- /dev/null
+++ b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h
@@ -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
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
index 3b092bb..31bfb0c 100644
--- a/Source/WebCore/rendering/RenderBlock.cpp
+++ b/Source/WebCore/rendering/RenderBlock.cpp
@@ -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 @@
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 @@
}
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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::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::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 @@
(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;
diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h
index 45ab913..93f9516 100644
--- a/Source/WebCore/rendering/RenderBlock.h
+++ b/Source/WebCore/rendering/RenderBlock.h
@@ -46,6 +46,7 @@
class LayoutStateMaintainer;
class LineLayoutState;
class LineWidth;
+class LogicalSelectionOffsetCaches;
class RenderInline;
class RenderText;
@@ -243,9 +244,9 @@
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 @@
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;
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index 27b676f..00935e1 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -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 @@
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
diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp
index 6655c43..105f2f7 100644
--- a/Source/WebCore/rendering/RootInlineBox.cpp
+++ b/Source/WebCore/rendering/RootInlineBox.cpp
@@ -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 @@
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 @@
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
diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h
index 766e370..f867745 100644
--- a/Source/WebCore/rendering/RootInlineBox.h
+++ b/Source/WebCore/rendering/RootInlineBox.h
@@ -28,6 +28,7 @@
class EllipsisBox;
class HitTestResult;
+class LogicalSelectionOffsetCaches;
class RenderRegion;
struct BidiStatus;
@@ -131,7 +132,8 @@
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;