Title: [128468] trunk/Source/WebCore
Revision
128468
Author
allan.jen...@nokia.com
Date
2012-09-13 08:22:37 -0700 (Thu, 13 Sep 2012)

Log Message

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):

Modified Paths

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"; }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to