Diff
Modified: trunk/Source/WebCore/ChangeLog (128467 => 128468)
--- trunk/Source/WebCore/ChangeLog 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/ChangeLog 2012-09-13 15:22:37 UTC (rev 128468)
@@ -1,5 +1,36 @@
2012-09-13 Allan Sandfeld Jensen <allan.jen...@nokia.com>
+ Move updateHoverActiveState to Document.
+ https://bugs.webkit.org/show_bug.cgi?id=95858
+
+ Reviewed by Antonio Gomes.
+
+ RenderLayer::updateHoverActiveState contains the logic that updates hover and active states based on
+ hit-tests, but hover and active states are document states, and does have any relation to layers other
+ than documents having atleast one layer.
+
+ By moving the function it will be in the same place as other active/hover state maintainace, and we avoid
+ excessive updates of the state from hit-testing flow threads.
+
+ * dom/Document.cpp:
+ (WebCore::commonAncestor):
+ (WebCore::Document::updateHoverActiveState):
+ * dom/Document.h:
+ (Document):
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::sendContextMenuEventForKey):
+ * rendering/RenderFrameBase.cpp:
+ (WebCore::RenderFrameBase::nodeAtPoint):
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::hitTest):
+ * rendering/RenderLayer.h:
+ * rendering/RenderView.cpp:
+ (WebCore::RenderView::hitTest):
+ * rendering/RenderView.h:
+ (RenderView):
+
+2012-09-13 Allan Sandfeld Jensen <allan.jen...@nokia.com>
+
REGRESSION: hit test doesn't take iframe scroll position into account
https://bugs.webkit.org/show_bug.cgi?id=96541
Modified: trunk/Source/WebCore/dom/Document.cpp (128467 => 128468)
--- trunk/Source/WebCore/dom/Document.cpp 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/dom/Document.cpp 2012-09-13 15:22:37 UTC (rev 128468)
@@ -6120,6 +6120,121 @@
m_contextFeatures = features;
}
+static RenderObject* nearestCommonHoverAncestor(RenderObject* obj1, RenderObject* obj2)
+{
+ if (!obj1 || !obj2)
+ return 0;
+
+ for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
+ for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
+ if (currObj1 == currObj2)
+ return currObj1;
+ }
+ }
+
+ return 0;
+}
+
+void Document::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
+{
+ // We don't update :hover/:active state when the result is marked as readOnly.
+ if (request.readOnly())
+ return;
+
+ Node* innerNodeInDocument = result.innerNode();
+ while (innerNodeInDocument && innerNodeInDocument->document() != this)
+ innerNodeInDocument = innerNodeInDocument->document()->ownerElement();
+
+ Node* oldActiveNode = activeNode();
+ if (oldActiveNode && !request.active()) {
+ // We are clearing the :active chain because the mouse has been released.
+ for (RenderObject* curr = oldActiveNode->renderer(); curr; curr = curr->parent()) {
+ if (curr->node() && !curr->isText()) {
+ curr->node()->setActive(false);
+ curr->node()->clearInActiveChain();
+ }
+ }
+ setActiveNode(0);
+ } else {
+ Node* newActiveNode = innerNodeInDocument;
+ if (!oldActiveNode && newActiveNode && request.active() && !request.touchMove()) {
+ // We are setting the :active chain and freezing it. If future moves happen, they
+ // will need to reference this chain.
+ for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
+ if (curr->node() && !curr->isText())
+ curr->node()->setInActiveChain();
+ }
+ setActiveNode(newActiveNode);
+ }
+ }
+ // If the mouse has just been pressed, set :active on the chain. Those (and only those)
+ // nodes should remain :active until the mouse is released.
+ bool allowActiveChanges = !oldActiveNode && activeNode();
+
+ // If the mouse is down and if this is a mouse move event, we want to restrict changes in
+ // :hover/:active to only apply to elements that are in the :active chain that we froze
+ // at the time the mouse went down.
+ bool mustBeInActiveChain = request.active() && request.move();
+
+ RefPtr<Node> oldHoverNode = hoverNode();
+ // Clear the :hover chain when the touch gesture is over.
+ if (request.touchRelease()) {
+ if (oldHoverNode) {
+ for (RenderObject* curr = oldHoverNode->renderer(); curr; curr = curr->hoverAncestor()) {
+ if (curr->node() && !curr->isText())
+ curr->node()->setHovered(false);
+ }
+ setHoverNode(0);
+ }
+ // A touch release can not set new hover or active target.
+ return;
+ }
+
+ // Check to see if the hovered node has changed.
+ // If it hasn't, we do not need to do anything.
+ Node* newHoverNode = innerNodeInDocument;
+ while (newHoverNode && !newHoverNode->renderer())
+ newHoverNode = newHoverNode->parentOrHostNode();
+
+ // Update our current hover node.
+ setHoverNode(newHoverNode);
+
+ // We have two different objects. Fetch their renderers.
+ RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
+ RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
+
+ // Locate the common ancestor render object for the two renderers.
+ RenderObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj);
+
+ Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
+ Vector<RefPtr<Node>, 32> nodesToAddToChain;
+
+ if (oldHoverObj != newHoverObj) {
+ // The old hover path only needs to be cleared up to (and not including) the common ancestor;
+ for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
+ if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
+ nodesToRemoveFromChain.append(curr->node());
+ }
+ }
+
+ // Now set the hover state for our new object up to the root.
+ for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
+ if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
+ nodesToAddToChain.append(curr->node());
+ }
+
+ size_t removeCount = nodesToRemoveFromChain.size();
+ for (size_t i = 0; i < removeCount; ++i)
+ nodesToRemoveFromChain[i]->setHovered(false);
+
+ size_t addCount = nodesToAddToChain.size();
+ for (size_t i = 0; i < addCount; ++i) {
+ if (allowActiveChanges)
+ nodesToAddToChain[i]->setActive(true);
+ nodesToAddToChain[i]->setHovered(true);
+ }
+}
+
void Document::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{
MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
Modified: trunk/Source/WebCore/dom/Document.h (128467 => 128468)
--- trunk/Source/WebCore/dom/Document.h 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/dom/Document.h 2012-09-13 15:22:37 UTC (rev 128468)
@@ -746,6 +746,8 @@
void hoveredNodeDetached(Node*);
void activeChainNodeDetached(Node*);
+ void updateHoverActiveState(const HitTestRequest&, HitTestResult&);
+
// Updates for :target (CSS3 selector).
void setCSSTarget(Element*);
Element* cssTarget() const { return m_cssTarget; }
Modified: trunk/Source/WebCore/page/EventHandler.cpp (128467 => 128468)
--- trunk/Source/WebCore/page/EventHandler.cpp 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/page/EventHandler.cpp 2012-09-13 15:22:37 UTC (rev 128468)
@@ -2624,7 +2624,7 @@
HitTestResult result(position);
result.setInnerNode(targetNode);
HitTestRequest request(HitTestRequest::Active);
- doc->renderView()->layer()->updateHoverActiveState(request, result);
+ doc->updateHoverActiveState(request, result);
doc->updateStyleIfNeeded();
// The contextmenu event is a mouse event even when invoked using the keyboard.
Modified: trunk/Source/WebCore/rendering/RenderFrameBase.cpp (128467 => 128468)
--- trunk/Source/WebCore/rendering/RenderFrameBase.cpp 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/rendering/RenderFrameBase.cpp 2012-09-13 15:22:37 UTC (rev 128468)
@@ -118,7 +118,7 @@
HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildFrameHitTest);
- bool isInsideChildFrame = childRoot->layer()->hitTest(newHitTestRequest, newHitTestLocation, result);
+ bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTestLocation, result);
if (isInsideChildFrame)
return true;
Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (128467 => 128468)
--- trunk/Source/WebCore/rendering/RenderLayer.cpp 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp 2012-09-13 15:22:37 UTC (rev 128468)
@@ -3472,9 +3472,6 @@
if (node && !result.URLElement())
result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
- // Next set up the correct :hover/:active state along the new chain.
- updateHoverActiveState(request, result);
-
// Now return whether we were inside this layer (this will always be true for the root
// layer).
return insideLayer;
@@ -4506,118 +4503,6 @@
#endif
}
-static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
-{
- if (!obj1 || !obj2)
- return 0;
-
- for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
- for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
- if (currObj1 == currObj2)
- return currObj1;
-
- return 0;
-}
-
-void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
-{
- // We don't update :hover/:active state when the result is marked as readOnly.
- if (request.readOnly())
- return;
-
- Document* doc = renderer()->document();
-
- Node* activeNode = doc->activeNode();
- if (activeNode && !request.active()) {
- // We are clearing the :active chain because the mouse has been released.
- for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
- if (curr->node() && !curr->isText()) {
- curr->node()->setActive(false);
- curr->node()->clearInActiveChain();
- }
- }
- doc->setActiveNode(0);
- } else {
- Node* newActiveNode = result.innerNode();
- if (!activeNode && newActiveNode && request.active() && !request.touchMove()) {
- // We are setting the :active chain and freezing it. If future moves happen, they
- // will need to reference this chain.
- for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
- if (curr->node() && !curr->isText())
- curr->node()->setInActiveChain();
- }
- doc->setActiveNode(newActiveNode);
- }
- }
- // If the mouse has just been pressed, set :active on the chain. Those (and only those)
- // nodes should remain :active until the mouse is released.
- bool allowActiveChanges = !activeNode && doc->activeNode();
-
- // If the mouse is down and if this is a mouse move event, we want to restrict changes in
- // :hover/:active to only apply to elements that are in the :active chain that we froze
- // at the time the mouse went down.
- bool mustBeInActiveChain = request.active() && request.move();
-
- RefPtr<Node> oldHoverNode = doc->hoverNode();
- // Clear the :hover chain when the touch gesture is over.
- if (request.touchRelease()) {
- if (oldHoverNode) {
- for (RenderObject* curr = oldHoverNode->renderer(); curr; curr = curr->parent()) {
- if (curr->node() && !curr->isText())
- curr->node()->setHovered(false);
- }
- doc->setHoverNode(0);
- }
- // A touch release can not set new hover or active target.
- return;
- }
-
- // Check to see if the hovered node has changed.
- // If it hasn't, we do not need to do anything.
- Node* newHoverNode = result.innerNode();
- if (newHoverNode && !newHoverNode->renderer())
- newHoverNode = result.innerNonSharedNode();
-
- // Update our current hover node.
- doc->setHoverNode(newHoverNode);
-
- // We have two different objects. Fetch their renderers.
- RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
- RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
-
- // Locate the common ancestor render object for the two renderers.
- RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
-
- Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
- Vector<RefPtr<Node>, 32> nodesToAddToChain;
-
- if (oldHoverObj != newHoverObj) {
- // The old hover path only needs to be cleared up to (and not including) the common ancestor;
- for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
- if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
- nodesToRemoveFromChain.append(curr->node());
- }
- }
-
- // Now set the hover state for our new object up to the root.
- for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
- if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
- nodesToAddToChain.append(curr->node());
- }
-
- size_t removeCount = nodesToRemoveFromChain.size();
- for (size_t i = 0; i < removeCount; ++i) {
- nodesToRemoveFromChain[i]->setHovered(false);
- }
-
- size_t addCount = nodesToAddToChain.size();
- for (size_t i = 0; i < addCount; ++i) {
- if (allowActiveChanges)
- nodesToAddToChain[i]->setActive(true);
- nodesToAddToChain[i]->setHovered(true);
- }
-}
-
// Helper for the sorting of layers by z-index.
static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
{
Modified: trunk/Source/WebCore/rendering/RenderLayer.h (128467 => 128468)
--- trunk/Source/WebCore/rendering/RenderLayer.h 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/rendering/RenderLayer.h 2012-09-13 15:22:37 UTC (rev 128468)
@@ -563,8 +563,6 @@
typedef unsigned CalculateLayerBoundsFlags;
static IntRect calculateLayerBounds(const RenderLayer*, const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags);
- void updateHoverActiveState(const HitTestRequest&, HitTestResult&);
-
// WARNING: This method returns the offset for the parent as this is what updateLayerPositions expects.
LayoutPoint computeOffsetFromRoot(bool& hasLayerOffset) const;
Modified: trunk/Source/WebCore/rendering/RenderView.cpp (128467 => 128468)
--- trunk/Source/WebCore/rendering/RenderView.cpp 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/rendering/RenderView.cpp 2012-09-13 15:22:37 UTC (rev 128468)
@@ -87,9 +87,19 @@
bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result)
{
- return layer()->hitTest(request, result);
+ return hitTest(request, result.hitTestLocation(), result);
}
+bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result)
+{
+ bool inside = layer()->hitTest(request, location, result);
+
+ // Next set up the correct :hover/:active state along the new chain.
+ document()->updateHoverActiveState(request, result);
+
+ return inside;
+}
+
void RenderView::updateLogicalHeight()
{
if (!shouldUsePrintingLayout() && m_frameView)
Modified: trunk/Source/WebCore/rendering/RenderView.h (128467 => 128468)
--- trunk/Source/WebCore/rendering/RenderView.h 2012-09-13 15:16:47 UTC (rev 128467)
+++ trunk/Source/WebCore/rendering/RenderView.h 2012-09-13 15:22:37 UTC (rev 128468)
@@ -48,6 +48,7 @@
virtual ~RenderView();
bool hitTest(const HitTestRequest&, HitTestResult&);
+ bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&);
virtual const char* renderName() const OVERRIDE { return "RenderView"; }