Implement Element.matches(selectors)

http://dom.spec.whatwg.org/#dom-element-matches

No tested browser (Firefox Nightly, IE11 Release Preview, Opera 12.16)
has implemented the unprefixed API yet.

Having verified that the other browsers throw an exception for
*MatchesSelector(), make the argument to webkitMatchesSelector()
non-optional to align with them and the unprefixed API.

The spec requires throwing a TypeError when parsing the selectors
fails, but we currently throw a SyntaxError. So do the other browsers
for *MatchesSelector(), so file a spec bug instead of changing it:
https://www.w3.org/Bugs/Public/show_bug.cgi?id=24028

BUG=326652

Review URL: https://codereview.chromium.org/106983004

git-svn-id: svn://svn.chromium.org/blink/trunk@163442 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/dom/Element/matches-expected.txt b/LayoutTests/fast/dom/Element/matches-expected.txt
new file mode 100644
index 0000000..5f31448
--- /dev/null
+++ b/LayoutTests/fast/dom/Element/matches-expected.txt
@@ -0,0 +1,18 @@
+PASS element.matches() threw exception TypeError: Failed to execute 'matches' on 'Element': 1 argument required, but only 0 present..
+PASS element.matches('body') is true
+PASS element.matches('html > .foo') is true
+PASS element.matches('html') is false
+PASS element.matches('html > .bar') is false
+PASS element.matches('') threw exception SyntaxError: Failed to execute 'matches' on 'Element': '' is not a valid selector..
+PASS element.matches('!invalid!') threw exception SyntaxError: Failed to execute 'matches' on 'Element': '!invalid!' is not a valid selector..
+PASS element.webkitMatchesSelector() threw exception TypeError: Failed to execute 'webkitMatchesSelector' on 'Element': 1 argument required, but only 0 present..
+PASS element.webkitMatchesSelector('body') is true
+PASS element.webkitMatchesSelector('html > .foo') is true
+PASS element.webkitMatchesSelector('html') is false
+PASS element.webkitMatchesSelector('html > .bar') is false
+PASS element.webkitMatchesSelector('') threw exception SyntaxError: Failed to execute 'webkitMatchesSelector' on 'Element': '' is not a valid selector..
+PASS element.webkitMatchesSelector('!invalid!') threw exception SyntaxError: Failed to execute 'webkitMatchesSelector' on 'Element': '!invalid!' is not a valid selector..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/Element/matches.html b/LayoutTests/fast/dom/Element/matches.html
new file mode 100644
index 0000000..88eb7e7
--- /dev/null
+++ b/LayoutTests/fast/dom/Element/matches.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+</head>
+<body class="foo">
+<script>
+var element = document.body;
+["matches", "webkitMatchesSelector"].forEach(function(func)
+{
+    shouldThrow("element." + func + "()");
+    shouldBeTrue("element." + func + "('body')");
+    shouldBeTrue("element." + func + "('html > .foo')");
+    shouldBeFalse("element." + func + "('html')");
+    shouldBeFalse("element." + func + "('html > .bar')");
+    shouldThrow("element." + func + "('')");
+    shouldThrow("element." + func + "('!invalid!')");
+});
+</script>
+</body>
+</html>
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index f0b7b12..f1c68f7 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -2690,14 +2690,9 @@
     return 0;
 }
 
-bool Element::webkitMatchesSelector(const String& selector, ExceptionState& exceptionState)
+bool Element::matches(const String& selectors, ExceptionState& exceptionState)
 {
-    if (selector.isEmpty()) {
-        exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
-        return false;
-    }
-
-    SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), exceptionState);
+    SelectorQuery* selectorQuery = document().selectorQueryCache().add(selectors, document(), exceptionState);
     if (!selectorQuery)
         return false;
     return selectorQuery->matches(*this);
diff --git a/Source/core/dom/Element.h b/Source/core/dom/Element.h
index 2ff1f47..a95423c 100644
--- a/Source/core/dom/Element.h
+++ b/Source/core/dom/Element.h
@@ -421,7 +421,7 @@
 
     virtual bool matchesReadOnlyPseudoClass() const { return false; }
     virtual bool matchesReadWritePseudoClass() const { return false; }
-    bool webkitMatchesSelector(const String& selectors, ExceptionState&);
+    bool matches(const String& selectors, ExceptionState&);
     virtual bool shouldAppearIndeterminate() const { return false; }
 
     DOMTokenList* classList();
diff --git a/Source/core/dom/Element.idl b/Source/core/dom/Element.idl
index 807ed3b..cbfd8ae 100644
--- a/Source/core/dom/Element.idl
+++ b/Source/core/dom/Element.idl
@@ -62,6 +62,8 @@
     [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, RaisesException=Setter] attribute DOMString prefix;
     [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString localName;
 
+    [RaisesException] boolean matches(DOMString selectors);
+
     // Common extensions
 
     [PerWorldBindings] readonly attribute long offsetLeft;
@@ -103,7 +105,7 @@
     [RaisesException] NodeList querySelectorAll(DOMString selectors);
 
     // WebKit extension
-    [RaisesException, MeasureAs=ElementPrefixedMatchesSelector] boolean webkitMatchesSelector([Default=Undefined] optional DOMString selectors);
+    [RaisesException, ImplementedAs=matches, MeasureAs=ElementPrefixedMatchesSelector] boolean webkitMatchesSelector(DOMString selectors);
 
     // Shadow DOM API
     [RuntimeEnabled=ShadowDOM, Reflect, TreatNullAs=NullString, PerWorldBindings] attribute DOMString pseudo;
diff --git a/Source/core/inspector/InspectorCSSAgent.cpp b/Source/core/inspector/InspectorCSSAgent.cpp
index b369361..da2d87a 100644
--- a/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/Source/core/inspector/InspectorCSSAgent.cpp
@@ -1622,7 +1622,7 @@
             bool matched = false;
             if (elementPseudoId)
                 matched = matchesPseudoElement(selector, elementPseudoId); // Modifies |selector|.
-            matched |= element->webkitMatchesSelector(firstTagHistorySelector->selectorText(), IGNORE_EXCEPTION);
+            matched |= element->matches(firstTagHistorySelector->selectorText(), IGNORE_EXCEPTION);
             if (matched)
                 matchingSelectors->addItem(index);
             ++index;