Move "active" state logic from Node to Element.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 26 May 2013 14:29:15 +0000 (14:29 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 26 May 2013 14:29:15 +0000 (14:29 +0000)
<http://webkit.org/b/116785>

Reviewed by Antti Koivisto.

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

* dom/UserActionElementSet.h:
(WebCore::UserActionElementSet::isActive):
(WebCore::UserActionElementSet::setActive):
* dom/ContainerNode.cpp:
* dom/ContainerNode.h:
* dom/Node.cpp:
* dom/Node.h:
* dom/Element.h:
(WebCore::Element::active):
* dom/Element.cpp:
(WebCore::Element::isUserActionElementActive):
(WebCore::Element::setActive):

    Moved here from Node/ContainerNode.

* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::isPressed):
* dom/Document.cpp:
(WebCore::Document::setFocusedNode):
(WebCore::Document::updateHoverActiveState):
* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::isPressed):
(WebCore::RenderTheme::isSpinUpButtonPartPressed):
* rendering/RenderThemeMac.mm:
(WebCore::getMediaUIPartStateFlags):
(WebCore::RenderThemeMac::updatePressedState):
* platform/qt/RenderThemeQt.cpp:
(WebCore::RenderThemeQt::getMediaControlForegroundColor):

    Check that the inspected Node is an Element before asking if it's active.

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::setActive):

    Call the right superclass.

* html/HTMLAnchorElement.h:
* html/HTMLLabelElement.h:
* html/shadow/MediaControlElementTypes.h:

    Sprinkle OVERRIDE>

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

17 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.h
Source/WebCore/html/HTMLAnchorElement.cpp
Source/WebCore/html/HTMLAnchorElement.h
Source/WebCore/html/HTMLLabelElement.h
Source/WebCore/html/shadow/MediaControlElementTypes.h
Source/WebCore/platform/qt/RenderThemeQt.cpp
Source/WebCore/rendering/RenderTheme.cpp
Source/WebCore/rendering/RenderThemeMac.mm

index 5d287c4..a985492 100644 (file)
@@ -1,5 +1,57 @@
 2013-05-26  Andreas Kling  <akling@apple.com>
 
+        Move "active" state logic from Node to Element.
+        <http://webkit.org/b/116785>
+
+        Reviewed by Antti Koivisto.
+
+        Resolve another 7 year old FIXME by merging the "active" state logic from Node and ContainerNode
+        and moving it all to Element instead.
+
+        * dom/UserActionElementSet.h:
+        (WebCore::UserActionElementSet::isActive):
+        (WebCore::UserActionElementSet::setActive):
+        * dom/ContainerNode.cpp:
+        * dom/ContainerNode.h:
+        * dom/Node.cpp:
+        * dom/Node.h:
+        * dom/Element.h:
+        (WebCore::Element::active):
+        * dom/Element.cpp:
+        (WebCore::Element::isUserActionElementActive):
+        (WebCore::Element::setActive):
+
+            Moved here from Node/ContainerNode.
+
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::isPressed):
+        * dom/Document.cpp:
+        (WebCore::Document::setFocusedNode):
+        (WebCore::Document::updateHoverActiveState):
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::isPressed):
+        (WebCore::RenderTheme::isSpinUpButtonPartPressed):
+        * rendering/RenderThemeMac.mm:
+        (WebCore::getMediaUIPartStateFlags):
+        (WebCore::RenderThemeMac::updatePressedState):
+        * platform/qt/RenderThemeQt.cpp:
+        (WebCore::RenderThemeQt::getMediaControlForegroundColor):
+
+            Check that the inspected Node is an Element before asking if it's active.
+
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::setActive):
+
+            Call the right superclass.
+
+        * html/HTMLAnchorElement.h:
+        * html/HTMLLabelElement.h:
+        * html/shadow/MediaControlElementTypes.h:
+
+            Sprinkle OVERRIDE>
+
+2013-05-26  Andreas Kling  <akling@apple.com>
+
         Move Node::dispatchSimulatedClick() to Element.
         <http://webkit.org/b/116784>
 
index 4ed2752..d297694 100644 (file)
@@ -634,7 +634,9 @@ bool AccessibilityNodeObject::isPressed() const
         return false;
     }
 
-    return node->active();
+    if (!node->isElementNode())
+        return false;
+    return toElement(node)->active();
 }
 
 bool AccessibilityNodeObject::isChecked() const
index 5879597..4b3fe1c 100644 (file)
@@ -968,56 +968,6 @@ LayoutRect ContainerNode::boundingBox() const
     return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
 }
 
-void ContainerNode::setActive(bool down, bool pause)
-{
-    if (down == active()) return;
-
-    Node::setActive(down);
-
-    // note that we need to recalc the style
-    // FIXME: Move to Element
-    if (renderer()) {
-        bool reactsToPress = renderStyle()->affectedByActive() || (isElementNode() && toElement(this)->childrenAffectedByActive());
-        if (reactsToPress)
-            setNeedsStyleRecalc();
-        if (renderStyle()->hasAppearance()) {
-            if (renderer()->theme()->stateChanged(renderer(), PressedState))
-                reactsToPress = true;
-        }
-
-        // The rest of this function implements a feature that only works if the
-        // platform supports immediate invalidations on the ChromeClient, so bail if
-        // that isn't supported.
-        if (!document()->page()->chrome().client()->supportsImmediateInvalidation())
-            return;
-
-        if (reactsToPress && pause) {
-            // The delay here is subtle.  It relies on an assumption, namely that the amount of time it takes
-            // to repaint the "down" state of the control is about the same time as it would take to repaint the
-            // "up" state.  Once you assume this, you can just delay for 100ms - that time (assuming that after you
-            // leave this method, it will be about that long before the flush of the up state happens again).
-#ifdef HAVE_FUNC_USLEEP
-            double startTime = currentTime();
-#endif
-
-            // Ensure there are no pending changes
-            Document::updateStyleForAllDocuments();
-            // Do an immediate repaint.
-            if (renderer())
-                renderer()->repaint(true);
-
-            // FIXME: Find a substitute for usleep for Win32.
-            // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.
-#ifdef HAVE_FUNC_USLEEP
-            // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
-            double remainingTime = 0.1 - (currentTime() - startTime);
-            if (remainingTime > 0)
-                usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
-#endif
-        }
-    }
-}
-
 unsigned ContainerNode::childNodeCount() const
 {
     unsigned count = 0;
index df175e9..1f92c1c 100644 (file)
@@ -109,7 +109,6 @@ public:
     virtual void attach() OVERRIDE;
     virtual void detach() OVERRIDE;
     virtual LayoutRect boundingBox() const OVERRIDE;
-    virtual void setActive(bool active = true, bool pause = false) OVERRIDE;
     virtual void scheduleSetNeedsStyleRecalc(StyleChangeType = FullStyleChange) OVERRIDE FINAL;
 
     // -----------------------------------------------------------------------------
index 374f48b..f01ffa6 100644 (file)
@@ -3340,11 +3340,13 @@ bool Document::setFocusedNode(PassRefPtr<Node> prpNewFocusedNode, FocusDirection
     if (oldFocusedNode) {
         ASSERT(!oldFocusedNode->inDetach());
 
-        if (oldFocusedNode->active())
-            oldFocusedNode->setActive(false);
+        if (oldFocusedNode->isElementNode()) {
+            Element* oldFocusedElement = toElement(oldFocusedNode.get());
+            if (oldFocusedElement->active())
+                oldFocusedElement->setActive(false);
 
-        if (oldFocusedNode->isElementNode())
             toElement(oldFocusedNode.get())->setFocus(false);
+        }
 
         // Dispatch a change event for form control elements that have been edited.
         if (oldFocusedNode->isElementNode() && toElement(oldFocusedNode.get())->isFormControlElement()) {
@@ -5870,7 +5872,8 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
         for (RenderObject* curr = oldActiveElement->renderer(); curr; curr = curr->parent()) {
             if (curr->node()) {
                 ASSERT(!curr->node()->isTextNode());
-                curr->node()->setActive(false);
+                if (curr->node()->isElementNode())
+                    toElement(curr->node())->setActive(false);
                 m_userActionElements.setInActiveChain(curr->node(), false);
             }
         }
@@ -5973,8 +5976,8 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
     bool sawCommonAncestor = false;
     size_t addCount = nodesToAddToChain.size();
     for (size_t i = 0; i < addCount; ++i) {
-        if (allowActiveChanges)
-            nodesToAddToChain[i]->setActive(true);
+        if (allowActiveChanges && nodesToAddToChain[i]->isElementNode())
+            toElement(nodesToAddToChain[i].get())->setActive(true);
         if (ancestor && nodesToAddToChain[i] == ancestor->node())
             sawCommonAncestor = true;
         if (!sawCommonAncestor) {
index 1febda2..43c7429 100644 (file)
@@ -30,6 +30,8 @@
 #include "Attr.h"
 #include "CSSParser.h"
 #include "CSSSelectorList.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
 #include "ClassList.h"
 #include "ClientRect.h"
 #include "ClientRectList.h"
@@ -86,6 +88,7 @@
 #include "XMLNames.h"
 #include "htmlediting.h"
 #include <wtf/BitVector.h>
+#include <wtf/CurrentTime.h>
 #include <wtf/text/CString.h>
 
 #if ENABLE(SVG)
@@ -454,6 +457,12 @@ bool Element::isFocusable() const
     return true;
 }
 
+bool Element::isUserActionElementActive() const
+{
+    ASSERT(isUserActionElement());
+    return document()->userActionElements().isActive(this);
+}
+
 bool Element::isUserActionElementFocused() const
 {
     ASSERT(isUserActionElement());
@@ -466,6 +475,54 @@ bool Element::isUserActionElementHovered() const
     return document()->userActionElements().isHovered(this);
 }
 
+void Element::setActive(bool flag, bool pause)
+{
+    if (flag == active())
+        return;
+
+    if (Document* document = this->document())
+        document->userActionElements().setActive(this, flag);
+
+    if (!renderer())
+        return;
+
+    bool reactsToPress = renderStyle()->affectedByActive() || childrenAffectedByActive();
+    if (reactsToPress)
+        setNeedsStyleRecalc();
+
+    if (renderer()->style()->hasAppearance() && renderer()->theme()->stateChanged(renderer(), PressedState))
+        reactsToPress = true;
+
+    // The rest of this function implements a feature that only works if the
+    // platform supports immediate invalidations on the ChromeClient, so bail if
+    // that isn't supported.
+    if (!document()->page()->chrome().client()->supportsImmediateInvalidation())
+        return;
+
+    if (reactsToPress && pause) {
+        // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
+        // to repaint the "down" state of the control is about the same time as it would take to repaint the
+        // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
+        // leave this method, it will be about that long before the flush of the up state happens again).
+#ifdef HAVE_FUNC_USLEEP
+        double startTime = currentTime();
+#endif
+
+        Document::updateStyleForAllDocuments();
+        // Do an immediate repaint.
+        if (renderer())
+            renderer()->repaint(true);
+
+        // FIXME: Come up with a less ridiculous way of doing this.
+#ifdef HAVE_FUNC_USLEEP
+        // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
+        double remainingTime = 0.1 - (currentTime() - startTime);
+        if (remainingTime > 0)
+            usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
+#endif
+    }
+}
+
 void Element::setFocus(bool flag)
 {
     if (flag == focused())
index 43f84df..cec04f9 100644 (file)
@@ -426,9 +426,11 @@ public:
 
     virtual const AtomicString& shadowPseudoId() const;
 
+    bool active() const { return isUserActionElement() && isUserActionElementActive(); }
     bool hovered() const { return isUserActionElement() && isUserActionElementHovered(); }
     bool focused() const { return isUserActionElement() && isUserActionElementFocused(); }
 
+    virtual void setActive(bool flag = true, bool pause = false);
     virtual void setHovered(bool flag = true);
     virtual void setFocus(bool flag);
 
@@ -662,6 +664,7 @@ protected:
     void classAttributeChanged(const AtomicString& newClassString);
 
 private:
+    bool isUserActionElementActive() const;
     bool isUserActionElementFocused() const;
     bool isUserActionElementHovered() const;
 
index 2246e8b..5ef7ea3 100644 (file)
@@ -2677,18 +2677,6 @@ size_t Node::numberOfScopedHTMLStyleChildren() const
     return count;
 }
 
-void Node::setActive(bool flag, bool)
-{
-    if (Document* document = this->document())
-        document->userActionElements().setActive(this, flag);
-}
-
-bool Node::isUserActionElementActive() const
-{
-    ASSERT(isUserActionElement());
-    return document()->userActionElements().isActive(this);
-}
-
 bool Node::isUserActionElementInActiveChain() const
 {
     ASSERT(isUserActionElement());
index 40d068f..7f47442 100644 (file)
@@ -358,7 +358,6 @@ public:
     bool isUserActionElement() const { return getFlag(IsUserActionElement); }
     void setUserActionElement(bool flag) { setFlag(flag, IsUserActionElement); }
 
-    bool active() const { return isUserActionElement() && isUserActionElementActive(); }
     bool inActiveChain() const { return isUserActionElement() && isUserActionElementInActiveChain(); }
 
     bool attached() const { return getFlag(IsAttachedFlag); }
@@ -397,8 +396,6 @@ public:
     void lazyAttach(ShouldSetAttached = SetAttached);
     void lazyReattach(ShouldSetAttached = SetAttached);
 
-    virtual void setActive(bool flag = true, bool pause = false);
-
     enum UserSelectAllTreatment {
         UserSelectAllDoesNotAffectEditability,
         UserSelectAllIsAlwaysNonEditable
@@ -773,9 +770,7 @@ private:
     bool rendererIsEditable(EditableLevel, UserSelectAllTreatment = UserSelectAllIsAlwaysNonEditable) const;
     bool isEditableToAccessibility(EditableLevel) const;
 
-    bool isUserActionElementActive() const;
     bool isUserActionElementInActiveChain() const;
-    bool isUserActionElementFocused() const;
 
     void setStyleChange(StyleChangeType);
 
index 125ff0d..09bc25f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -43,11 +44,11 @@ public:
     static PassOwnPtr<UserActionElementSet> create() { return adoptPtr(new UserActionElementSet()); }
 
     bool isFocused(const Element* element) { return hasFlags(element, IsFocusedFlag); }
-    bool isActive(const Node* node) { return hasFlags(node, IsActiveFlag); }
+    bool isActive(const Element* element) { return hasFlags(element, IsActiveFlag); }
     bool isInActiveChain(const Node* node) { return hasFlags(node, InActiveChainFlag); }
     bool isHovered(const Element* element) { return hasFlags(element, IsHoveredFlag); }
     void setFocused(Element* element, bool enable) { setFlags(element, enable, IsFocusedFlag); }
-    void setActive(Node* node, bool enable) { setFlags(node, enable, IsActiveFlag); }
+    void setActive(Element* element, bool enable) { setFlags(element, enable, IsActiveFlag); }
     void setInActiveChain(Node* node, bool enable) { setFlags(node, enable, InActiveChainFlag); }
     void setHovered(Element* element, bool enable) { setFlags(element, enable, IsHoveredFlag); }
 
index f0b5b5e..988e8db 100644 (file)
@@ -215,7 +215,7 @@ void HTMLAnchorElement::setActive(bool down, bool pause)
 
     }
     
-    ContainerNode::setActive(down, pause);
+    HTMLElement::setActive(down, pause);
 }
 
 void HTMLAnchorElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
index b370ea6..07fb3f6 100644 (file)
@@ -112,7 +112,7 @@ private:
     virtual bool isMouseFocusable() const OVERRIDE;
     virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE;
     virtual void defaultEventHandler(Event*);
-    virtual void setActive(bool active = true, bool pause = false);
+    virtual void setActive(bool active = true, bool pause = false) OVERRIDE FINAL;
     virtual void accessKeyAction(bool sendMouseEvents);
     virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
     virtual bool canStartSelection() const;
index 1458158..3e6debe 100644 (file)
@@ -46,7 +46,7 @@ private:
     virtual void accessKeyAction(bool sendMouseEvents);
 
     // Overridden to update the hover/active state of the corresponding control.
-    virtual void setActive(bool = true, bool pause = false);
+    virtual void setActive(bool = true, bool pause = false) OVERRIDE;
     virtual void setHovered(bool = true) OVERRIDE;
 
     // Overridden to either click() or focus() the corresponding control.
index f0ff32c..8925183 100644 (file)
@@ -169,7 +169,7 @@ protected:
     virtual bool isForwardButton() const = 0;
 
 private:
-    void setActive(bool /*flag*/ = true, bool /*pause*/ = false);
+    void setActive(bool /*flag*/ = true, bool /*pause*/ = false) OVERRIDE FINAL;
 
     void startTimer();
     void stopTimer();
index 668b624..55b72b0 100644 (file)
@@ -594,7 +594,7 @@ QColor RenderThemeQt::getMediaControlForegroundColor(RenderObject* o) const
     if (!o)
         return fgColor;
 
-    if (o->node()->active())
+    if (o->node() && o->node()->isElementNode() && toElement(o->node())->active())
         fgColor = fgColor.lighter();
 
     if (!mediaElementCanPlay(o))
index 8077f55..74f8ad9 100644 (file)
@@ -805,19 +805,20 @@ bool RenderTheme::isFocused(const RenderObject* o) const
 
 bool RenderTheme::isPressed(const RenderObject* o) const
 {
-    if (!o->node())
+    if (!o->node() || !o->node()->isElementNode())
         return false;
-    return o->node()->active();
+    return toElement(o->node())->active();
 }
 
 bool RenderTheme::isSpinUpButtonPartPressed(const RenderObject* o) const
 {
     Node* node = o->node();
-    if (!node || !node->active() || !node->isElementNode()
-        || !toElement(node)->isSpinButtonElement())
+    if (!node || !node->isElementNode())
         return false;
-    SpinButtonElement* element = static_cast<SpinButtonElement*>(node);
-    return element->upDownState() == SpinButtonElement::Up;
+    Element* element = toElement(node);
+    if (!element->active() || !element->isSpinButtonElement())
+        return false;
+    return static_cast<SpinButtonElement*>(element)->upDownState() == SpinButtonElement::Up;
 }
 
 bool RenderTheme::isReadOnlyControl(const RenderObject* o) const
index 5636744..c617c03 100644 (file)
@@ -252,7 +252,7 @@ static unsigned getMediaUIPartStateFlags(Node* node)
 
     if (isDisabledFormControl(node))
         flags |= MediaUIPartDisabledFlag;
-    else if (node->active())
+    else if (node->isElementNode() && toElement(node)->active())
         flags |= MediaUIPartPressedFlag;
     return flags;
 }
@@ -975,7 +975,7 @@ void RenderThemeMac::updateFocusedState(NSCell* cell, const RenderObject* o)
 void RenderThemeMac::updatePressedState(NSCell* cell, const RenderObject* o)
 {
     bool oldPressed = [cell isHighlighted];
-    bool pressed = (o->node() && o->node()->active());
+    bool pressed = o->node() && o->node()->isElementNode() && toElement(o->node())->active();
     if (pressed != oldPressed)
         [cell setHighlighted:pressed];
 }