Bug 1919853 - Make InspectorUtils able to return CSSNestedDeclarations too. r=devtools-reviewers,nchevobbe,dshin

Rename getCSSStyleRules now that it can return something else, and
change getCSSStyleRules_starting_style.html to cover this again.

Unfortunately the asserts in ServoStyleRuleMap.cpp no longer hold,
because the style attribute and other declarations are expected not to
show up there.

Differential Revision: https://phabricator.services.mozilla.com/D222856
This commit is contained in:
Emilio Cobos Álvarez 2024-09-20 15:59:53 +00:00
Родитель ecc5c26f1d
Коммит 4a5f0fcca1
49 изменённых файлов: 200 добавлений и 260 удалений

Просмотреть файл

@ -200,7 +200,7 @@ const rollouts = [
"gfx/layers/layerviewer/layerTreeView.js",
"intl/uconv/tests/unit/test_charset_conversion.js",
"js/src/builtin/**",
"layout/inspector/tests/test_getCSSStyleRules.html",
"layout/inspector/tests/test_getMatchingCSSRules.html",
"layout/inspector/tests/test_is_valid_css_color.html",
"layout/style/test/property_database.js",
"layout/style/test/test_computed_style_grid_with_pseudo.html",

Просмотреть файл

@ -12,7 +12,7 @@ loader.lazyRequireGetter(
);
loader.lazyRequireGetter(
this,
"getCSSStyleRules",
"getMatchingCSSRules",
"resource://devtools/shared/inspector/css-logic.js",
true
);
@ -45,9 +45,6 @@ const {
},
} = require("resource://devtools/shared/constants.js");
// Specified by the author CSS rule type.
const STYLE_RULE = 1;
// Accessible action for showing long description.
const CLICK_ACTION = "click";
@ -167,19 +164,15 @@ function hasStylesForFocusRelatedPseudoClass(
currentNode,
pseudoClass
) {
const defaultRules = getCSSStyleRules(currentNode);
const defaultRules = getMatchingCSSRules(currentNode);
InspectorUtils.addPseudoClassLock(focusableNode, pseudoClass);
// Determine a set of properties that are specific to CSS rules that are only
// present when a focus related pseudo-class is locked in.
const tempRules = getCSSStyleRules(currentNode);
const tempRules = getMatchingCSSRules(currentNode);
const properties = new Set();
for (const rule of tempRules) {
if (rule.type !== STYLE_RULE) {
continue;
}
if (!defaultRules.includes(rule)) {
for (let index = 0; index < rule.style.length; index++) {
properties.add(rule.style.item(index));

Просмотреть файл

@ -17,7 +17,7 @@ const {
getCurrentZoom,
} = require("resource://devtools/shared/layout/utils.js");
const {
getCSSStyleRules,
getMatchingCSSRules,
} = require("resource://devtools/shared/inspector/css-logic.js");
const GEOMETRY_LABEL_SIZE = 6;
@ -139,13 +139,13 @@ function getDefinedGeometryProperties(node) {
}
// Get the list of css rules applying to the current node.
const cssRules = getCSSStyleRules(node);
const cssRules = getMatchingCSSRules(node);
for (let i = 0; i < cssRules.length; i++) {
const rule = cssRules[i];
for (const name of GeoProp.allProps()) {
const value = rule.style.getPropertyValue(name);
if (value && value !== "auto") {
// getCSSStyleRules returns rules ordered from least to most specific
// getMatchingCSSRules returns rules ordered from least to most specific
// so just override any previous properties we have set.
props.set(name, {
cssRule: rule,

Просмотреть файл

@ -36,7 +36,7 @@ const {
} = require("resource://devtools/shared/layout/dom-matrix-2d.js");
const EventEmitter = require("resource://devtools/shared/event-emitter.js");
const {
getCSSStyleRules,
getMatchingCSSRules,
} = require("resource://devtools/shared/inspector/css-logic.js");
const BASE_MARKER_SIZE = 5;
@ -2991,7 +2991,7 @@ function getDefinedShapeProperties(node, property) {
return prop;
}
const cssRules = getCSSStyleRules(node);
const cssRules = getMatchingCSSRules(node);
for (let i = 0; i < cssRules.length; i++) {
const rule = cssRules[i];
const value = rule.style.getPropertyValue(property);

Просмотреть файл

@ -30,7 +30,7 @@
const nodeConstants = require("resource://devtools/shared/dom-node-constants.js");
const {
getBindingElementAndPseudo,
getCSSStyleRules,
getMatchingCSSRules,
hasVisitedState,
isAgentStylesheet,
isAuthorStylesheet,
@ -586,7 +586,7 @@ class CssLogic {
this.viewedElement === element ? STATUS.MATCHED : STATUS.PARENT_MATCH;
try {
domRules = getCSSStyleRules(element);
domRules = getMatchingCSSRules(element);
} catch (ex) {
console.log("CL__buildMatchedRules error: " + ex);
continue;
@ -601,17 +601,13 @@ class CssLogic {
this._matchedRules.push([rule, status, distance]);
}
// getCSSStyleRules can return null with a shadow DOM element.
// getMatchingCSSRules can return null with a shadow DOM element.
if (domRules !== null) {
// getCSSStyleRules returns ordered from least-specific to most-specific,
// getMatchingCSSRules returns ordered from least-specific to most-specific,
// but we do want them from most-specific to least specific, so we need to loop
// through the rules backward.
for (let i = domRules.length - 1; i >= 0; i--) {
const domRule = domRules[i];
if (!CSSStyleRule.isInstance(domRule)) {
continue;
}
const sheet = this.getSheet(domRule.parentStyleSheet, -1);
if (sheet._passId !== this._passId) {
sheet.index = sheetIndex++;
@ -1541,7 +1537,7 @@ class CssSelectorInfo {
/**
* Compare the current CssSelectorInfo instance to another instance.
* Since selectorInfos is computed from `InspectorUtils.getCSSStyleRules`,
* Since selectorInfos is computed from `InspectorUtils.getMatchingCSSRules`,
* it's already sorted for regular cases. We only need to handle important values.
*
* @param {CssSelectorInfo} that

Просмотреть файл

@ -30,7 +30,7 @@ loader.lazyRequireGetter(
);
loader.lazyRequireGetter(
this,
"getCSSStyleRules",
"getMatchingCSSRules",
"resource://devtools/shared/inspector/css-logic.js",
true
);
@ -205,7 +205,7 @@ class FlexItemActor extends Actor {
if (isElementNode) {
for (const name in properties) {
const values = [];
const cssRules = getCSSStyleRules(this.element);
const cssRules = getMatchingCSSRules(this.element);
for (const rule of cssRules) {
// For each rule, go through *all* properties, because there may be several of

Просмотреть файл

@ -842,7 +842,7 @@ class PageStyleActor extends Actor {
// we don't need to retrieve inherited starting style rules
const includeStartingStyleRules =
!inherited && DISPLAY_STARTING_STYLE_RULES;
const domRules = InspectorUtils.getCSSStyleRules(
const domRules = InspectorUtils.getMatchingCSSRules(
node,
pseudo,
CssLogic.hasVisitedState(node),
@ -857,7 +857,7 @@ class PageStyleActor extends Actor {
const doc = this.inspector.targetActor.window.document;
// getCSSStyleRules returns ordered from least-specific to
// getMatchingCSSRules returns ordered from least-specific to
// most-specific.
for (let i = domRules.length - 1; i >= 0; i--) {
const domRule = domRules[i];

Просмотреть файл

@ -559,16 +559,16 @@ function getBindingElementAndPseudo(node) {
exports.getBindingElementAndPseudo = getBindingElementAndPseudo;
/**
* Returns css style rules for a given a node.
* Returns css rules for a given a node.
* This function can handle ::before or ::after pseudo element as well as
* normal element.
*/
function getCSSStyleRules(node) {
function getMatchingCSSRules(node) {
const { bindingElement, pseudo } = getBindingElementAndPseudo(node);
const rules = InspectorUtils.getCSSStyleRules(bindingElement, pseudo);
const rules = InspectorUtils.getMatchingCSSRules(bindingElement, pseudo);
return rules;
}
exports.getCSSStyleRules = getCSSStyleRules;
exports.getMatchingCSSRules = getMatchingCSSRules;
/**
* Returns true if the given node has visited state.

Просмотреть файл

@ -14,7 +14,7 @@
namespace InspectorUtils {
// documentOnly tells whether user and UA sheets should get included.
sequence<StyleSheet> getAllStyleSheets(Document document, optional boolean documentOnly = false);
sequence<CSSStyleRule> getCSSStyleRules(
sequence<CSSRule> getMatchingCSSRules(
Element element,
optional [LegacyNullToEmptyString] DOMString pseudo = "",
optional boolean relevantLinkVisited = false,

Просмотреть файл

@ -31,7 +31,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=416896
var linkedSheet = $("l").sheet;
isnot(linkedSheet, null, "Should have sheet here");
var inspectedRules = InspectorUtils.getCSSStyleRules(document.links[0]);
var inspectedRules = InspectorUtils.getMatchingCSSRules(document.links[0]);
var seenInline = false;
var seenLinked = false;

Просмотреть файл

@ -8499,11 +8499,11 @@ void nsIFrame::ListTextRuns(FILE* out, nsTHashSet<const void*>& aSeen) const {
}
void nsIFrame::ListMatchedRules(FILE* out, const char* aPrefix) const {
nsTArray<const StyleLockedStyleRule*> rawRuleList;
Servo_ComputedValues_GetStyleRuleList(mComputedStyle, &rawRuleList);
for (const StyleLockedStyleRule* rawRule : rawRuleList) {
nsTArray<const StyleLockedDeclarationBlock*> rawDecls;
Servo_ComputedValues_GetMatchingDeclarations(Style(), &rawDecls);
for (const StyleLockedDeclarationBlock* rawRule : rawDecls) {
nsAutoCString ruleText;
Servo_StyleRule_GetCssText(rawRule, &ruleText);
Servo_DeclarationBlock_GetCssText(rawRule, &ruleText);
fprintf_stderr(out, "%s%s\n", aPrefix, ruleText.get());
}
}

Просмотреть файл

@ -250,16 +250,16 @@ static already_AddRefed<const ComputedStyle> GetStartingStyle(
return styleSet->ResolveStartingStyle(aElement);
}
static void GetCSSStyleRulesFromComputedValue(
static void GetCSSRulesFromComputedValues(
Element& aElement, const ComputedStyle* aComputedStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult) {
nsTArray<RefPtr<css::Rule>>& aResult) {
const PresShell* presShell = aElement.OwnerDoc()->GetPresShell();
if (!presShell) {
return;
}
AutoTArray<const StyleLockedStyleRule*, 8> rawRuleList;
Servo_ComputedValues_GetStyleRuleList(aComputedStyle, &rawRuleList);
AutoTArray<const StyleLockedDeclarationBlock*, 8> rawDecls;
Servo_ComputedValues_GetMatchingDeclarations(aComputedStyle, &rawDecls);
AutoTArray<ServoStyleRuleMap*, 8> maps;
{
@ -295,41 +295,23 @@ static void GetCSSStyleRulesFromComputedValue(
}
// Find matching rules in the table.
for (const StyleLockedStyleRule* rawRule : Reversed(rawRuleList)) {
CSSStyleRule* rule = nullptr;
for (const StyleLockedDeclarationBlock* rawDecl : Reversed(rawDecls)) {
for (ServoStyleRuleMap* map : maps) {
rule = map->Lookup(rawRule);
if (rule) {
if (css::Rule* rule = map->Lookup(rawDecl)) {
aResult.AppendElement(rule);
break;
}
}
if (rule) {
aResult.AppendElement(rule);
} else {
#ifdef DEBUG
aElement.Dump();
printf_stderr("\n\n----\n\n");
aComputedStyle->DumpMatchedRules();
nsAutoCString str;
Servo_StyleRule_Debug(rawRule, &str);
printf_stderr("\n\n----\n\n");
printf_stderr("%s\n", str.get());
MOZ_CRASH_UNSAFE_PRINTF(
"We should be able to map raw rule %p to a rule in one of the %zu "
"maps: %s\n",
rawRule, maps.Length(), str.get());
#endif
}
}
}
/* static */
void InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject,
Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
bool aWithStartingStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult) {
void InspectorUtils::GetMatchingCSSRules(GlobalObject& aGlobalObject,
Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
bool aWithStartingStyle,
nsTArray<RefPtr<css::Rule>>& aResult) {
auto [type, functionalPseudoParameter] =
nsCSSPseudoElements::ParsePseudoElement(aPseudo,
CSSEnabledState::ForAllContent);
@ -362,7 +344,7 @@ void InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject,
}
}
GetCSSStyleRulesFromComputedValue(aElement, computedStyle, aResult);
GetCSSRulesFromComputedValues(aElement, computedStyle, aResult);
}
/* static */

Просмотреть файл

@ -41,11 +41,11 @@ class InspectorUtils {
static void GetAllStyleSheets(GlobalObject& aGlobal, Document& aDocument,
bool aDocumentOnly,
nsTArray<RefPtr<StyleSheet>>& aResult);
static void GetCSSStyleRules(GlobalObject& aGlobal, Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
bool aWithStartingStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult);
static void GetMatchingCSSRules(GlobalObject& aGlobal, Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
bool aWithStartingStyle,
nsTArray<RefPtr<css::Rule>>& aResult);
/**
* Get the line number of a rule.

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/dom/CSSImportRule.h"
#include "mozilla/dom/CSSRuleBinding.h"
#include "mozilla/dom/CSSStyleRule.h"
#include "mozilla/dom/CSSNestedDeclarations.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ShadowRoot.h"
@ -118,9 +119,14 @@ size_t ServoStyleRuleMap::SizeOfIncludingThis(
void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
switch (aRule.Type()) {
case StyleCssRuleType::NestedDeclarations: {
auto& rule = static_cast<CSSNestedDeclarations&>(aRule);
mTable.InsertOrUpdate(rule.RawStyle(), &rule);
break;
}
case StyleCssRuleType::Style: {
auto& rule = static_cast<CSSStyleRule&>(aRule);
mTable.InsertOrUpdate(rule.Raw(), &rule);
mTable.InsertOrUpdate(rule.RawStyle(), &rule);
[[fallthrough]];
}
case StyleCssRuleType::LayerBlock:
@ -153,7 +159,6 @@ void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
case StyleCssRuleType::FontFeatureValues:
case StyleCssRuleType::FontPaletteValues:
case StyleCssRuleType::PositionTry:
case StyleCssRuleType::NestedDeclarations:
break;
}
}

Просмотреть файл

@ -7,7 +7,7 @@
#ifndef mozilla_ServoStyleRuleMap_h
#define mozilla_ServoStyleRuleMap_h
#include "mozilla/dom/CSSStyleRule.h"
#include "mozilla/css/Rule.h"
#include "mozilla/StyleSheet.h"
#include "nsTHashMap.h"
@ -23,15 +23,15 @@ class Rule;
namespace dom {
class ShadowRoot;
}
class ServoStyleRuleMap {
class ServoStyleRuleMap final {
public:
ServoStyleRuleMap() = default;
void EnsureTable(ServoStyleSet&);
void EnsureTable(dom::ShadowRoot&);
dom::CSSStyleRule* Lookup(const StyleLockedStyleRule* aRawRule) const {
return mTable.Get(aRawRule);
css::Rule* Lookup(const StyleLockedDeclarationBlock* aDecls) const {
return mTable.Get(aDecls);
}
void SheetAdded(StyleSheet&);
@ -55,8 +55,8 @@ class ServoStyleRuleMap {
void FillTableFromRuleList(ServoCSSRuleList&);
void FillTableFromStyleSheet(StyleSheet&);
using Hashtable = nsTHashMap<nsPtrHashKey<const StyleLockedStyleRule>,
WeakPtr<dom::CSSStyleRule>>;
using Hashtable = nsTHashMap<nsPtrHashKey<const StyleLockedDeclarationBlock>,
WeakPtr<css::Rule>>;
Hashtable mTable;
};

Просмотреть файл

@ -5,7 +5,7 @@
<p></p>
<script>
function start() {
let rules = InspectorUtils.getCSSStyleRules(document.querySelector("p"));
let rules = InspectorUtils.getMatchingCSSRules(document.querySelector("p"));
ok(rules.length > 0, "Should have found some rules");
is(rules[0].type, CSSRule.STYLE_RULE, "Should have found a style rule");

Просмотреть файл

@ -43,7 +43,7 @@
info(description);
const rules =
InspectorUtils.getCSSStyleRules(target, undefined, isVisitedTest);
InspectorUtils.getMatchingCSSRules(target, undefined, isVisitedTest);
ok(getRule(rules, validSelector),
`Rule of ${validSelector} is in rules`);
ok(!getRule(rules, invalidSelector),

Просмотреть файл

@ -1,3 +0,0 @@
<!DOCTYPE html>
<link rel="alternate stylesheet" title="x" href="getCSSStyleRules-1.css">
<unknowntagname></unknowntagname>

Просмотреть файл

@ -1,3 +0,0 @@
<!DOCTYPE html>
<link rel="stylesheet" href="getCSSStyleRules-1.css">
<unknowntagname></unknowntagname>

Просмотреть файл

@ -0,0 +1,3 @@
<!DOCTYPE html>
<link rel="alternate stylesheet" title="x" href="getMatchingCSSRules-1.css">
<unknowntagname></unknowntagname>

Просмотреть файл

@ -0,0 +1,3 @@
<!DOCTYPE html>
<link rel="stylesheet" href="getMatchingCSSRules-1.css">
<unknowntagname></unknowntagname>

Просмотреть файл

@ -46,19 +46,19 @@ support-files = [
["test_getCSSPseudoElementNames.html"]
["test_getCSSStyleRules.html"]
["test_getMatchingCSSRules.html"]
support-files = [
"file_getCSSStyleRules-default.html",
"file_getCSSStyleRules-alternate.html",
"getCSSStyleRules-1.css",
"getCSSStyleRules-2.css",
"file_getMatchingCSSRules-default.html",
"file_getMatchingCSSRules-alternate.html",
"getMatchingCSSRules-1.css",
"getMatchingCSSRules-2.css",
]
["test_getCSSStyleRules_pseudo.html"]
["test_getMatchingCSSRules_pseudo.html"]
["test_getCSSStyleRules_slotted.html"]
["test_getMatchingCSSRules_slotted.html"]
["test_getCSSStyleRules_starting_style.html"]
["test_getMatchingCSSRules_starting_style.html"]
["test_getRegisteredCssHighlights.html"]

Просмотреть файл

@ -23,7 +23,7 @@ const InspectorUtils = SpecialPowers.InspectorUtils;
function do_test() {
try {
InspectorUtils.getCSSStyleRules(null);
InspectorUtils.getMatchingCSSRules(null);
ok(false, "expected an exception");
}
catch(e) {

Просмотреть файл

@ -31,10 +31,10 @@ function do_test() {
var text = body.firstChild;
try {
var res = InspectorUtils.getCSSStyleRules(docElement);
is(res.length, 0, "getCSSStyleRules");
res = InspectorUtils.getCSSStyleRules(body);
is(res.length, 0, "getCSSStyleRules");
var res = InspectorUtils.getMatchingCSSRules(docElement);
is(res.length, 0, "getMatchingCSSRules");
res = InspectorUtils.getMatchingCSSRules(body);
is(res.length, 0, "getMatchingCSSRules");
}
catch(e) { ok(false, "got an unexpected exception:" + e); }

Просмотреть файл

@ -22,7 +22,7 @@ const CI = SpecialPowers.Ci;
const CC = SpecialPowers.Cc;
const InspectorUtils = SpecialPowers.InspectorUtils;
var rules = InspectorUtils.getCSSStyleRules(document.getElementById("display"));
var rules = InspectorUtils.getMatchingCSSRules(document.getElementById("display"));
var firstPRule = rules[rules.length - 2];
firstPRule.style.removeProperty("color");
ok(true, "should not crash");

Просмотреть файл

@ -22,7 +22,7 @@ const CI = SpecialPowers.Ci;
const CC = SpecialPowers.Cc;
const InspectorUtils = SpecialPowers.InspectorUtils;
var rules = InspectorUtils.getCSSStyleRules(document.getElementById("display"));
var rules = InspectorUtils.getMatchingCSSRules(document.getElementById("display"));
var firstPRule = rules[rules.length - 2];
firstPRule.style.removeProperty("color");
ok(true, "should not crash");

Просмотреть файл

@ -68,34 +68,34 @@ function getSelectors (rules) {
var div = document.getElementById("div1");
/* empty or missing pseudo-element argument */
var selectors = getSelectors(InspectorUtils.getCSSStyleRules(div));
var selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div));
is(selectors.length, 1, "psuedo-element argument should be optional");
is(selectors[0], "#div1", "should only have the non-pseudo element rule");
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, ""));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, ""));
is(selectors.length, 1, "pseudo-element argument can be empty string");
is(selectors[0], "#div1", "should only have the non pseudo-element rule");
/* invalid pseudo-element argument */
var rules = InspectorUtils.getCSSStyleRules(div, "not a valid pseudo element");
var rules = InspectorUtils.getMatchingCSSRules(div, "not a valid pseudo element");
is(rules.length, 0, "invalid pseudo-element returns no rules");
/* valid pseudo-element argument */
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, ":first-letter"));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, ":first-letter"));
is(selectors.length, 1, "pseudo-element argument can be used");
is(selectors[0], "#div1::first-letter", "should only have the ::first-letter rule");
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, ":before"));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, ":before"));
is(selectors.length, 2, "::before pseudo-element has two matching rules");
isnot(selectors.indexOf("#div1::after, #div1::before"), -1, "fetched rule for ::before")
isnot(selectors.indexOf("#div1::before"), -1, "fetched rule for ::before")
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, ":first-line"));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, ":first-line"));
is(selectors.length, 0, "valid pseudo-element but no matching rules");
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, "::selection"));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, "::selection"));
is(selectors.length, 1, "::selection pseudo-element has a matching rule");
is(selectors[0], "::selection", "fetched rule for ::selection");
@ -105,11 +105,11 @@ range.setEnd(div.firstChild, 20);
const highlight = new Highlight(range);
CSS.highlights.set("search", highlight);
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, "::highlight(search)"));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, "::highlight(search)"));
is(selectors.length, 1, "::highlight(search) pseudo-element has a matching rule");
is(selectors[0], "::highlight(search)", "fetched ::highlight(search) rule");
selectors = getSelectors(InspectorUtils.getCSSStyleRules(div, "::highlight(whatever)"));
selectors = getSelectors(InspectorUtils.getMatchingCSSRules(div, "::highlight(whatever)"));
is(selectors.length, 1, "::highlight(whatever) pseudo-element has a matching rule");
is(selectors[0], "::highlight(whatever)", "fetched ::highlight(whatever) rule");

Просмотреть файл

@ -10,7 +10,7 @@
<pre id="log">
<script>
/**
* This test checks that getCSSStyleRules returns correct style set in
* This test checks that getMatchingCSSRules returns correct style set in
* various cases. To avoid effects from UA sheets, most of the tests use
* an element with "unknowntagname".
*/
@ -22,14 +22,14 @@ let iframe = document.getElementById("test");
SimpleTest.waitForExplicitFinish();
function* getStyleRules(elem) {
let rules = InspectorUtils.getCSSStyleRules(elem);
let rules = InspectorUtils.getMatchingCSSRules(elem);
for (let i = 0; i < rules.length; i++) {
yield rules[i];
}
}
// This will check that value of z-index property declarations in the
// rules from getCSSStyleRules matches the given content.
// rules from getMatchingCSSRules matches the given content.
function checkRules(doc, rulesContent, queryStr = "unknowntagname") {
let elem = doc.querySelector(queryStr);
let rules = [...getStyleRules(elem)];
@ -52,7 +52,7 @@ const tests = [
checkRules(doc, [1]);
let link = doc.createElement("link");
link.rel = "stylesheet";
link.href = "getCSSStyleRules-2.css";
link.href = "getMatchingCSSRules-2.css";
let load = new Promise(resolve => { link.onload = resolve; });
doc.head.appendChild(link);
await load;
@ -121,7 +121,7 @@ const tests = [
checkRules(doc, [3, 5, 4]);
info("Inserting import rule");
sheet.insertRule("@import url(getCSSStyleRules-2.css);", 0);
sheet.insertRule("@import url(getMatchingCSSRules-2.css);", 0);
// There is no notification we can get when the associated style
// sheet gets loaded, so we have to query it.
while (true) {
@ -189,7 +189,7 @@ add_task(async function runTests() {
if (!test.base) {
test.base = "default";
}
iframe.src = `file_getCSSStyleRules-${test.base}.html`;
iframe.src = `file_getMatchingCSSRules-${test.base}.html`;
await new Promise(resolve => { iframe.onload = resolve; });
try {
await test.run(iframe.contentDocument, iframe.contentWindow);

Просмотреть файл

@ -1,5 +1,5 @@
<!DOCTYPE html>
<title>Test getCSSStyleRules for pseudo elements</title>
<title>Test getMatchingCSSRules for pseudo elements</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
@ -52,12 +52,12 @@ const InspectorUtils = SpecialPowers.InspectorUtils;
function checkPseudoStyleForId(id) {
let element = document.getElementById(id);
let beforeRules = InspectorUtils.getCSSStyleRules(element, ":before");
let beforeRules = InspectorUtils.getMatchingCSSRules(element, ":before");
is (beforeRules.length, 1, "Element " + id + ":before has expected number of rules.");
let beforeDecl = beforeRules[0].style;
is (beforeDecl.content, '":before"', "Element " + id + ":before has expected style content.");
let afterRules = InspectorUtils.getCSSStyleRules(element, ":after");
let afterRules = InspectorUtils.getMatchingCSSRules(element, ":after");
is (afterRules.length, 1, "Element " + id + ":after has expected number of rules.");
let afterDecl = afterRules[0].style;
is (afterDecl.content, '":after"', "Element " + id + ":after has expected style content.");

Просмотреть файл

@ -1,5 +1,5 @@
<!DOCTYPE html>
<title>Test getCSSStyleRules for pseudo elements</title>
<title>Test getMatchingCSSRules for pseudo elements</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
@ -41,7 +41,7 @@
function checkElementRules(id, text, property) {
const element = document.getElementById(id);
let slottedRules = InspectorUtils.getCSSStyleRules(element);
let slottedRules = InspectorUtils.getMatchingCSSRules(element);
is(slottedRules.length, 1, "Slotted element has expected number of rules.");
let slottedText = slottedRules[0].cssText;

Просмотреть файл

@ -1,5 +1,5 @@
<!DOCTYPE HTML>
<title>Test for InspectorUtils.getCSSStyleRules for starting style</title>
<title>Test for InspectorUtils.getMatchingCSSRules for starting style</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
<style>
@ -13,9 +13,7 @@
opacity: 1;
@starting-style {
& {
opacity: 0;
}
opacity: 0;
}
}
@ -28,14 +26,7 @@
background-color: tomato;
@starting-style {
/*
* FIXME(bug 1919853): getCSSStyleRules() doesn't return bare nested
* declarations. Once we figure out the right thing to do there,
* the wrapping `&{}` can go away.
*/
& {
background-color: gold;
}
background-color: gold;
}
}
</style>
@ -44,7 +35,7 @@
<tagnametwo></tagnametwo>
<script>
/**
* This test checks that InspectorUtils.getCSSStyleRules setting
* This test checks that InspectorUtils.getMatchingCSSRules setting
* withStartingStyle:true returns correct style set in various cases.
* To avoid effects from UA sheets, we use an element with "unknowntagname".
*/
@ -56,7 +47,7 @@ add_task(async function testBasic() {
const styleSheet = document.styleSheets[1];
const el = document.querySelector("tagname");
let rules = InspectorUtils.getCSSStyleRules(el, "", false, true);
let rules = InspectorUtils.getMatchingCSSRules(el, "", false, true);
is(rules.length, 3, "Expected rules");
is(
@ -81,7 +72,7 @@ add_task(async function testBasic() {
"Check that starting style rules are not returned when withStartingStyle " +
"param is false"
);
rules = InspectorUtils.getCSSStyleRules(el, "", false);
rules = InspectorUtils.getMatchingCSSRules(el, "", false);
is(rules.length, 1, "Expected rules");
is(
@ -97,7 +88,7 @@ add_task(async function testCombinator() {
const styleSheet = document.styleSheets[1];
const el = document.querySelector("tagnametwo");
const rules = InspectorUtils.getCSSStyleRules(el, "", false, true);
const rules = InspectorUtils.getMatchingCSSRules(el, "", false, true);
is(rules.length, 3, "Got expected rules");
is(

Просмотреть файл

@ -33,9 +33,9 @@
);
is(
InspectorUtils.getCSSStyleRules(spanEl).length,
InspectorUtils.getMatchingCSSRules(spanEl).length,
2,
"getCSSStyleRules returned 2 rules for .mySpan"
"getMatchingCSSRules returned 2 rules for .mySpan"
);
info("Modify stylesheet using InspectorUtils.parseStyleSheet");
@ -66,14 +66,14 @@
"rgb(0, 0, 0)",
"the color of the span element was properly updated"
);
const rules = InspectorUtils.getCSSStyleRules(spanEl);
const rules = InspectorUtils.getMatchingCSSRules(spanEl);
is(
rules.length,
2,
"getCSSStyleRules still returned 2 rules for .mySpan after stylesheet was updated"
"getMatchingCSSRules still returned 2 rules for .mySpan after stylesheet was updated"
);
is(rules[1].style.color, "black", "rule was properly updated");
});
</script>
</body>
</html>
</html>

Просмотреть файл

@ -50,7 +50,7 @@ const InspectorUtils = SpecialPowers.InspectorUtils;
function do_test() {
var element = document.querySelector("#foo");
var elementRules = InspectorUtils.getCSSStyleRules(element);
var elementRules = InspectorUtils.getMatchingCSSRules(element);
var multiSelectorRule = elementRules[2];
is(multiSelectorRule.selectorText, `#foo, #bar, #foo::before`, "Got expected multi-selector rule");
@ -77,7 +77,7 @@ function do_test() {
SimpleTest.finish();
function checkPseudo(pseudo) {
var rules = InspectorUtils.getCSSStyleRules(element, pseudo);
var rules = InspectorUtils.getMatchingCSSRules(element, pseudo);
var rule = rules[rules.length - 1];
is (rule.selectorMatchesElement(0, element), false,

Просмотреть файл

@ -116,6 +116,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSNestedDeclarations,
// Keep this in sync with IsCCLeaf.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
StyleLockedDeclarationBlock* CSSNestedDeclarations::RawStyle() const {
return mDecls.mDecls->Raw();
}
bool CSSNestedDeclarations::IsCCLeaf() const {
if (!css::Rule::IsCCLeaf()) {
return false;

Просмотреть файл

@ -69,6 +69,7 @@ class CSSNestedDeclarations final : public css::Rule {
nsICSSDeclaration* Style() { return &mDecls; }
StyleLockedNestedDeclarationsRule* Raw() const { return mRawRule.get(); }
StyleLockedDeclarationBlock* RawStyle() const;
void SetRawAfterClone(RefPtr<StyleLockedNestedDeclarationsRule>);
// Methods of mozilla::css::Rule

Просмотреть файл

@ -181,6 +181,10 @@ void CSSStyleRule::GetCssText(nsACString& aCssText) const {
/* CSSStyleRule implementation */
StyleLockedDeclarationBlock* CSSStyleRule::RawStyle() const {
return mDecls.mDecls->Raw();
}
void CSSStyleRule::GetSelectorText(nsACString& aSelectorText) {
Servo_StyleRule_GetSelectorText(mRawRule, &aSelectorText);
}

Просмотреть файл

@ -9,7 +9,6 @@
#include "mozilla/css/GroupRule.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/WeakPtr.h"
#include "nsDOMCSSDeclaration.h"
@ -54,7 +53,7 @@ class CSSStyleRuleDeclaration final : public nsDOMCSSDeclaration {
RefPtr<DeclarationBlock> mDecls;
};
class CSSStyleRule final : public css::GroupRule, public SupportsWeakPtr {
class CSSStyleRule final : public css::GroupRule {
public:
CSSStyleRule(already_AddRefed<StyleLockedStyleRule> aRawRule,
StyleSheet* aSheet, css::Rule* aParentRule, uint32_t aLine,
@ -84,6 +83,7 @@ class CSSStyleRule final : public css::GroupRule, public SupportsWeakPtr {
nsICSSDeclaration* Style() { return &mDecls; }
StyleLockedStyleRule* Raw() const { return mRawRule; }
StyleLockedDeclarationBlock* RawStyle() const;
void SetRawAfterClone(RefPtr<StyleLockedStyleRule>);
already_AddRefed<StyleLockedCssRules> GetOrCreateRawRules() final;

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/WeakPtr.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
@ -26,7 +27,7 @@ enum class StyleCssRuleType : uint8_t;
namespace css {
class GroupRule;
class Rule : public nsISupports, public nsWrapperCache {
class Rule : public nsISupports, public nsWrapperCache, public SupportsWeakPtr {
protected:
Rule(StyleSheet* aSheet, Rule* aParentRule, uint32_t aLineNumber,
uint32_t aColumnNumber)

Просмотреть файл

@ -21,7 +21,7 @@
xhr.open('G', '', false)
xhr.send()
SpecialPowers.InspectorUtils.getCSSStyleRules(document.documentElement)
SpecialPowers.InspectorUtils.getMatchingCSSRules(document.documentElement)
}
window.addEventListener('load', start)

Просмотреть файл

@ -372,7 +372,7 @@ impl<T: ?Sized> Arc<T> {
/// allocation
#[inline]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.ptr() as *const () == other.ptr() as *const ()
this.raw_ptr() == other.raw_ptr()
}
fn ptr(&self) -> *mut ArcInner<T> {
@ -380,8 +380,8 @@ impl<T: ?Sized> Arc<T> {
}
/// Returns a raw ptr to the underlying allocation.
pub fn raw_ptr(&self) -> *const c_void {
self.p.as_ptr() as *const _
pub fn raw_ptr(&self) -> ptr::NonNull<()> {
self.p.cast()
}
}

Просмотреть файл

@ -145,14 +145,14 @@ trait PrivateMatchMethods: TElement {
result |= Self::replace_single_rule_node(
context.shared,
CascadeLevel::same_tree_author_normal(),
LayerOrder::root(),
LayerOrder::style_attribute(),
style_attribute,
primary_rules,
);
result |= Self::replace_single_rule_node(
context.shared,
CascadeLevel::same_tree_author_important(),
LayerOrder::root(),
LayerOrder::style_attribute(),
style_attribute,
primary_rules,
);

Просмотреть файл

@ -127,30 +127,33 @@ impl RuleCache {
/// Walk the rule tree and return a rule node for using as the key
/// for rule cache.
///
/// It currently skips a rule node when it is neither from a style
/// rule, nor containing any declaration of reset property. We don't
/// skip style rule so that we don't need to walk a long way in the
/// worst case. Skipping declarations rule nodes should be enough
/// to address common cases that rule cache would fail to share
/// when using the rule node directly, like preshint, style attrs,
/// and animations.
/// It currently skips animation / style attribute / preshint rules when they don't contain any
/// declaration of a reset property. We don't skip other levels because walking the whole
/// parent chain can be expensive.
///
/// TODO(emilio): Measure this, this was not super-well measured for performance (this was done
/// for memory in bug 1427681)... Walking the rule tree might be worth it if we hit the cache
/// enough?
fn get_rule_node_for_cache<'r>(
guards: &StylesheetGuards,
mut rule_node: Option<&'r StrongRuleNode>,
) -> Option<&'r StrongRuleNode> {
use crate::rule_tree::CascadeLevel;
while let Some(node) = rule_node {
match node.style_source() {
Some(s) => match s.as_declarations() {
Some(decls) => {
let cascade_level = node.cascade_level();
let decls = decls.read_with(cascade_level.guard(guards));
if decls.contains_any_reset() {
break;
}
},
None => break,
},
None => {},
let priority = node.cascade_priority();
let cascade_level = priority.cascade_level();
let should_try_to_skip =
cascade_level.is_animation() ||
matches!(cascade_level, CascadeLevel::PresHints) ||
priority.layer_order().is_style_attribute_layer();
if !should_try_to_skip {
break;
}
if let Some(source) = node.style_source() {
let decls = source.get().read_with(cascade_level.guard(guards));
if decls.contains_any_reset() {
break;
}
}
rule_node = node.parent();
}

Просмотреть файл

@ -214,24 +214,24 @@ impl RuleTree {
current = current.parent().unwrap().clone();
}
let cascade_priority = CascadePriority::new(level, layer_order);
// Then remove the one at the level we want to replace, if any.
//
// NOTE: Here we assume that only one rule can be at the level we're
// replacing.
// NOTE: Here we assume that only one rule can be at the level + priority we're replacing,
// which holds because we only use this for HTML style attribute, animations and transition
// rules.
//
// This is certainly true for HTML style attribute rules, animations and
// transitions, but could not be so for SMIL animations, which we'd need
// to special-case (isn't hard, it's just about removing the `if` and
// special cases, and replacing them for a `while` loop, avoiding the
// optimizations).
if current.cascade_priority().cascade_level() == level {
// This is certainly true for HTML style attribute rules, animations, transitions, and
// SMIL.
if current.cascade_priority() == cascade_priority {
*important_rules_changed |= level.is_important();
let current_decls = current.style_source().unwrap().as_declarations();
let current_decls = current.style_source().unwrap().get();
// If the only rule at the level we're replacing is exactly the
// same as `pdb`, we're done, and `path` is still valid.
if let (Some(ref pdb), Some(ref current_decls)) = (pdb, current_decls) {
if let Some(ref pdb) = pdb {
// If the only rule at the level we're replacing is exactly the
// same as `pdb`, we're done, and `path` is still valid.
//
@ -241,30 +241,27 @@ impl RuleTree {
// also equally valid. This is less likely, and would require an
// in-place mutation of the source, which is, at best, fiddly,
// so let's skip it for now.
let is_here_already = ArcBorrow::ptr_eq(pdb, current_decls);
let is_here_already = ArcBorrow::ptr_eq(pdb, &current_decls.borrow_arc());
if is_here_already {
debug!("Picking the fast path in rule replacement");
return None;
}
}
if current_decls.is_some() {
current = current.parent().unwrap().clone();
}
current = current.parent().unwrap().clone();
}
// Insert the rule if it's relevant at this level in the cascade.
//
// These optimizations are likely to be important, because the levels
// where replacements apply (style and animations) tend to trigger
// pretty bad styling cases already.
// These optimizations are likely to be important, because the levels where replacements
// apply (style and animations) tend to trigger pretty bad styling cases already.
if let Some(pdb) = pdb {
if level.is_important() {
if pdb.read_with(level.guard(guards)).any_important() {
current = current.ensure_child(
self.root(),
StyleSource::from_declarations(pdb.clone_arc()),
CascadePriority::new(level, layer_order),
cascade_priority,
);
*important_rules_changed = true;
}
@ -273,7 +270,7 @@ impl RuleTree {
current = current.ensure_child(
self.root(),
StyleSource::from_declarations(pdb.clone_arc()),
CascadePriority::new(level, layer_order),
cascade_priority,
);
}
}

Просмотреть файл

@ -6,49 +6,38 @@
use crate::properties::PropertyDeclarationBlock;
use crate::shared_lock::{Locked, SharedRwLockReadGuard};
use crate::stylesheets::StyleRule;
use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow};
use servo_arc::Arc;
use std::io::Write;
use std::ptr;
/// A style source for the rule node. It can either be a CSS style rule or a
/// declaration block.
/// A style source for the rule node. It is a declaration block that may come from either a style
/// rule or a standalone block like animations / transitions / smil / preshints / style attr...
///
/// Note that, even though the declaration block from inside the style rule
/// could be enough to implement the rule tree, keeping the whole rule provides
/// more debuggability, and also the ability of show those selectors to
/// devtools.
/// Keeping the style rule around would provide more debugability, but also causes more
/// pointer-chasing in the common code-path, which is undesired. If needed, we could keep it around
/// in debug builds or something along those lines.
#[derive(Clone, Debug)]
pub struct StyleSource(ArcUnion<Locked<StyleRule>, Locked<PropertyDeclarationBlock>>);
pub struct StyleSource(Arc<Locked<PropertyDeclarationBlock>>);
impl PartialEq for StyleSource {
fn eq(&self, other: &Self) -> bool {
ArcUnion::ptr_eq(&self.0, &other.0)
Arc::ptr_eq(&self.0, &other.0)
}
}
impl StyleSource {
/// Creates a StyleSource from a StyleRule.
pub fn from_rule(rule: Arc<Locked<StyleRule>>) -> Self {
StyleSource(ArcUnion::from_first(rule))
}
#[inline]
pub(super) fn key(&self) -> ptr::NonNull<()> {
self.0.ptr()
self.0.raw_ptr()
}
/// Creates a StyleSource from a PropertyDeclarationBlock.
#[inline]
pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
StyleSource(ArcUnion::from_second(decls))
Self(decls)
}
pub(super) fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
if let Some(ref rule) = self.0.as_first() {
let rule = rule.read_with(guard);
let _ = write!(writer, "{:?}", rule.selectors);
}
let _ = write!(writer, " -> {:?}", self.read(guard).declarations());
}
@ -56,20 +45,12 @@ impl StyleSource {
/// underlying property declaration block.
#[inline]
pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock {
let block: &Locked<PropertyDeclarationBlock> = match self.0.borrow() {
ArcUnionBorrow::First(ref rule) => &rule.get().read_with(guard).block,
ArcUnionBorrow::Second(ref block) => block.get(),
};
block.read_with(guard)
}
/// Returns the style rule if applicable, otherwise None.
pub fn as_rule(&self) -> Option<ArcBorrow<Locked<StyleRule>>> {
self.0.as_first()
self.0.read_with(guard)
}
/// Returns the declaration block if applicable, otherwise None.
pub fn as_declarations(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
self.0.as_second()
#[inline]
pub fn get(&self) -> &Arc<Locked<PropertyDeclarationBlock>> {
&self.0
}
}

Просмотреть файл

@ -3239,7 +3239,6 @@ impl CascadeData {
fn add_styles(
&mut self,
style_source: StyleSource,
selectors: &SelectorList<SelectorImpl>,
declarations: &Arc<Locked<PropertyDeclarationBlock>>,
ancestor_selectors: Option<&SelectorList<SelectorImpl>>,
@ -3270,7 +3269,7 @@ impl CascadeData {
.expect("Expected precomputed declarations for the UA level")
.get_or_insert_with(pseudo, Vec::new)
.push(ApplicableDeclarationBlock::new(
style_source.clone(),
StyleSource::from_declarations(declarations.clone()),
self.rules_source_order,
CascadeLevel::UANormal,
selector.specificity(),
@ -3294,7 +3293,7 @@ impl CascadeData {
let rule = Rule::new(
selector,
hashes,
style_source.clone(),
StyleSource::from_declarations(declarations.clone()),
self.rules_source_order,
containing_rule_state.layer_id,
containing_rule_state.container_condition_id,
@ -3428,7 +3427,6 @@ impl CascadeData {
let ancestor_selectors = containing_rule_state.ancestor_selector_lists.last();
let collect_replaced_selectors = has_nested_rules && ancestor_selectors.is_some();
self.add_styles(
StyleSource::from_rule(locked.clone()),
&style_rule.selectors,
&style_rule.block,
ancestor_selectors,
@ -3467,7 +3465,6 @@ impl CascadeData {
NestedDeclarationsContext::Scope => &*IMPLICIT_SCOPE,
};
self.add_styles(
StyleSource::from_declarations(decls.clone()),
selectors,
decls,
/* ancestor_selectors = */ None,

Просмотреть файл

@ -116,13 +116,8 @@ impl<T> ArcSlice<T> {
/// Creates a value that can be passed via FFI, and forgets this value
/// altogether.
#[inline]
#[allow(unsafe_code)]
pub fn forget(self) -> ForgottenArcSlicePtr<T> {
let ret = unsafe {
ForgottenArcSlicePtr(NonNull::new_unchecked(
self.0.raw_ptr() as *const _ as *mut _
))
};
let ret = ForgottenArcSlicePtr(self.0.raw_ptr().cast());
mem::forget(self);
ret
}
@ -134,7 +129,7 @@ impl<T> ArcSlice<T> {
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
let ptr = empty.0.raw_ptr();
std::mem::forget(empty);
ptr as *mut _
ptr.cast().as_ptr()
}
/// Returns whether there's only one reference to this ArcSlice.

Просмотреть файл

@ -4471,9 +4471,9 @@ pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
pub extern "C" fn Servo_ComputedValues_GetMatchingDeclarations(
values: &ComputedValues,
rules: &mut nsTArray<*const LockedStyleRule>,
rules: &mut nsTArray<*const LockedDeclarationBlock>,
) {
let rule_node = match values.rules {
Some(ref r) => r,
@ -4481,11 +4481,6 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
};
for node in rule_node.self_and_ancestors() {
let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
Some(rule) => rule,
_ => continue,
};
// For the rules with any important declaration, we insert them into
// rule tree twice, one for normal level and another for important
// level. So, we skip the important one to keep the specificity order of
@ -4494,7 +4489,9 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
continue;
}
rules.push(&*style_rule);
let Some(source) = node.style_source() else { continue };
rules.push(&**source.get());
}
}
@ -4526,20 +4523,13 @@ fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
#[cfg(feature = "gecko_debug")]
fn dump_rules(cv: &ComputedValues) {
println_stderr!(" Rules({:?}):", cv.pseudo());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
if let Some(rules) = cv.rules.as_ref() {
for rn in rules.self_and_ancestors() {
if rn.importance().important() {
continue;
}
if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
println_stderr!(" [DeclarationBlock: {:?}]", d);
}
if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
let mut s = nsCString::new();
r.read_with(&guard).to_css(&guard, &mut s).unwrap();
println_stderr!(" {}", s);
if let Some(d) = rn.style_source() {
println_stderr!(" {:?}", d.get());
}
}
}