summaryrefslogtreecommitdiffstats
path: root/layout/inspector
diff options
context:
space:
mode:
Diffstat (limited to 'layout/inspector')
-rw-r--r--layout/inspector/InspectorCSSParser.cpp70
-rw-r--r--layout/inspector/InspectorCSSParser.h47
-rw-r--r--layout/inspector/moz.build2
-rw-r--r--layout/inspector/tests/chrome/chrome.toml2
-rw-r--r--layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html121
5 files changed, 242 insertions, 0 deletions
diff --git a/layout/inspector/InspectorCSSParser.cpp b/layout/inspector/InspectorCSSParser.cpp
new file mode 100644
index 0000000000..bc9cbf1487
--- /dev/null
+++ b/layout/inspector/InspectorCSSParser.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/InspectorCSSParser.h"
+
+#include "mozilla/ServoBindings.h"
+#include "mozilla/ServoStyleConsts.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla::dom {
+
+InspectorCSSParser::InspectorCSSParser(const nsACString& aText)
+ : mInput(aText) {
+ mParserState = Servo_CSSParser_create(&mInput);
+}
+
+UniquePtr<InspectorCSSParser> InspectorCSSParser::Constructor(
+ const GlobalObject& aGlobal, const nsACString& aText) {
+ return MakeUnique<InspectorCSSParser>(aText);
+}
+
+InspectorCSSParser::~InspectorCSSParser() {
+ Servo_CSSParser_destroy(mParserState);
+ mParserState = nullptr;
+}
+
+uint32_t InspectorCSSParser::LineNumber() const { return mLineNumber; }
+
+uint32_t InspectorCSSParser::ColumnNumber() const {
+ // mColumnNumber is 1-based, but consumers expect 0-based.
+ return mColumnNumber - 1;
+}
+
+void InspectorCSSParser::NextToken(Nullable<InspectorCSSToken>& aResult) {
+ StyleCSSToken cssToken;
+ if (!Servo_CSSParser_NextToken(&mInput, mParserState, &cssToken)) {
+ aResult.SetNull();
+
+ mLineNumber = Servo_CSSParser_GetCurrentLine(mParserState);
+ mColumnNumber = Servo_CSSParser_GetCurrentColumn(mParserState);
+
+ return;
+ }
+
+ InspectorCSSToken& inspectorCssToken = aResult.SetValue();
+ inspectorCssToken.mText.Append(cssToken.text);
+ inspectorCssToken.mTokenType.Append(cssToken.token_type);
+ if (cssToken.has_value) {
+ inspectorCssToken.mValue.Append(cssToken.value);
+ } else {
+ inspectorCssToken.mValue.SetIsVoid(true);
+ }
+ if (cssToken.has_unit) {
+ inspectorCssToken.mUnit.Append(cssToken.unit);
+ } else {
+ inspectorCssToken.mUnit.SetIsVoid(true);
+ }
+ if (cssToken.has_number) {
+ // Reduce precision to avoid floating point inprecision
+ inspectorCssToken.mNumber = round(cssToken.number * 100) / 100.0;
+ }
+
+ mLineNumber = cssToken.line;
+ mColumnNumber = cssToken.column;
+}
+
+} // namespace mozilla::dom
diff --git a/layout/inspector/InspectorCSSParser.h b/layout/inspector/InspectorCSSParser.h
new file mode 100644
index 0000000000..e11bc9a898
--- /dev/null
+++ b/layout/inspector/InspectorCSSParser.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef InspectorCSSParser_h___
+#define InspectorCSSParser_h___
+
+#include "mozilla/dom/InspectorUtilsBinding.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+
+namespace mozilla {
+
+class StyleParserState;
+
+namespace dom {
+
+class InspectorCSSParser final : public NonRefcountedDOMObject {
+ public:
+ explicit InspectorCSSParser(const nsACString&);
+ // The WebIDL constructor.
+ static UniquePtr<InspectorCSSParser> Constructor(const GlobalObject& aGlobal,
+ const nsACString& aText);
+
+ ~InspectorCSSParser();
+
+ bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
+ JS::MutableHandle<JSObject*> aReflector) {
+ return InspectorCSSParser_Binding::Wrap(aCx, this, aGivenProto, aReflector);
+ }
+
+ uint32_t LineNumber() const;
+ uint32_t ColumnNumber() const;
+ void NextToken(Nullable<InspectorCSSToken>& aResult);
+
+ private:
+ const nsCString mInput;
+ StyleParserState* mParserState;
+ uint32_t mLineNumber = 0;
+ uint32_t mColumnNumber = 0;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* InspectorCSSParser_h___ */
diff --git a/layout/inspector/moz.build b/layout/inspector/moz.build
index 45d31eb090..9a6634204c 100644
--- a/layout/inspector/moz.build
+++ b/layout/inspector/moz.build
@@ -19,6 +19,7 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.dom += [
+ "InspectorCSSParser.h",
"InspectorFontFace.h",
"InspectorUtils.h",
]
@@ -26,6 +27,7 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
"inDeepTreeWalker.cpp",
"inLayoutUtils.cpp",
+ "InspectorCSSParser.cpp",
"InspectorFontFace.cpp",
"InspectorUtils.cpp",
"ServoStyleRuleMap.cpp",
diff --git a/layout/inspector/tests/chrome/chrome.toml b/layout/inspector/tests/chrome/chrome.toml
index 193be351cb..4326401918 100644
--- a/layout/inspector/tests/chrome/chrome.toml
+++ b/layout/inspector/tests/chrome/chrome.toml
@@ -14,6 +14,8 @@ support-files = ["test_bug708874.css"]
["test_bug727834.xhtml"]
support-files = ["test_bug727834.css"]
+["test_CSSStyleRule_querySelectorAll.html"]
+
["test_fontFaceGeneric.xhtml"]
["test_fontFaceRanges.xhtml"]
diff --git a/layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html b/layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html
new file mode 100644
index 0000000000..dcddc5744b
--- /dev/null
+++ b/layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Test CSSStyleRule::QuerySelectorAll</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <style>
+ .test-simple {
+ }
+ .test-nested-parent {
+ .test-nested-child {
+ .test-nested-and-non-nested {
+ }
+ }
+ }
+ .test-nested-and-non-nested {
+ }
+ .test-no-match {
+ }
+ </style>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+
+ function doTest() {
+ let { cssRules } = document.styleSheets[1];
+
+ info("Testing simple case");
+ let rule = cssRules[0];
+ let result = rule.querySelectorAll(document);
+ is(result.length, 2, `2 elements are matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "a",
+ `Got expected id for first element matching "${rule.selectorText}"`
+ );
+ is(
+ result[1].id,
+ "b",
+ `Got expected id for second element matching "${rule.selectorText}"`
+ );
+
+ info("Testing nested rule");
+ rule = cssRules[1].cssRules[0];
+ result = rule.querySelectorAll(document);
+ is(result.length, 1, `1 element is matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "d",
+ `Got expected id for element matching "${rule.selectorText}"`
+ );
+
+ info("Testing multi-level deep nested rule");
+ rule = cssRules[1].cssRules[0].cssRules[0];
+ result = rule.querySelectorAll(document);
+ // Check that we're not retrieving `f`, as the rule selectorText is `.test-nested-and-non-nested`,
+ // but it is nested inside `.test-nested-child`.
+ is(result.length, 1, `1 element is matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "e",
+ `Got expected id for element matching "${rule.selectorText}"`
+ );
+
+ info(
+ "Testing rule matching multiple elements with the same class, some nested, some not"
+ );
+ rule = cssRules[2];
+ result = rule.querySelectorAll(document);
+ is(result.length, 2, `2 elements are matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "e",
+ `Got expected id for first element matching "${rule.selectorText}"`
+ );
+ is(
+ result[1].id,
+ "f",
+ `Got expected id for second element matching "${rule.selectorText}"`
+ );
+
+ info("Testing that search results are limited by the passed root node");
+ rule = cssRules[2];
+ result = rule.querySelectorAll(document.querySelector("#c"));
+ is(
+ result.length,
+ 1,
+ `An element is matching "${rule.selectorText}" in #c`
+ );
+ is(
+ result[0].id,
+ "e",
+ `Got expected id for element matching "${rule.selectorText}"`
+ );
+
+ info("Testing rule with no matching elements");
+ rule = cssRules[3];
+ result = rule.querySelectorAll(document);
+ is(result.length, 0, `No elements matching "${rule.selectorText}"`);
+
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Test CSSStyleRule::QuerySelectorAll</h1>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ <div id="a" class="test-simple"></div>
+ <div id="b" class="test-simple"></div>
+ <div id="c" class="test-nested-parent">
+ <span id="d" class="test-nested-child">
+ <b id="e" class="test-nested-and-non-nested"></b>
+ </span>
+ </div>
+ <b id="f" class="test-nested-and-non-nested"></b>
+ </div>
+ <pre id="test"></pre>
+ </body>
+</html>