Backed out changeset 8c89fd37b79d (bug 1544242) for failures in browser_rules_shadowdom_slot_rules.js CLOSED TREE

This commit is contained in:
Noemi Erli 2019-05-01 22:03:06 +03:00
Родитель 7fa6125c63
Коммит f1ef21cbc7
23 изменённых файлов: 146 добавлений и 271 удалений

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

@ -2516,8 +2516,9 @@ static void UpdateBackdropIfNeeded(nsIFrame* aFrame, ServoStyleSet& aStyleSet,
PseudoStyleType::backdrop); PseudoStyleType::backdrop);
RefPtr<ComputedStyle> newStyle = aStyleSet.ResolvePseudoElementStyle( RefPtr<ComputedStyle> newStyle = aStyleSet.ResolvePseudoElementStyle(
*aFrame->GetContent()->AsElement(), PseudoStyleType::backdrop, aFrame->GetContent()->AsElement(), PseudoStyleType::backdrop,
aFrame->Style()); aFrame->Style(),
/* aPseudoElement = */ nullptr);
// NOTE(emilio): We can't use the changes handled for the owner of the // NOTE(emilio): We can't use the changes handled for the owner of the
// backdrop frame, since it's out of flow, and parented to the viewport or // backdrop frame, since it's out of flow, and parented to the viewport or
@ -2560,7 +2561,8 @@ static void UpdateOneAdditionalComputedStyle(nsIFrame* aFrame, uint32_t aIndex,
RefPtr<ComputedStyle> newStyle = RefPtr<ComputedStyle> newStyle =
aRestyleState.StyleSet().ResolvePseudoElementStyle( aRestyleState.StyleSet().ResolvePseudoElementStyle(
*aFrame->GetContent()->AsElement(), pseudoType, aFrame->Style()); aFrame->GetContent()->AsElement(), pseudoType, aFrame->Style(),
/* aPseudoElement = */ nullptr);
uint32_t equalStructs; // Not used, actually. uint32_t equalStructs; // Not used, actually.
nsChangeHint childHint = nsChangeHint childHint =
@ -2757,8 +2759,8 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
styleFrame->IsBlockFrameOrSubclass() && styleFrame->IsBlockFrameOrSubclass() &&
!nsLayoutUtils::GetMarkerPseudo(aElement)) { !nsLayoutUtils::GetMarkerPseudo(aElement)) {
RefPtr<ComputedStyle> pseudoStyle = RefPtr<ComputedStyle> pseudoStyle =
aRestyleState.StyleSet().ProbeMarkerPseudoStyle(*aElement, aRestyleState.StyleSet().ProbePseudoElementStyle(
*upToDateStyleIfRestyled); *aElement, PseudoStyleType::marker, upToDateStyleIfRestyled);
if (pseudoStyle) { if (pseudoStyle) {
changeHint |= nsChangeHint_ReconstructFrame; changeHint |= nsChangeHint_ReconstructFrame;
} }

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

@ -1160,8 +1160,9 @@ void nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent,
RefPtr<ComputedStyle> style = RefPtr<ComputedStyle> style =
mPresShell->StyleSet()->ResolvePseudoElementStyle( mPresShell->StyleSet()->ResolvePseudoElementStyle(
*aContent->AsElement(), PseudoStyleType::backdrop, aContent->AsElement(), PseudoStyleType::backdrop,
/* aParentStyle */ nullptr); /* aParentComputedStyle */ nullptr,
/* aPseudoElement */ nullptr);
MOZ_ASSERT(style->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP); MOZ_ASSERT(style->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
nsContainerFrame* parentFrame = nsContainerFrame* parentFrame =
GetGeometricParent(*style->StyleDisplay(), nullptr); GetGeometricParent(*style->StyleDisplay(), nullptr);
@ -1702,27 +1703,24 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
ServoStyleSet* styleSet = mPresShell->StyleSet(); ServoStyleSet* styleSet = mPresShell->StyleSet();
// Probe for the existence of the pseudo-element // Probe for the existence of the pseudo-element
RefPtr<ComputedStyle> pseudoStyle; RefPtr<ComputedStyle> pseudoStyle = styleSet->ProbePseudoElementStyle(
aOriginatingElement, aPseudoElement, &aStyle);
if (!pseudoStyle) {
return;
}
nsAtom* elemName = nullptr; nsAtom* elemName = nullptr;
nsAtom* property = nullptr; nsAtom* property = nullptr;
switch (aPseudoElement) { switch (aPseudoElement) {
case PseudoStyleType::before: case PseudoStyleType::before:
pseudoStyle = styleSet->ProbePseudoElementStyle(aOriginatingElement,
aPseudoElement, &aStyle);
elemName = nsGkAtoms::mozgeneratedcontentbefore; elemName = nsGkAtoms::mozgeneratedcontentbefore;
property = nsGkAtoms::beforePseudoProperty; property = nsGkAtoms::beforePseudoProperty;
break; break;
case PseudoStyleType::after: case PseudoStyleType::after:
pseudoStyle = styleSet->ProbePseudoElementStyle(aOriginatingElement,
aPseudoElement, &aStyle);
elemName = nsGkAtoms::mozgeneratedcontentafter; elemName = nsGkAtoms::mozgeneratedcontentafter;
property = nsGkAtoms::afterPseudoProperty; property = nsGkAtoms::afterPseudoProperty;
break; break;
case PseudoStyleType::marker: case PseudoStyleType::marker:
// We want to get a marker style even if we match no rules, but we still
// want to check the result of GeneratedContentPseudoExists.
pseudoStyle = styleSet->ProbeMarkerPseudoStyle(aOriginatingElement,
aStyle);
elemName = nsGkAtoms::mozgeneratedcontentmarker; elemName = nsGkAtoms::mozgeneratedcontentmarker;
property = nsGkAtoms::markerPseudoProperty; property = nsGkAtoms::markerPseudoProperty;
break; break;
@ -1730,10 +1728,6 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement"); MOZ_ASSERT_UNREACHABLE("unexpected aPseudoElement");
} }
if (!pseudoStyle) {
return;
}
// |ProbePseudoStyleFor| checked the 'display' property and the // |ProbePseudoStyleFor| checked the 'display' property and the
// |ContentCount()| of the 'content' property for us. // |ContentCount()| of the 'content' property for us.
RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo( RefPtr<NodeInfo> nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(
@ -8718,7 +8712,8 @@ already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLetterStyle(
nsIContent* aContent, ComputedStyle* aComputedStyle) { nsIContent* aContent, ComputedStyle* aComputedStyle) {
if (aContent) { if (aContent) {
return mPresShell->StyleSet()->ResolvePseudoElementStyle( return mPresShell->StyleSet()->ResolvePseudoElementStyle(
*aContent->AsElement(), PseudoStyleType::firstLetter, aComputedStyle); aContent->AsElement(), PseudoStyleType::firstLetter, aComputedStyle,
nullptr);
} }
return nullptr; return nullptr;
} }
@ -8727,7 +8722,8 @@ already_AddRefed<ComputedStyle> nsCSSFrameConstructor::GetFirstLineStyle(
nsIContent* aContent, ComputedStyle* aComputedStyle) { nsIContent* aContent, ComputedStyle* aComputedStyle) {
if (aContent) { if (aContent) {
return mPresShell->StyleSet()->ResolvePseudoElementStyle( return mPresShell->StyleSet()->ResolvePseudoElementStyle(
*aContent->AsElement(), PseudoStyleType::firstLine, aComputedStyle); aContent->AsElement(), PseudoStyleType::firstLine, aComputedStyle,
nullptr);
} }
return nullptr; return nullptr;
} }

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

@ -500,12 +500,13 @@ ImgDrawResult nsButtonFrameRenderer::PaintBorder(nsDisplayListBuilder* aBuilder,
*/ */
void nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext) { void nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext) {
// get all the styles // get all the styles
ComputedStyle* context = mFrame->Style();
ServoStyleSet* styleSet = aPresContext->StyleSet(); ServoStyleSet* styleSet = aPresContext->StyleSet();
// get styles assigned to -moz-focus-inner (ie dotted border on Windows) // get styles assigned to -moz-focus-inner (ie dotted border on Windows)
mInnerFocusStyle = styleSet->ProbePseudoElementStyle( mInnerFocusStyle = styleSet->ProbePseudoElementStyle(
*mFrame->GetContent()->AsElement(), PseudoStyleType::mozFocusInner, *mFrame->GetContent()->AsElement(), PseudoStyleType::mozFocusInner,
mFrame->Style()); context);
} }
ComputedStyle* nsButtonFrameRenderer::GetComputedStyle(int32_t aIndex) const { ComputedStyle* nsButtonFrameRenderer::GetComputedStyle(int32_t aIndex) const {

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

@ -5465,7 +5465,8 @@ void nsBlockFrame::UpdateFirstLetterStyle(ServoRestyleState& aRestyleState) {
ComputedStyle* parentStyle = styleParent->Style(); ComputedStyle* parentStyle = styleParent->Style();
RefPtr<ComputedStyle> firstLetterStyle = RefPtr<ComputedStyle> firstLetterStyle =
aRestyleState.StyleSet().ResolvePseudoElementStyle( aRestyleState.StyleSet().ResolvePseudoElementStyle(
*mContent->AsElement(), PseudoStyleType::firstLetter, parentStyle); mContent->AsElement(), PseudoStyleType::firstLetter, parentStyle,
nullptr);
// Note that we don't need to worry about changehints for the continuation // Note that we don't need to worry about changehints for the continuation
// styles: those will be handled by the styleParent already. // styles: those will be handled by the styleParent already.
RefPtr<ComputedStyle> continuationStyle = RefPtr<ComputedStyle> continuationStyle =
@ -7187,7 +7188,8 @@ void nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState) {
ComputedStyle* parentStyle = styleParent->Style(); ComputedStyle* parentStyle = styleParent->Style();
RefPtr<ComputedStyle> firstLineStyle = RefPtr<ComputedStyle> firstLineStyle =
aRestyleState.StyleSet().ResolvePseudoElementStyle( aRestyleState.StyleSet().ResolvePseudoElementStyle(
*mContent->AsElement(), PseudoStyleType::firstLine, parentStyle); mContent->AsElement(), PseudoStyleType::firstLine, parentStyle,
nullptr);
// FIXME(bz): Can we make first-line continuations be non-inheriting anon // FIXME(bz): Can we make first-line continuations be non-inheriting anon
// boxes? // boxes?

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

@ -98,7 +98,7 @@ void nsMathMLFrame::ResolveMathMLCharStyle(nsPresContext* aPresContext,
PseudoStyleType pseudoType = PseudoStyleType::mozMathAnonymous; // savings PseudoStyleType pseudoType = PseudoStyleType::mozMathAnonymous; // savings
RefPtr<ComputedStyle> newComputedStyle; RefPtr<ComputedStyle> newComputedStyle;
newComputedStyle = aPresContext->StyleSet()->ResolvePseudoElementStyle( newComputedStyle = aPresContext->StyleSet()->ResolvePseudoElementStyle(
*aContent->AsElement(), pseudoType, aParentComputedStyle); aContent->AsElement(), pseudoType, aParentComputedStyle, nullptr);
aMathMLChar->SetComputedStyle(newComputedStyle); aMathMLChar->SetComputedStyle(newComputedStyle);
} }

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

@ -374,6 +374,8 @@ Maybe<StyleStructID> ComputedStyle::LookupStruct(const nsACString& aName) {
ComputedStyle* ComputedStyle::GetCachedLazyPseudoStyle( ComputedStyle* ComputedStyle::GetCachedLazyPseudoStyle(
PseudoStyleType aPseudo) const { PseudoStyleType aPseudo) const {
MOZ_ASSERT(PseudoStyle::IsPseudoElement(aPseudo)); MOZ_ASSERT(PseudoStyle::IsPseudoElement(aPseudo));
MOZ_ASSERT(!IsLazilyCascadedPseudoElement(),
"Lazy pseudos can't inherit lazy pseudos");
if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudo)) { if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudo)) {
return nullptr; return nullptr;

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

@ -194,6 +194,8 @@ class ComputedStyle {
void SetCachedLazyPseudoStyle(ComputedStyle* aStyle) { void SetCachedLazyPseudoStyle(ComputedStyle* aStyle) {
MOZ_ASSERT(aStyle->IsPseudoElement()); MOZ_ASSERT(aStyle->IsPseudoElement());
MOZ_ASSERT(!GetCachedLazyPseudoStyle(aStyle->GetPseudoType())); MOZ_ASSERT(!GetCachedLazyPseudoStyle(aStyle->GetPseudoType()));
MOZ_ASSERT(!IsLazilyCascadedPseudoElement(),
"lazy pseudos can't inherit lazy pseudos");
MOZ_ASSERT(aStyle->IsLazilyCascadedPseudoElement()); MOZ_ASSERT(aStyle->IsLazilyCascadedPseudoElement());
// Since we're caching lazy pseudo styles on the ComputedValues of the // Since we're caching lazy pseudo styles on the ComputedValues of the

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

@ -440,55 +440,38 @@ static inline bool LazyPseudoIsCacheable(PseudoStyleType aType,
} }
already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePseudoElementStyle( already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePseudoElementStyle(
const Element& aOriginatingElement, PseudoStyleType aType, Element* aOriginatingElement, PseudoStyleType aType,
ComputedStyle* aParentStyle, IsProbe aIsProbe) { ComputedStyle* aParentStyle, Element* aPseudoElement) {
// Runs from frame construction, this should have clean styles already, except // Runs from frame construction, this should have clean styles already, except
// with non-lazy FC... // with non-lazy FC...
UpdateStylistIfNeeded(); UpdateStylistIfNeeded();
MOZ_ASSERT(PseudoStyle::IsPseudoElement(aType)); MOZ_ASSERT(PseudoStyle::IsPseudoElement(aType));
const bool cacheable = RefPtr<ComputedStyle> computedValues;
LazyPseudoIsCacheable(aType, aOriginatingElement, aParentStyle);
RefPtr<ComputedStyle> style = if (aPseudoElement) {
MOZ_ASSERT(aType == aPseudoElement->GetPseudoElementType());
computedValues =
Servo_ResolveStyle(aPseudoElement, mRawSet.get()).Consume();
} else {
bool cacheable =
LazyPseudoIsCacheable(aType, *aOriginatingElement, aParentStyle);
computedValues =
cacheable ? aParentStyle->GetCachedLazyPseudoStyle(aType) : nullptr; cacheable ? aParentStyle->GetCachedLazyPseudoStyle(aType) : nullptr;
const bool isProbe = aIsProbe == IsProbe::Yes; if (!computedValues) {
computedValues = Servo_ResolvePseudoStyle(aOriginatingElement, aType,
if (!style) { /* is_probe = */ false,
// FIXME(emilio): Why passing null for probing as the parent style? aParentStyle, mRawSet.get())
//
// There are callers which do pass the wrong parent style and it would
// assert (like ComputeSelectionStyle()). That's messy!
style = Servo_ResolvePseudoStyle(&aOriginatingElement, aType, isProbe,
isProbe ? nullptr : aParentStyle,
mRawSet.get())
.Consume(); .Consume();
if (!style) {
MOZ_ASSERT(isProbe);
return nullptr;
}
if (cacheable) { if (cacheable) {
aParentStyle->SetCachedLazyPseudoStyle(style); aParentStyle->SetCachedLazyPseudoStyle(computedValues);
}
} }
} }
MOZ_ASSERT(style); MOZ_ASSERT(computedValues);
return computedValues.forget();
if (isProbe && !GeneratedContentPseudoExists(*aParentStyle, *style)) {
return nullptr;
}
return style.forget();
}
already_AddRefed<ComputedStyle> ServoStyleSet::ProbeMarkerPseudoStyle(
const dom::Element& aOriginatingElement, ComputedStyle& aParentStyle) {
RefPtr<ComputedStyle> markerStyle = ResolvePseudoElementStyle(
aOriginatingElement, PseudoStyleType::marker, &aParentStyle);
if (!GeneratedContentPseudoExists(aParentStyle, *markerStyle)) {
return nullptr;
}
return markerStyle.forget();
} }
already_AddRefed<ComputedStyle> already_AddRefed<ComputedStyle>
@ -674,35 +657,66 @@ void ServoStyleSet::AddDocStyleSheet(StyleSheet* aSheet) {
} }
} }
bool ServoStyleSet::GeneratedContentPseudoExists( already_AddRefed<ComputedStyle> ServoStyleSet::ProbePseudoElementStyle(
const ComputedStyle& aParentStyle, const ComputedStyle& aPseudoStyle) { const Element& aOriginatingElement, PseudoStyleType aType,
auto type = aPseudoStyle.GetPseudoType(); ComputedStyle* aParentStyle) {
MOZ_ASSERT(type != PseudoStyleType::NotPseudo); // Runs from frame construction, this should have clean styles already, except
// with non-lazy FC...
UpdateStylistIfNeeded();
if (type == PseudoStyleType::marker) { // NB: We ignore aParentStyle, because in some cases
// (first-line/first-letter on anonymous box blocks) Gecko passes something
// nonsensical there. In all other cases we want to inherit directly from
// aOriginatingElement's styles anyway.
MOZ_ASSERT(PseudoStyle::IsPseudoElement(aType));
bool cacheable =
LazyPseudoIsCacheable(aType, aOriginatingElement, aParentStyle);
RefPtr<ComputedStyle> computedValues =
cacheable ? aParentStyle->GetCachedLazyPseudoStyle(aType) : nullptr;
if (!computedValues) {
computedValues =
Servo_ResolvePseudoStyle(&aOriginatingElement, aType,
/* is_probe = */ true, nullptr, mRawSet.get())
.Consume();
if (!computedValues) {
return nullptr;
}
if (cacheable) {
// NB: We don't need to worry about the before/after handling below
// because those are eager and thus not |cacheable| anyway.
aParentStyle->SetCachedLazyPseudoStyle(computedValues);
}
}
if (aType == PseudoStyleType::marker) {
// ::marker only exist for list items (for now). // ::marker only exist for list items (for now).
if (aParentStyle.StyleDisplay()->mDisplay != StyleDisplay::ListItem) { if (aParentStyle->StyleDisplay()->mDisplay != StyleDisplay::ListItem) {
return false; return nullptr;
} }
// display:none is equivalent to not having the pseudo-element at all. // display:none is equivalent to not having the pseudo-element at all.
if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) { if (computedValues->StyleDisplay()->mDisplay == StyleDisplay::None) {
return false; return nullptr;
} }
} }
// For :before and :after pseudo-elements, having display: none or no // For :before and :after pseudo-elements, having display: none or no
// 'content' property is equivalent to not having the pseudo-element // 'content' property is equivalent to not having the pseudo-element
// at all. // at all.
if (type == PseudoStyleType::before || type == PseudoStyleType::after) { bool isBeforeOrAfter =
if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) { aType == PseudoStyleType::before || aType == PseudoStyleType::after;
return false; if (isBeforeOrAfter) {
} const nsStyleDisplay* display = computedValues->StyleDisplay();
if (!aPseudoStyle.StyleContent()->ContentCount()) { const nsStyleContent* content = computedValues->StyleContent();
return false; if (display->mDisplay == StyleDisplay::None ||
content->ContentCount() == 0) {
return nullptr;
} }
} }
return true; return computedValues.forget();
} }
bool ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) { bool ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) {

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

@ -168,36 +168,14 @@ class ServoStyleSet {
// matching for them is a first step.) // matching for them is a first step.)
already_AddRefed<ComputedStyle> ResolveStyleForPlaceholder(); already_AddRefed<ComputedStyle> ResolveStyleForPlaceholder();
// Returns whether a given pseudo-element should exist or not. // Get a ComputedStyle for a pseudo-element. aParentElement must be
static bool GeneratedContentPseudoExists(const ComputedStyle& aParentStyle, // non-null. aPseudoID is the PseudoStyleType for the
const ComputedStyle& aPseudoStyle); // pseudo-element. aPseudoElement must be non-null if the pseudo-element
// type is one that allows user action pseudo-classes after it or allows
enum class IsProbe { // style attributes; otherwise, it is ignored.
No,
Yes,
};
// Get a style for a pseudo-element.
//
// If IsProbe is Yes, then no style is returned if there are no rules matching
// for the pseudo-element, or GeneratedContentPseudoExists returns false.
//
// If IsProbe is No, then the style is guaranteed to be non-null.
already_AddRefed<ComputedStyle> ResolvePseudoElementStyle( already_AddRefed<ComputedStyle> ResolvePseudoElementStyle(
const dom::Element& aOriginatingElement, PseudoStyleType, dom::Element* aOriginatingElement, PseudoStyleType aType,
ComputedStyle* aParentStyle, IsProbe = IsProbe::No); ComputedStyle* aParentStyle, dom::Element* aPseudoElement);
already_AddRefed<ComputedStyle> ProbePseudoElementStyle(
const dom::Element& aOriginatingElement, PseudoStyleType aType,
ComputedStyle* aParentStyle) {
return ResolvePseudoElementStyle(aOriginatingElement, aType, aParentStyle,
IsProbe::Yes);
}
// A special one for ::marker since we don want to get a style if no rules
// match, but we want to also check GeneratedContentPseudoExists.
already_AddRefed<ComputedStyle> ProbeMarkerPseudoStyle(
const dom::Element& aOriginatingElement, ComputedStyle& aParentStyle);
// Resolves style for a (possibly-pseudo) Element without assuming that the // Resolves style for a (possibly-pseudo) Element without assuming that the
// style has been resolved. If the element was unstyled and a new style // style has been resolved. If the element was unstyled and a new style
@ -241,6 +219,11 @@ class ServoStyleSet {
void AddDocStyleSheet(StyleSheet* aSheet); void AddDocStyleSheet(StyleSheet* aSheet);
// check whether there is ::before/::after style for an element
already_AddRefed<ComputedStyle> ProbePseudoElementStyle(
const dom::Element& aOriginatingElement, PseudoStyleType aType,
ComputedStyle* aParentStyle);
/** /**
* Performs a Servo traversal to compute style for all dirty nodes in the * Performs a Servo traversal to compute style for all dirty nodes in the
* document. * document.

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

@ -84,6 +84,12 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
self.current_len = 0; self.current_len = 0;
} }
/// Returns true if no simple selectors have ever been pushed to this builder.
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.simple_selectors.is_empty()
}
/// Returns true if combinators have ever been pushed to this builder. /// Returns true if combinators have ever been pushed to this builder.
#[inline(always)] #[inline(always)]
pub fn has_combinators(&self) -> bool { pub fn has_combinators(&self) -> bool {

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

@ -331,11 +331,10 @@ where
return false; return false;
} }
// Advance to the non-pseudo-element part of the selector. // Advance to the non-pseudo-element part of the selector, but let the
let next_sequence = iter.next_sequence().unwrap(); // context note that .
debug_assert_eq!(next_sequence, Combinator::PseudoElement); if iter.next_sequence().is_none() {
if element.is_pseudo_element() { return true;
return false;
} }
} }
@ -467,13 +466,7 @@ where
} }
Some(current_slot) Some(current_slot)
}, },
Combinator::PseudoElement => { Combinator::PseudoElement => element.pseudo_element_originating_element(),
let next_element = element.pseudo_element_originating_element()?;
if next_element.is_pseudo_element() {
return None;
}
Some(next_element)
}
} }
} }
@ -684,6 +677,7 @@ where
Component::Slotted(ref selector) => { Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables. // <slots> are never flattened tree slottables.
!element.is_html_slot_element() && !element.is_html_slot_element() &&
element.assigned_slot().is_some() &&
context.shared.nest(|context| { context.shared.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter) matches_complex_selector(selector.iter(), element, context, flags_setter)
}) })

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

@ -1998,7 +1998,9 @@ where
}, },
SimpleSelectorParseResult::SlottedPseudo(selector) => { SimpleSelectorParseResult::SlottedPseudo(selector) => {
state.insert(SelectorParsingState::AFTER_SLOTTED); state.insert(SelectorParsingState::AFTER_SLOTTED);
if !builder.is_empty() {
builder.push_combinator(Combinator::SlotAssignment); builder.push_combinator(Combinator::SlotAssignment);
}
builder.push_simple_selector(Component::Slotted(selector)); builder.push_simple_selector(Component::Slotted(selector));
}, },
SimpleSelectorParseResult::PseudoElement(p) => { SimpleSelectorParseResult::PseudoElement(p) => {
@ -2006,7 +2008,9 @@ where
if !p.accepts_state_pseudo_classes() { if !p.accepts_state_pseudo_classes() {
state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT); state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
} }
if !builder.is_empty() {
builder.push_combinator(Combinator::PseudoElement); builder.push_combinator(Combinator::PseudoElement);
}
builder.push_simple_selector(Component::PseudoElement(p)); builder.push_simple_selector(Component::PseudoElement(p));
}, },
} }
@ -2811,10 +2815,7 @@ pub mod tests {
assert_eq!( assert_eq!(
parse("::before"), parse("::before"),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
vec![ vec![Component::PseudoElement(PseudoElement::Before)],
Component::Combinator(Combinator::PseudoElement),
Component::PseudoElement(PseudoElement::Before),
],
specificity(0, 0, 1) | HAS_PSEUDO_BIT, specificity(0, 0, 1) | HAS_PSEUDO_BIT,
)])) )]))
); );
@ -2822,7 +2823,6 @@ pub mod tests {
parse("::before:hover"), parse("::before:hover"),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
vec![ vec![
Component::Combinator(Combinator::PseudoElement),
Component::PseudoElement(PseudoElement::Before), Component::PseudoElement(PseudoElement::Before),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
], ],
@ -2833,7 +2833,6 @@ pub mod tests {
parse("::before:hover:hover"), parse("::before:hover:hover"),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
vec![ vec![
Component::Combinator(Combinator::PseudoElement),
Component::PseudoElement(PseudoElement::Before), Component::PseudoElement(PseudoElement::Before),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
@ -2946,7 +2945,6 @@ pub mod tests {
specificity(0, 0, 0), specificity(0, 0, 0),
)])) )]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(svg|*)", &parser), parse_ns(":not(svg|*)", &parser),
Ok(SelectorList::from_vec(vec![Selector::from_vec( Ok(SelectorList::from_vec(vec![Selector::from_vec(
@ -3021,8 +3019,6 @@ pub mod tests {
Some(&Component::PseudoElement(PseudoElement::Before)) Some(&Component::PseudoElement(PseudoElement::Before))
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_sequence(), None); assert_eq!(iter.next_sequence(), None);
} }

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

@ -47,13 +47,9 @@ pub trait Element: Sized + Clone + Debug {
/// ///
/// This is guaranteed to be called in a pseudo-element. /// This is guaranteed to be called in a pseudo-element.
fn pseudo_element_originating_element(&self) -> Option<Self> { fn pseudo_element_originating_element(&self) -> Option<Self> {
debug_assert!(self.is_pseudo_element());
self.parent_element() self.parent_element()
} }
/// Whether we're matching on a pseudo-element.
fn is_pseudo_element(&self) -> bool;
/// Skips non-element nodes /// Skips non-element nodes
fn prev_sibling_element(&self) -> Option<Self>; fn prev_sibling_element(&self) -> Option<Self>;

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

@ -779,7 +779,7 @@ pub trait TElement:
/// element-backed pseudo-element, in which case we return the originating /// element-backed pseudo-element, in which case we return the originating
/// element. /// element.
fn rule_hash_target(&self) -> Self { fn rule_hash_target(&self) -> Self {
if self.is_pseudo_element() { if self.implemented_pseudo_element().is_some() {
self.pseudo_element_originating_element() self.pseudo_element_originating_element()
.expect("Trying to collect rules for a detached pseudo-element") .expect("Trying to collect rules for a detached pseudo-element")
} else { } else {

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

@ -1098,7 +1098,7 @@ impl<'le> TElement for GeckoElement<'le> {
type TraversalChildrenIterator = GeckoChildrenIterator<'le>; type TraversalChildrenIterator = GeckoChildrenIterator<'le>;
fn inheritance_parent(&self) -> Option<Self> { fn inheritance_parent(&self) -> Option<Self> {
if self.is_pseudo_element() { if self.implemented_pseudo_element().is_some() {
return self.pseudo_element_originating_element(); return self.pseudo_element_originating_element();
} }
@ -1471,7 +1471,7 @@ impl<'le> TElement for GeckoElement<'le> {
#[inline] #[inline]
fn skip_item_display_fixup(&self) -> bool { fn skip_item_display_fixup(&self) -> bool {
debug_assert!( debug_assert!(
!self.is_pseudo_element(), self.implemented_pseudo_element().is_none(),
"Just don't call me if I'm a pseudo, you should know the answer already" "Just don't call me if I'm a pseudo, you should know the answer already"
); );
self.is_root_of_native_anonymous_subtree() self.is_root_of_native_anonymous_subtree()
@ -1918,14 +1918,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
Some(shadow.host()) Some(shadow.host())
} }
#[inline]
fn is_pseudo_element(&self) -> bool {
self.implemented_pseudo_element().is_some()
}
#[inline] #[inline]
fn pseudo_element_originating_element(&self) -> Option<Self> { fn pseudo_element_originating_element(&self) -> Option<Self> {
debug_assert!(self.is_pseudo_element()); debug_assert!(self.implemented_pseudo_element().is_some());
let parent = self.closest_anon_subtree_root_parent()?; let parent = self.closest_anon_subtree_root_parent()?;
// FIXME(emilio): Special-case for <input type="number">s // FIXME(emilio): Special-case for <input type="number">s

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

@ -366,10 +366,6 @@ where
self.element.is_root() self.element.is_root()
} }
fn is_pseudo_element(&self) -> bool {
self.element.is_pseudo_element()
}
fn pseudo_element_originating_element(&self) -> Option<Self> { fn pseudo_element_originating_element(&self) -> Option<Self> {
self.element self.element
.pseudo_element_originating_element() .pseudo_element_originating_element()

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

@ -734,7 +734,10 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
E: TElement, E: TElement,
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
if element.map_or(false, |e| e.is_pseudo_element()) { if element
.and_then(|e| e.implemented_pseudo_element())
.is_some()
{
// It'd be nice to assert `self.style.pseudo == Some(&pseudo)`, // It'd be nice to assert `self.style.pseudo == Some(&pseudo)`,
// but we do resolve ::-moz-list pseudos on ::before / ::after // but we do resolve ::-moz-list pseudos on ::before / ::after
// content, sigh. // content, sigh.

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

@ -233,7 +233,7 @@ where
let mut pseudo_styles = EagerPseudoStyles::default(); let mut pseudo_styles = EagerPseudoStyles::default();
if !self.element.is_pseudo_element() { if self.element.implemented_pseudo_element().is_none() {
let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() { let layout_parent_style_for_pseudo = if primary_style.style().is_display_contents() {
layout_parent_style layout_parent_style
} else { } else {
@ -293,6 +293,10 @@ where
layout_parent_style: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>, pseudo: Option<&PseudoElement>,
) -> ResolvedStyle { ) -> ResolvedStyle {
debug_assert!(
self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
"Pseudo-elements can't have other pseudos!"
);
debug_assert!(pseudo.map_or(true, |p| p.is_eager())); debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
let implemented_pseudo = self.element.implemented_pseudo_element(); let implemented_pseudo = self.element.implemented_pseudo_element();
@ -473,8 +477,8 @@ where
); );
debug_assert!(pseudo_element.is_eager()); debug_assert!(pseudo_element.is_eager());
debug_assert!( debug_assert!(
!self.element.is_pseudo_element(), self.element.implemented_pseudo_element().is_none(),
"Element pseudos can't have any other eager pseudo." "Element pseudos can't have any other pseudo."
); );
let mut applicable_declarations = ApplicableDeclarationList::new(); let mut applicable_declarations = ApplicableDeclarationList::new();

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

@ -1,23 +0,0 @@
<!doctype html>
<title>CSS Test Reference</title>
<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<style>
div {
display: inline-block;
}
div div {
list-style-type: initial;
display: list-item;
}
li {
list-style-type: none;
}
</style>
<ul>
<li><div><div>Foo</div></div>Bar
<script>
// 100px from the ref.
document.querySelector("ul").style.marginLeft = 100 - document.querySelector("div div").offsetWidth + "px";
</script>

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

@ -1,17 +0,0 @@
<!doctype html>
<title>CSS Test: Nested ::marker with `content` property generates another ::marker</title>
<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1539171">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1543758">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<link rel="match" href="nested-marker-content-ref.html">
<style>
ul { margin-left: 100px }
::marker {
display: list-item;
content: "Foo";
}
</style>
<ul>
<li>Bar

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

@ -1,36 +0,0 @@
<!doctype html>
<title>::marker pseudo-elements generated by ::before and ::after are not addressable by selectors</title>
<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1539171">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1543758">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<link rel="match" href="nested-marker-ref.html">
<style>
li, ::marker {
color: red;
}
li::before, li::after {
display: list-item;
content: "Before";
}
li::after {
content: "After";
}
.tweak::marker {
color: blue;
}
.tweak, .tweak::before, .tweak::after {
color: initial;
}
</style>
<ol>
<li>Foo
<li>Bar
<script>
window.onload = function() {
document.body.offsetTop;
for (let li of document.querySelectorAll("li"))
li.classList.add("tweak");
}
</script>

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

@ -1,15 +0,0 @@
<!doctype html>
<title>CSS test reference</title>
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<style>
li::marker {
color: blue;
}
div {
display: list-item;
}
</style>
<ol>
<li><div>Before</div>Foo<div>After</div>
<li><div>Before</div>Bar<div>After</div>

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

@ -1,26 +0,0 @@
<!doctype html>
<title>::marker pseudo-elements generated by ::before and ::after are not addressable by global selectors</title>
<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1539171">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1543758">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<link rel="match" href="nested-marker-ref.html">
<style>
::marker {
color: red;
}
li::marker {
color: blue;
}
li::before, li::after {
display: list-item;
content: "Before";
}
li::after {
content: "After";
}
</style>
<ol>
<li>Foo
<li>Bar