Move "hover" state logic from Node to Element.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 25 May 2013 09:16:30 +0000 (09:16 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 25 May 2013 09:16:30 +0000 (09:16 +0000)
<http://webkit.org/b/116757>

Reviewed by Antti Koivisto.

Resolve a 7 year old FIXME by merging the "hover" state logic from Node and ContainerNode
and moving it all to Element instead.

* dom/Node.cpp:
(WebCore::Node::detach):
* dom/Element.cpp:
(WebCore::Element::detach):

    Move Document::hoveredNodeDetached() call from Node::detach() to Element::detach().

(WebCore::Element::isUserActionElementHovered):
(WebCore::Element::setHovered):
* dom/Element.h:
(WebCore::Element::hovered):

    Moved here from Node/ContainerNode.

* dom/UserActionElementSet.h:
(WebCore::UserActionElementSet::setHovered):
(WebCore::UserActionElementSet::setFlags):

    Make setHovered() take an Element* instead of a Node*. I'd like to do this will all
    of these methods eventually, so added a setFlags() helper with the tighter type.

* html/HTMLLabelElement.h:
* html/shadow/SpinButtonElement.h:

    Sprinkle OVERRIDE on setHovered() overrides.

* dom/Document.cpp:
(WebCore::Document::updateHoverActiveState):
* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::isHovered):
* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::isHovered):

    Check if the inspected Node is an element before asking if it's hovered.

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

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityNodeObject.cpp
Source/WebCore/dom/ContainerNode.cpp
Source/WebCore/dom/ContainerNode.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/dom/Node.cpp
Source/WebCore/dom/Node.h
Source/WebCore/dom/UserActionElementSet.cpp
Source/WebCore/dom/UserActionElementSet.h
Source/WebCore/html/HTMLLabelElement.h
Source/WebCore/html/shadow/SpinButtonElement.h
Source/WebCore/rendering/RenderTheme.cpp

index 58b01f5..07f28e3 100644 (file)
@@ -1,3 +1,48 @@
+2013-05-24  Andreas Kling  <akling@apple.com>
+
+        Move "hover" state logic from Node to Element.
+        <http://webkit.org/b/116757>
+
+        Reviewed by Antti Koivisto.
+
+        Resolve a 7 year old FIXME by merging the "hover" state logic from Node and ContainerNode
+        and moving it all to Element instead.
+
+        * dom/Node.cpp:
+        (WebCore::Node::detach):
+        * dom/Element.cpp:
+        (WebCore::Element::detach):
+
+            Move Document::hoveredNodeDetached() call from Node::detach() to Element::detach().
+
+        (WebCore::Element::isUserActionElementHovered):
+        (WebCore::Element::setHovered):
+        * dom/Element.h:
+        (WebCore::Element::hovered):
+
+            Moved here from Node/ContainerNode.
+
+        * dom/UserActionElementSet.h:
+        (WebCore::UserActionElementSet::setHovered):
+        (WebCore::UserActionElementSet::setFlags):
+
+            Make setHovered() take an Element* instead of a Node*. I'd like to do this will all
+            of these methods eventually, so added a setFlags() helper with the tighter type.
+
+        * html/HTMLLabelElement.h:
+        * html/shadow/SpinButtonElement.h:
+
+            Sprinkle OVERRIDE on setHovered() overrides.
+
+        * dom/Document.cpp:
+        (WebCore::Document::updateHoverActiveState):
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::isHovered):
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::isHovered):
+
+            Check if the inspected Node is an element before asking if it's hovered.
+
 2013-05-25  Andreas Kling  <akling@apple.com>
 
         Document::formController() should return a reference.
index 94b7422..7795218 100644 (file)
@@ -672,7 +672,7 @@ bool AccessibilityNodeObject::isHovered() const
     if (!node)
         return false;
 
-    return node->hovered();
+    return node->isElementNode() && toElement(node)->hovered();
 }
 
 bool AccessibilityNodeObject::isMultiSelectable() const
index 9043be9..9608686 100644 (file)
@@ -1029,22 +1029,6 @@ void ContainerNode::setActive(bool down, bool pause)
     }
 }
 
-void ContainerNode::setHovered(bool over)
-{
-    if (over == hovered()) return;
-
-    Node::setHovered(over);
-
-    // note that we need to recalc the style
-    // FIXME: Move to Element
-    if (renderer()) {
-        if (renderStyle()->affectedByHover() || (isElementNode() && toElement(this)->childrenAffectedByHover()))
-            setNeedsStyleRecalc();
-        if (renderer() && renderer()->style()->hasAppearance())
-            renderer()->theme()->stateChanged(renderer(), HoverState);
-    }
-}
-
 unsigned ContainerNode::childNodeCount() const
 {
     unsigned count = 0;
index 83d69cb..14b2611 100644 (file)
@@ -111,7 +111,6 @@ public:
     virtual LayoutRect boundingBox() const OVERRIDE;
     virtual void setFocus(bool) OVERRIDE;
     virtual void setActive(bool active = true, bool pause = false) OVERRIDE;
-    virtual void setHovered(bool = true) OVERRIDE;
     virtual void scheduleSetNeedsStyleRecalc(StyleChangeType = FullStyleChange) OVERRIDE FINAL;
 
     // -----------------------------------------------------------------------------
index 998ad34..7291ddc 100644 (file)
@@ -5969,7 +5969,8 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
 
     size_t removeCount = nodesToRemoveFromChain.size();
     for (size_t i = 0; i < removeCount; ++i) {
-        nodesToRemoveFromChain[i]->setHovered(false);
+        if (nodesToRemoveFromChain[i]->isElementNode())
+            toElement(nodesToRemoveFromChain[i].get())->setHovered(false);
         if (event && (hasCapturingMouseLeaveListener || nodesToRemoveFromChain[i]->hasEventListeners(eventNames().mouseleaveEvent)))
             nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, eventNames().mouseleaveEvent, 0, newHoverNode);
     }
@@ -5983,7 +5984,8 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
             sawCommonAncestor = true;
         if (!sawCommonAncestor) {
             // Elements after the common hover ancestor does not change hover state, but are iterated over because they may change active state.
-            nodesToAddToChain[i]->setHovered(true);
+            if (nodesToAddToChain[i]->isElementNode())
+                toElement(nodesToAddToChain[i].get())->setHovered(true);
             if (event && (hasCapturingMouseEnterListener || nodesToAddToChain[i]->hasEventListeners(eventNames().mouseenterEvent)))
                 nodesToAddToChain[i]->dispatchMouseEvent(*event, eventNames().mouseenterEvent, 0, oldHoverNode.get());
         }
index af5ddd4..46ad98e 100644 (file)
@@ -70,6 +70,7 @@
 #include "PointerLockController.h"
 #include "PseudoElement.h"
 #include "RenderRegion.h"
+#include "RenderTheme.h"
 #include "RenderView.h"
 #include "RenderWidget.h"
 #include "SelectorQuery.h"
@@ -401,6 +402,30 @@ const AtomicString& Element::getAttribute(const QualifiedName& name) const
     return nullAtom;
 }
 
+bool Element::isUserActionElementHovered() const
+{
+    ASSERT(isUserActionElement());
+    return document()->userActionElements().isHovered(this);
+}
+
+void Element::setHovered(bool flag)
+{
+    if (flag == hovered())
+        return;
+
+    if (Document* document = this->document())
+        document->userActionElements().setHovered(this, flag);
+
+    if (!renderer())
+        return;
+
+    if (renderer()->style()->affectedByHover() || childrenAffectedByHover())
+        setNeedsStyleRecalc();
+
+    if (renderer()->style()->hasAppearance())
+        renderer()->theme()->stateChanged(renderer(), HoverState);
+}
+
 void Element::scrollIntoView(bool alignToTop) 
 {
     document()->updateLayoutIgnorePendingStylesheets();
@@ -1326,6 +1351,10 @@ void Element::detach()
         detachChildrenIfNeeded();
         shadow->detach();
     }
+
+    if (hovered())
+        document()->hoveredNodeDetached(this);
+
     ContainerNode::detach();
 }
 
index 633cbc4..f16032e 100644 (file)
@@ -426,6 +426,9 @@ public:
 
     virtual const AtomicString& shadowPseudoId() const;
 
+    bool hovered() const { return isUserActionElement() && isUserActionElementHovered(); }
+    virtual void setHovered(bool flag = true);
+
     RenderStyle* computedStyle(PseudoId = NOPSEUDO);
 
     // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.)
@@ -654,6 +657,8 @@ protected:
     void classAttributeChanged(const AtomicString& newClassString);
 
 private:
+    bool isUserActionElementHovered() const;
+
     void updatePseudoElement(PseudoId, StyleChange = NoChange);
     PassRefPtr<PseudoElement> createPseudoElementIfNeeded(PseudoId);
     void setPseudoElement(PseudoId, PassRefPtr<PseudoElement>);
index b771da2..f179326 100644 (file)
@@ -1107,8 +1107,6 @@ void Node::detach()
 
     Document* doc = document();
     if (isUserActionElement()) {
-        if (hovered())
-            doc->hoveredNodeDetached(this);
         if (inActiveChain())
             doc->activeChainNodeDetached(this);
         doc->userActionElements().didDetach(this);
@@ -2751,12 +2749,6 @@ void Node::setActive(bool flag, bool)
         document->userActionElements().setActive(this, flag);
 }
 
-void Node::setHovered(bool flag)
-{
-    if (Document* document = this->document())
-        document->userActionElements().setHovered(this, flag);
-}
-
 bool Node::isUserActionElementActive() const
 {
     ASSERT(isUserActionElement());
@@ -2769,12 +2761,6 @@ bool Node::isUserActionElementInActiveChain() const
     return document()->userActionElements().isInActiveChain(this);
 }
 
-bool Node::isUserActionElementHovered() const
-{
-    ASSERT(isUserActionElement());
-    return document()->userActionElements().isHovered(this);
-}
-
 bool Node::isUserActionElementFocused() const
 {
     ASSERT(isUserActionElement());
index 4b5f4cd..6556fd4 100644 (file)
@@ -360,7 +360,6 @@ public:
 
     bool active() const { return isUserActionElement() && isUserActionElementActive(); }
     bool inActiveChain() const { return isUserActionElement() && isUserActionElementInActiveChain(); }
-    bool hovered() const { return isUserActionElement() && isUserActionElementHovered(); }
     bool focused() const { return isUserActionElement() && isUserActionElementFocused(); }
 
     bool attached() const { return getFlag(IsAttachedFlag); }
@@ -401,7 +400,6 @@ public:
 
     virtual void setFocus(bool flag);
     virtual void setActive(bool flag = true, bool pause = false);
-    virtual void setHovered(bool flag = true);
 
     virtual short tabIndex() const;
 
@@ -791,7 +789,6 @@ private:
 
     bool isUserActionElementActive() const;
     bool isUserActionElementInActiveChain() const;
-    bool isUserActionElementHovered() const;
     bool isUserActionElementFocused() const;
 
     void setStyleChange(StyleChangeType);
index 410fd5f..e3b4bf6 100644 (file)
@@ -72,7 +72,7 @@ void UserActionElementSet::clearFlags(Node* node, unsigned flags)
     return clearFlags(toElement(node), flags);
 }
 
-inline bool UserActionElementSet::hasFlags(const Element* element, unsigned flags) const
+bool UserActionElementSet::hasFlags(const Element* element, unsigned flags) const
 {
     ASSERT(element->isUserActionElement());
     ElementFlagMap::const_iterator found = m_elements.find(const_cast<Element*>(element));
@@ -81,7 +81,7 @@ inline bool UserActionElementSet::hasFlags(const Element* element, unsigned flag
     return found->value & flags;
 }
 
-inline void UserActionElementSet::clearFlags(Element* element, unsigned flags)
+void UserActionElementSet::clearFlags(Element* element, unsigned flags)
 {
     if (!element->isUserActionElement()) {
         ASSERT(m_elements.end() == m_elements.find(element));
@@ -104,7 +104,7 @@ inline void UserActionElementSet::clearFlags(Element* element, unsigned flags)
     found->value = updated;
 }
 
-inline void UserActionElementSet::setFlags(Element* element, unsigned flags)
+void UserActionElementSet::setFlags(Element* element, unsigned flags)
 {
     ElementFlagMap::iterator result = m_elements.find(element);
     if (result != m_elements.end()) {
index fa4d53f..59379d2 100644 (file)
@@ -49,7 +49,7 @@ public:
     void setFocused(Node* node, bool enable) { setFlags(node, enable, IsFocusedFlag); }
     void setActive(Node* node, bool enable) { setFlags(node, enable, IsActiveFlag); }
     void setInActiveChain(Node* node, bool enable) { setFlags(node, enable, InActiveChainFlag); }
-    void setHovered(Node* node, bool enable) { setFlags(node, enable, IsHoveredFlag); }
+    void setHovered(Element* element, bool enable) { setFlags(element, enable, IsHoveredFlag); }
 
     UserActionElementSet();
     ~UserActionElementSet();
@@ -70,6 +70,7 @@ private:
     void clearFlags(Node*, unsigned);
     bool hasFlags(const Node*, unsigned flags) const;
 
+    void setFlags(Element* element, bool enable, unsigned flags) { enable ? setFlags(element, flags) : clearFlags(element, flags); }
     void setFlags(Element*, unsigned);
     void clearFlags(Element*, unsigned);
     bool hasFlags(const Element*, unsigned flags) const;
index 7b1935b..2d4fac0 100644 (file)
@@ -47,7 +47,7 @@ private:
 
     // Overridden to update the hover/active state of the corresponding control.
     virtual void setActive(bool = true, bool pause = false);
-    virtual void setHovered(bool = true);
+    virtual void setHovered(bool = true) OVERRIDE;
 
     // Overridden to either click() or focus() the corresponding control.
     virtual void defaultEventHandler(Event*);
index c524355..7aab4ca 100644 (file)
@@ -81,7 +81,7 @@ private:
     void startRepeatingTimer();
     void stopRepeatingTimer();
     void repeatingTimerFired(Timer<SpinButtonElement>*);
-    virtual void setHovered(bool = true);
+    virtual void setHovered(bool = true) OVERRIDE;
     bool shouldRespondToMouseEvents();
     virtual bool isMouseFocusable() const { return false; }
 
index 7f333e1..2537519 100644 (file)
@@ -831,10 +831,10 @@ bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
 bool RenderTheme::isHovered(const RenderObject* o) const
 {
     Node* node = o->node();
-    if (!node)
+    if (!node || !node->isElementNode())
         return false;
-    if (!node->isElementNode() || !toElement(node)->isSpinButtonElement())
-        return node->hovered();
+    if (!toElement(node)->isSpinButtonElement())
+        return toElement(node)->hovered();
     SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
     return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate;
 }