REGRESSION: Click on focused link should not remove focus on it.

This is a regression by wkrev.com/72796.

The first isMouseFocusable call in EventHandler::dispatchMouseEvent 
should be isFocusable because we need to do different things for
focusable-but-non-mouse-focusable elements.

Also fix wrong usage of isMouseFocusable in text shadow elements and
SVG elements. In general isFocusable must return true whenever
isMouseFocusable is true. Some layout tests fail without these changes.

BUG=264575

Review URL: https://chromiumcodereview.appspot.com/20670002

git-svn-id: svn://svn.chromium.org/blink/trunk@155083 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/events/focus-click-on-non-mouse-focusable-element-expected.txt b/LayoutTests/fast/events/focus-click-on-non-mouse-focusable-element-expected.txt
new file mode 100644
index 0000000..f169a8d
--- /dev/null
+++ b/LayoutTests/fast/events/focus-click-on-non-mouse-focusable-element-expected.txt
@@ -0,0 +1,11 @@
+Click on a focused anchor element should not change focus, and click on a non-focused anchor element should remove focus of another element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.activeElement is a
+PASS document.activeElement is document.body
+PASS successfullyParsed is true
+
+TEST COMPLETE
+link 
diff --git a/LayoutTests/fast/events/focus-click-on-non-mouse-focusable-element.html b/LayoutTests/fast/events/focus-click-on-non-mouse-focusable-element.html
new file mode 100644
index 0000000..2053695
--- /dev/null
+++ b/LayoutTests/fast/events/focus-click-on-non-mouse-focusable-element.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<body>
+<a href="#foo" onclick="return false;">link</a>
+<input>
+<script src="../js/resources/js-test-pre.js"></script>
+<script>
+description('Click on a focused anchor element should not change focus, and click on a non-focused anchor element should remove focus of another element.');
+jsTestIsAsync = true;
+var a = document.querySelector('a');
+var input = document.querySelector('input');
+window.onload = function() {
+    a.focus();
+    shouldBe('document.activeElement', 'a', true);
+    eventSender.mouseMoveTo(a.offsetLeft + a.offsetWidth / 2, a.offsetTop + a.offsetHeight / 2);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    shouldBe('document.activeElement', 'a');
+
+    input.focus();
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    shouldBe('document.activeElement', 'document.body');
+
+    finishJSTest();
+};
+</script>
+<script src="../js/resources/js-test-post.js"></script>
+</body>
diff --git a/Source/core/html/shadow/TextControlInnerElements.h b/Source/core/html/shadow/TextControlInnerElements.h
index 76d9123..f3f6a8c 100644
--- a/Source/core/html/shadow/TextControlInnerElements.h
+++ b/Source/core/html/shadow/TextControlInnerElements.h
@@ -52,7 +52,7 @@
     virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
 
 private:
-    virtual bool isMouseFocusable() const { return false; }
+    virtual bool supportsFocus() const OVERRIDE { return false; }
 };
 
 class TextControlInnerTextElement FINAL : public HTMLDivElement {
@@ -65,7 +65,7 @@
     TextControlInnerTextElement(Document*);
     virtual RenderObject* createRenderer(RenderStyle*);
     virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
-    virtual bool isMouseFocusable() const { return false; }
+    virtual bool supportsFocus() const OVERRIDE { return false; }
 };
 
 class SearchFieldDecorationElement FINAL : public HTMLDivElement {
@@ -78,7 +78,7 @@
 private:
     SearchFieldDecorationElement(Document*);
     virtual const AtomicString& shadowPseudoId() const;
-    virtual bool isMouseFocusable() const { return false; }
+    virtual bool supportsFocus() const OVERRIDE { return false; }
 };
 
 class SearchFieldCancelButtonElement FINAL : public HTMLDivElement {
@@ -91,7 +91,7 @@
 private:
     SearchFieldCancelButtonElement(Document*);
     virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
-    virtual bool isMouseFocusable() const { return false; }
+    virtual bool supportsFocus() const OVERRIDE { return false; }
 
     bool m_capturing;
 };
diff --git a/Source/core/page/EventHandler.cpp b/Source/core/page/EventHandler.cpp
index 2e738ef..5e64e1c 100644
--- a/Source/core/page/EventHandler.cpp
+++ b/Source/core/page/EventHandler.cpp
@@ -2034,7 +2034,7 @@
 
         // Walk up the DOM tree to search for a node to focus.
         while (node) {
-            if (node->isMouseFocusable()) {
+            if (node->isFocusable()) {
                 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
                 // node on mouse down if it's selected and inside a focused node. It will be
                 // focused if the user does a mouseup over it, however, because the mouseup
diff --git a/Source/core/svg/SVGCircleElement.h b/Source/core/svg/SVGCircleElement.h
index 17724fe..25b5d88 100644
--- a/Source/core/svg/SVGCircleElement.h
+++ b/Source/core/svg/SVGCircleElement.h
@@ -37,7 +37,7 @@
     SVGCircleElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGElement.cpp b/Source/core/svg/SVGElement.cpp
index 085e5f6..70cb071 100644
--- a/Source/core/svg/SVGElement.cpp
+++ b/Source/core/svg/SVGElement.cpp
@@ -640,6 +640,18 @@
     return svgRareData()->overrideComputedStyle(this, parentStyle);
 }
 
+bool SVGElement::hasFocusEventListeners() const
+{
+    // FIXME: EventTarget::hasEventListeners should be const.
+    SVGElement* mutableThis = const_cast<SVGElement*>(this);
+    return mutableThis->hasEventListeners(eventNames().focusinEvent) || mutableThis->hasEventListeners(eventNames().focusoutEvent);
+}
+
+bool SVGElement::isKeyboardFocusable(KeyboardEvent*) const
+{
+    return isFocusable();
+}
+
 #ifndef NDEBUG
 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
 {
diff --git a/Source/core/svg/SVGElement.h b/Source/core/svg/SVGElement.h
index bb37756..a0e81b2 100644
--- a/Source/core/svg/SVGElement.h
+++ b/Source/core/svg/SVGElement.h
@@ -136,6 +136,7 @@
     SVGElementRareData* ensureSVGRareData();
 
     void reportAttributeParsingError(SVGParsingError, const QualifiedName&, const AtomicString&);
+    bool hasFocusEventListeners() const;
 
 private:
     friend class SVGElementInstance;
@@ -147,7 +148,7 @@
     RenderStyle* computedStyle(PseudoId = NOPSEUDO);
     virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); }
     virtual void willRecalcStyle(StyleChange) OVERRIDE;
-
+    virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE;
     virtual bool rendererIsNeeded(const NodeRenderingContext&) { return false; }
 
     virtual bool isSupported(StringImpl* feature, StringImpl* version) const;
diff --git a/Source/core/svg/SVGEllipseElement.h b/Source/core/svg/SVGEllipseElement.h
index b5de223..c341e14 100644
--- a/Source/core/svg/SVGEllipseElement.h
+++ b/Source/core/svg/SVGEllipseElement.h
@@ -37,7 +37,7 @@
     SVGEllipseElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGGElement.h b/Source/core/svg/SVGGElement.h
index fa64a9f..9acf1ac 100644
--- a/Source/core/svg/SVGGElement.h
+++ b/Source/core/svg/SVGGElement.h
@@ -39,7 +39,7 @@
 
 private:
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGImageElement.h b/Source/core/svg/SVGImageElement.h
index 1ef658b1..1573668 100644
--- a/Source/core/svg/SVGImageElement.h
+++ b/Source/core/svg/SVGImageElement.h
@@ -42,7 +42,7 @@
     SVGImageElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGLineElement.h b/Source/core/svg/SVGLineElement.h
index 2deed76..f90960a 100644
--- a/Source/core/svg/SVGLineElement.h
+++ b/Source/core/svg/SVGLineElement.h
@@ -37,7 +37,7 @@
     SVGLineElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGPathElement.h b/Source/core/svg/SVGPathElement.h
index 496472d..6e1ea50 100644
--- a/Source/core/svg/SVGPathElement.h
+++ b/Source/core/svg/SVGPathElement.h
@@ -101,7 +101,7 @@
     SVGPathElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGPolyElement.h b/Source/core/svg/SVGPolyElement.h
index 5f735be..f7bb439 100644
--- a/Source/core/svg/SVGPolyElement.h
+++ b/Source/core/svg/SVGPolyElement.h
@@ -44,7 +44,7 @@
 
 private:
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGRectElement.h b/Source/core/svg/SVGRectElement.h
index e3a7118..eaf2c1f 100644
--- a/Source/core/svg/SVGRectElement.h
+++ b/Source/core/svg/SVGRectElement.h
@@ -38,7 +38,7 @@
     SVGRectElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGSVGElement.h b/Source/core/svg/SVGSVGElement.h
index d7532d8..fca2053 100644
--- a/Source/core/svg/SVGSVGElement.h
+++ b/Source/core/svg/SVGSVGElement.h
@@ -50,7 +50,7 @@
     using SVGGraphicsElement::deref;
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     // 'SVGSVGElement' functions
     const AtomicString& contentScriptType() const;
diff --git a/Source/core/svg/SVGStyledElement.cpp b/Source/core/svg/SVGStyledElement.cpp
index 5f57599..03a7bdf 100644
--- a/Source/core/svg/SVGStyledElement.cpp
+++ b/Source/core/svg/SVGStyledElement.cpp
@@ -469,17 +469,4 @@
     }
 }
 
-bool SVGStyledElement::isMouseFocusable() const
-{
-    if (!isFocusable())
-        return false;
-    Element* eventTarget = const_cast<SVGStyledElement *>(this);
-    return eventTarget->hasEventListeners(eventNames().focusinEvent) || eventTarget->hasEventListeners(eventNames().focusoutEvent);
-}
-
-bool SVGStyledElement::isKeyboardFocusable(KeyboardEvent*) const
-{
-    return isMouseFocusable();
-}
-
 }
diff --git a/Source/core/svg/SVGStyledElement.h b/Source/core/svg/SVGStyledElement.h
index 56fc504..863af84 100644
--- a/Source/core/svg/SVGStyledElement.h
+++ b/Source/core/svg/SVGStyledElement.h
@@ -80,9 +80,6 @@
 private:
     virtual bool isSVGStyledElement() const OVERRIDE { return true; }
 
-    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
-    virtual bool isMouseFocusable() const;
-
     void buildPendingResourcesIfNeeded();
 
     HashSet<SVGStyledElement*> m_elementsWithRelativeLengths;
diff --git a/Source/core/svg/SVGSwitchElement.h b/Source/core/svg/SVGSwitchElement.h
index 7b82311..99cf956 100644
--- a/Source/core/svg/SVGSwitchElement.h
+++ b/Source/core/svg/SVGSwitchElement.h
@@ -36,7 +36,7 @@
     SVGSwitchElement(const QualifiedName&, Document*);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
 
diff --git a/Source/core/svg/SVGSymbolElement.h b/Source/core/svg/SVGSymbolElement.h
index 4319213..a7eea44 100644
--- a/Source/core/svg/SVGSymbolElement.h
+++ b/Source/core/svg/SVGSymbolElement.h
@@ -39,7 +39,7 @@
 private:
     SVGSymbolElement(const QualifiedName&, Document*);
 
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
diff --git a/Source/core/svg/SVGTextElement.h b/Source/core/svg/SVGTextElement.h
index 6765d0c..95be00e 100644
--- a/Source/core/svg/SVGTextElement.h
+++ b/Source/core/svg/SVGTextElement.h
@@ -34,7 +34,7 @@
 private:
     SVGTextElement(const QualifiedName&, Document*);
 
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     virtual RenderObject* createRenderer(RenderStyle*);
     virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
diff --git a/Source/core/svg/SVGUseElement.h b/Source/core/svg/SVGUseElement.h
index e35322c..6bd1fb6 100644
--- a/Source/core/svg/SVGUseElement.h
+++ b/Source/core/svg/SVGUseElement.h
@@ -54,7 +54,7 @@
     SVGUseElement(const QualifiedName&, Document*, bool wasInsertedByParser);
 
     virtual bool isValid() const { return SVGTests::isValid(); }
-    virtual bool supportsFocus() const { return true; }
+    virtual bool supportsFocus() const OVERRIDE { return hasFocusEventListeners(); }
 
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void removedFrom(ContainerNode*) OVERRIDE;