Bug 1893409 - Make getCSSStyleRules() work for starting style as well. r=layout-reviewers,firefox-style-system-reviewers,nchevobbe,emilio

Update the API, `nspectorUtils.getCSSStyleRules`. Add one extra
argument so the user can choose whether we should return the starting
style, for a given element, at this moment.

Differential Revision: https://phabricator.services.mozilla.com/D209318
This commit is contained in:
Boris Chiou 2024-06-04 03:15:00 +00:00
parent 300659b5ee
commit 6203ad286b
10 changed files with 202 additions and 29 deletions

View file

@ -17,7 +17,8 @@ namespace InspectorUtils {
sequence<CSSStyleRule> getCSSStyleRules(
Element element,
optional [LegacyNullToEmptyString] DOMString pseudo = "",
optional boolean relevantLinkVisited = false);
optional boolean relevantLinkVisited = false,
optional boolean withStartingStyle = false);
unsigned long getRuleLine(CSSRule rule);
unsigned long getRuleColumn(CSSRule rule);
unsigned long getRelativeRuleLine(CSSRule rule);

View file

@ -229,41 +229,37 @@ void InspectorUtils::GetChildrenForNode(nsINode& aNode,
}
}
/* static */
void InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject,
Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult) {
auto [type, functionalPseudoParameter] =
nsCSSPseudoElements::ParsePseudoElement(aPseudo,
CSSEnabledState::ForAllContent);
if (!type) {
return;
static already_AddRefed<const ComputedStyle> GetStartingStyle(
Element& aElement) {
// If this element is unstyled, or it doesn't have matched rules in
// @starting-style, we return.
if (!Servo_Element_MayHaveStartingStyle(&aElement)) {
return nullptr;
}
RefPtr<const ComputedStyle> computedStyle = GetCleanComputedStyleForElement(
&aElement, *type, functionalPseudoParameter);
if (!computedStyle) {
// This can fail for elements that are not in the document or
// if the document they're in doesn't have a presshell. Bail out.
return;
const PresShell* presShell = aElement.OwnerDoc()->GetPresShell();
if (!presShell) {
return nullptr;
}
if (aIncludeVisitedStyle) {
if (auto* styleIfVisited = computedStyle->GetStyleIfVisited()) {
computedStyle = styleIfVisited;
}
ServoStyleSet* styleSet = presShell->StyleSet();
if (!styleSet) {
return nullptr;
}
Document* doc = aElement.OwnerDoc();
PresShell* presShell = doc->GetPresShell();
return styleSet->ResolveStartingStyle(aElement);
}
static void GetCSSStyleRulesFromComputedValue(
Element& aElement, const ComputedStyle* aComputedStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult) {
const PresShell* presShell = aElement.OwnerDoc()->GetPresShell();
if (!presShell) {
return;
}
AutoTArray<const StyleLockedStyleRule*, 8> rawRuleList;
Servo_ComputedValues_GetStyleRuleList(computedStyle, &rawRuleList);
Servo_ComputedValues_GetStyleRuleList(aComputedStyle, &rawRuleList);
AutoTArray<ServoStyleRuleMap*, 8> maps;
{
@ -313,7 +309,7 @@ void InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject,
#ifdef DEBUG
aElement.Dump();
printf_stderr("\n\n----\n\n");
computedStyle->DumpMatchedRules();
aComputedStyle->DumpMatchedRules();
nsAutoCString str;
Servo_StyleRule_Debug(rawRule, &str);
printf_stderr("\n\n----\n\n");
@ -327,6 +323,48 @@ void InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject,
}
}
/* static */
void InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject,
Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
bool aWithStartingStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult) {
auto [type, functionalPseudoParameter] =
nsCSSPseudoElements::ParsePseudoElement(aPseudo,
CSSEnabledState::ForAllContent);
if (!type) {
return;
}
RefPtr<const ComputedStyle> computedStyle;
if (aWithStartingStyle) {
computedStyle = GetStartingStyle(aElement);
}
// Note: GetStartingStyle() return nullptr if this element doesn't have rules
// inside @starting-style. For this case, we would like to return the primay
// rules of this element.
if (!computedStyle) {
computedStyle = GetCleanComputedStyleForElement(&aElement, *type,
functionalPseudoParameter);
}
if (!computedStyle) {
// This can fail for elements that are not in the document or
// if the document they're in doesn't have a presshell. Bail out.
return;
}
if (aIncludeVisitedStyle) {
if (const auto* styleIfVisited = computedStyle->GetStyleIfVisited()) {
computedStyle = styleIfVisited;
}
}
GetCSSStyleRulesFromComputedValue(aElement, computedStyle, aResult);
}
/* static */
uint32_t InspectorUtils::GetRuleLine(GlobalObject& aGlobal, css::Rule& aRule) {
uint32_t line = aRule.GetLineNumber();

View file

@ -44,6 +44,7 @@ class InspectorUtils {
static void GetCSSStyleRules(GlobalObject& aGlobal, Element& aElement,
const nsAString& aPseudo,
bool aIncludeVisitedStyle,
bool aWithStartingStyle,
nsTArray<RefPtr<CSSStyleRule>>& aResult);
/**

View file

@ -4,6 +4,7 @@ prefs = [
"layout.css.basic-shape-shape.enabled=true",
"layout.css.basic-shape-xywh.enabled=true",
"layout.css.properties-and-values.enabled=true",
"layout.css.starting-style-at-rules.enabled=true",
"layout.css.transition-behavior.enabled=true",
"dom.customHighlightAPI.enabled=true",
]
@ -56,6 +57,8 @@ support-files = [
["test_getCSSStyleRules_slotted.html"]
["test_getCSSStyleRules_starting_style.html"]
["test_getRegisteredCssHighlights.html"]
["test_getRegisteredCustomProperties.html"]

View file

@ -0,0 +1,68 @@
<!DOCTYPE HTML>
<title>Test for InspectorUtils.getCSSStyleRules for starting style</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
<style>
@starting-style {
unknowntagname {
color: red;
}
}
unknowntagname {
color: blue;
opacity: 1;
@starting-style {
opacity: 0;
}
}
</style>
<pre id="log"></pre>
<unknowntagname></unknowntagname>
<script>
/**
* This test checks that InspectorUtils.getCSSStyleRules setting
* withStartingStyle:true returns correct style set in various cases.
* To avoid effects from UA sheets, we use an element with "unknowntagname".
*/
const InspectorUtils = SpecialPowers.InspectorUtils;
add_task(async function runTests() {
const styleSheet = document.styleSheets[1];
const el = document.querySelector("unknowntagname");
let rules = InspectorUtils.getCSSStyleRules(el, "", false, true);
is(rules.length, 3, "Expected rules");
is(
rules[0].cssText,
styleSheet.cssRules[0].cssRules[0].cssText,
"first returned rule is the one in the top-level starting-style rule"
);
is(
rules[1].cssText,
styleSheet.cssRules[1].cssText,
"first returned rule is top-level unknowntagname rule"
);
is(
rules[2].cssText,
styleSheet.cssRules[1].cssRules[0].cssRules[0].cssText,
"second returned rule is the one in the top-level starting-style rule"
);
info(
"Check that starting style rules are not returned when withStartingStyle " +
"param is false"
);
rules = InspectorUtils.getCSSStyleRules(el, "", false);
is(rules.length, 1, "Expected rules");
is(
rules[0].cssText,
styleSheet.cssRules[1].cssText,
"Only returned rule is top-level unknowntagname rule"
);
});
</script>

View file

@ -598,6 +598,18 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolveXULTreePseudoStyle(
.Consume();
}
already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStartingStyle(
dom::Element& aElement) {
nsPresContext* pc = GetPresContext();
if (!pc) {
return nullptr;
}
return Servo_ResolveStartingStyle(
&aElement, &pc->RestyleManager()->Snapshots(), mRawData.get())
.Consume();
}
// manage the set of style sheets in the style set
void ServoStyleSet::AppendStyleSheet(StyleSheet& aSheet) {
MOZ_ASSERT(aSheet.IsApplicable());

View file

@ -257,6 +257,10 @@ class ServoStyleSet {
dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,
ComputedStyle* aParentStyle, const AtomArray& aInputWord);
// Try to resolve the staring style for a given element. Please call this
// function after checking if it may have rules inside @starting-style.
already_AddRefed<ComputedStyle> ResolveStartingStyle(dom::Element& aElement);
size_t SheetCount(Origin) const;
StyleSheet* SheetAt(Origin, size_t aIndex) const;

View file

@ -402,7 +402,7 @@ trait PrivateMatchMethods: TElement {
PseudoElementResolution::IfApplicable,
);
let starting_style = resolver.resolve_starting_style();
let starting_style = resolver.resolve_starting_style().style;
if starting_style.style().clone_display().is_none() {
return None;
}

View file

@ -629,7 +629,7 @@ where
}
/// Resolve the starting style.
pub fn resolve_starting_style(&mut self) -> ResolvedStyle {
pub fn resolve_starting_style(&mut self) -> PrimaryStyle {
// Compute after-change style for the parent and the layout parent.
// Per spec, starting style inherits from the parents after-change style just like
// after-change style does.
@ -665,7 +665,6 @@ where
layout_parent_values,
IncludeStartingStyle::Yes,
)
.style
}
/// If there is no transition rule in the ComputedValues, it returns None.

View file

@ -1555,6 +1555,17 @@ pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGec
.contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
}
#[no_mangle]
pub extern "C" fn Servo_Element_MayHaveStartingStyle(element: &RawGeckoElement) -> bool {
let element = GeckoElement(element);
let data = match element.borrow_data() {
Some(d) => d,
None => return false,
};
data.flags
.contains(data::ElementDataFlags::MAY_HAVE_STARTING_STYLE)
}
fn mode_to_origin(mode: SheetParsingMode) -> Origin {
match mode {
SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
@ -6094,6 +6105,42 @@ pub extern "C" fn Servo_ResolveStyleLazily(
.into()
}
#[no_mangle]
pub extern "C" fn Servo_ResolveStartingStyle(
element: &RawGeckoElement,
snapshots: *const ServoElementSnapshotTable,
raw_data: &PerDocumentStyleData,
) -> Strong<ComputedValues> {
use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
let doc_data = raw_data.borrow();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let shared = create_shared_context(
&global_style_data,
&guard,
&doc_data.stylist,
TraversalFlags::empty(),
unsafe { &*snapshots },
);
let mut tlc = ThreadLocalStyleContext::new();
let mut context = StyleContext {
shared: &shared,
thread_local: &mut tlc,
};
let element = GeckoElement(element);
let mut resolver = StyleResolverForElement::new(
element,
&mut context,
RuleInclusion::All,
PseudoElementResolution::IfApplicable,
);
let starting_style = resolver.resolve_starting_style();
starting_style.style.0.into()
}
#[no_mangle]
pub extern "C" fn Servo_ReparentStyle(
style_to_reparent: &ComputedValues,