mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Support CSS shadow parts
This commit is contained in:
parent
667a753448
commit
a852c0a86a
10 changed files with 1882 additions and 29 deletions
|
|
@ -1003,6 +1003,7 @@ GK_ATOM(parameter, "parameter")
|
|||
GK_ATOM(parent, "parent")
|
||||
GK_ATOM(parentfocused, "parentfocused")
|
||||
GK_ATOM(parsetype, "parsetype")
|
||||
GK_ATOM(part, "part")
|
||||
GK_ATOM(password, "password")
|
||||
GK_ATOM(pattern, "pattern")
|
||||
GK_ATOM(patternSeparator, "pattern-separator")
|
||||
|
|
|
|||
|
|
@ -823,16 +823,37 @@ nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc,
|
|||
}
|
||||
}
|
||||
|
||||
// The approach in WalkAllShadowRootHostRules seems reasonable on the surface and reminds me of what is done with mScopedRoot elsewhere. But something important is missing, either here or in the code that would normally use it.
|
||||
|
||||
void
|
||||
nsBindingManager::WalkAllShadowRootHostRules(nsIStyleRuleProcessor::EnumFunc aFunc,
|
||||
ElementDependentRuleProcessorData* aData)
|
||||
{
|
||||
aData->mTreeMatchContext.mOnlyMatchHostPseudo = true;
|
||||
WalkAllRules(aFunc, aData, true);
|
||||
aData->mTreeMatchContext.mOnlyMatchHostPseudo = false;
|
||||
}
|
||||
{
|
||||
if (!mBoundContentSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool oldOnlyMatchHostPseudo = aData->mTreeMatchContext.mOnlyMatchHostPseudo;
|
||||
nsIContent* oldScopedRoot = aData->mTreeMatchContext.mScopedRoot;
|
||||
aData->mTreeMatchContext.mOnlyMatchHostPseudo = true;
|
||||
|
||||
for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsIContent* boundContent = iter.Get()->GetKey();
|
||||
ShadowRoot* shadowRoot = boundContent->GetShadowRoot();
|
||||
if (!shadowRoot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsXBLBinding* binding = shadowRoot->GetAssociatedBinding();
|
||||
if (!binding) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aData->mTreeMatchContext.mScopedRoot = boundContent;
|
||||
binding->WalkRules(aFunc, aData);
|
||||
}
|
||||
|
||||
aData->mTreeMatchContext.mScopedRoot = oldScopedRoot;
|
||||
aData->mTreeMatchContext.mOnlyMatchHostPseudo = oldOnlyMatchHostPseudo;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext,
|
||||
|
|
|
|||
|
|
@ -404,6 +404,22 @@ RuleHash::AppendUniversalRule(const RuleSelectorPair& aRuleInfo)
|
|||
RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
|
||||
}
|
||||
|
||||
static bool
|
||||
SelectorContainsPseudoClass(nsCSSSelector* aSelector, CSSPseudoClassType aType)
|
||||
{
|
||||
for (nsCSSSelector* selector = aSelector; selector; selector = selector->mNext) {
|
||||
for (nsPseudoClassList* pseudoClass = selector->mPseudoClassList;
|
||||
pseudoClass;
|
||||
pseudoClass = pseudoClass->mNext) {
|
||||
if (pseudoClass->mType == aType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo)
|
||||
{
|
||||
|
|
@ -411,7 +427,10 @@ RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo)
|
|||
if (selector->IsPseudoElement()) {
|
||||
selector = selector->mNext;
|
||||
}
|
||||
if (nullptr != selector->mIDList) {
|
||||
if (SelectorContainsPseudoClass(selector, CSSPseudoClassType::part)) {
|
||||
AppendUniversalRule(aRuleInfo);
|
||||
RULE_HASH_STAT_INCREMENT(mUniversalSelectors);
|
||||
} else if (nullptr != selector->mIDList) {
|
||||
AppendRuleToTable(&mIdTable, selector->mIDList->mAtom, aRuleInfo);
|
||||
RULE_HASH_STAT_INCREMENT(mIdSelectors);
|
||||
} else if (nullptr != selector->mClassList) {
|
||||
|
|
@ -452,6 +471,10 @@ LookForTargetPseudo(nsCSSSelector* aSelector,
|
|||
nsRestyleHint* possibleChange)
|
||||
{
|
||||
if (aMatchContext->mOnlyMatchHostPseudo) {
|
||||
if (SelectorContainsPseudoClass(aSelector, CSSPseudoClassType::part)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
while (aSelector && aSelector->mNext != nullptr) {
|
||||
aSelector = aSelector->mNext;
|
||||
}
|
||||
|
|
@ -502,7 +525,8 @@ ContentEnumFunc(const RuleValue& value,
|
|||
data->mTreeMatchContext.SetHaveRelevantLink();
|
||||
}
|
||||
// XXX: Ignore the ancestor filter if we're testing the assigned slot.
|
||||
bool useAncestorFilter = !(data->mTreeMatchContext.mForAssignedSlot);
|
||||
bool useAncestorFilter = !(data->mTreeMatchContext.mForAssignedSlot ||
|
||||
data->mTreeMatchContext.mOnlyMatchHostPseudo);
|
||||
if (useAncestorFilter && ancestorFilter &&
|
||||
!ancestorFilter->MightHaveMatchingAncestor<RuleValue::eMaxAncestorHashes>(
|
||||
value.mAncestorSelectorHashes)) {
|
||||
|
|
@ -556,9 +580,18 @@ ContentEnumFunc(const RuleValue& value,
|
|||
nodeContext,
|
||||
data->mTreeMatchContext,
|
||||
selectorFlags)) {
|
||||
Element* treeMatchStart = data->mElement;
|
||||
if (SelectorContainsPseudoClass(selector, CSSPseudoClassType::part)) {
|
||||
nsIContent* partHost = data->mElement->GetContainingShadowHost();
|
||||
if (!partHost || !partHost->IsElement()) {
|
||||
return;
|
||||
}
|
||||
treeMatchStart = partHost->AsElement();
|
||||
}
|
||||
|
||||
nsCSSSelector* next = selector->mNext;
|
||||
if (!next || nsCSSRuleUtils::SelectorMatchesTree(
|
||||
data->mElement,
|
||||
treeMatchStart,
|
||||
next,
|
||||
data->mTreeMatchContext,
|
||||
nodeContext.mIsRelevantLink ? SelectorMatchesTreeFlags(0)
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
|
|||
result->mCasedTag = mCasedTag;
|
||||
result->mOperator = mOperator;
|
||||
result->mPseudoType = mPseudoType;
|
||||
result->mHybridPseudoType = mHybridPseudoType;
|
||||
|
||||
NS_IF_CLONE(mIDList);
|
||||
NS_IF_CLONE(mClassList);
|
||||
|
|
|
|||
|
|
@ -6690,6 +6690,8 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
|
|||
if (hybridPseudoElementType == CSSPseudoElementType::slotted) {
|
||||
pseudoClassType = CSSPseudoClassType::slotted;
|
||||
aFlags |= SelectorParsingFlags::eDisallowCombinators;
|
||||
} else if (hybridPseudoElementType == CSSPseudoElementType::part) {
|
||||
pseudoClassType = CSSPseudoClassType::part;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6842,6 +6844,28 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
|
|||
UngetToken();
|
||||
return eSelectorParsingStatus_Error;
|
||||
}
|
||||
else if (hybridPseudoElementType != CSSPseudoElementType::NotPseudo) {
|
||||
aSelector.SetHybridPseudoType(hybridPseudoElementType);
|
||||
// Ensure hybrid pseudo-elements are rejected if they're not allowed.
|
||||
if (disallowPseudoElements) {
|
||||
UngetToken();
|
||||
return eSelectorParsingStatus_Error;
|
||||
}
|
||||
|
||||
if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
|
||||
parsingStatus =
|
||||
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
|
||||
}
|
||||
else if (nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) {
|
||||
parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector,
|
||||
pseudoClassType,
|
||||
flags);
|
||||
}
|
||||
else {
|
||||
MOZ_ASSERT(false, "unexpected hybrid pseudo-element");
|
||||
parsingStatus = eSelectorParsingStatus_Error;
|
||||
}
|
||||
}
|
||||
else if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
|
||||
parsingStatus =
|
||||
ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
|
||||
|
|
@ -6853,14 +6877,6 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
|
|||
else {
|
||||
MOZ_ASSERT(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType),
|
||||
"unexpected pseudo with function token");
|
||||
if (hybridPseudoElementType != CSSPseudoElementType::NotPseudo) {
|
||||
aSelector.SetHybridPseudoType(hybridPseudoElementType);
|
||||
// Ensure hybrid pseudo-elements are rejected if they're not allowed.
|
||||
if (disallowPseudoElements) {
|
||||
UngetToken();
|
||||
return eSelectorParsingStatus_Error;
|
||||
}
|
||||
}
|
||||
parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector,
|
||||
pseudoClassType,
|
||||
flags);
|
||||
|
|
|
|||
|
|
@ -94,6 +94,9 @@ CSS_PSEUDO_CLASS(nthLastOfType, ":nth-last-of-type", 0, "")
|
|||
// Match slot nodes.
|
||||
CSS_PSEUDO_CLASS(slotted, ":slotted", 0, "layout.css.slotted-pseudo.enabled")
|
||||
|
||||
// Match elements exposed through a shadow host's part attribute.
|
||||
CSS_PSEUDO_CLASS(part, ":part", 0, "dom.webcomponents.enabled")
|
||||
|
||||
// Match nodes that are HTML but not XHTML
|
||||
CSS_PSEUDO_CLASS(mozIsHTML, ":-moz-is-html", 0, "")
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,8 @@ nsCSSPseudoClasses::HasStringArg(Type aType)
|
|||
aType == Type::mozSystemMetric ||
|
||||
aType == Type::mozLocaleDir ||
|
||||
aType == Type::mozDir ||
|
||||
aType == Type::dir;
|
||||
aType == Type::dir ||
|
||||
aType == Type::part;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -210,5 +211,6 @@ nsCSSPseudoClasses::IsUserActionPseudoClass(Type aType)
|
|||
/* static */ bool
|
||||
nsCSSPseudoClasses::IsHybridPseudoElement(Type aType)
|
||||
{
|
||||
return aType == Type::slotted;
|
||||
return aType == Type::slotted ||
|
||||
aType == Type::part;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,13 @@
|
|||
CSS_PSEUDO_ELEMENT(after, ":after", CSS_PSEUDO_ELEMENT_IS_CSS2)
|
||||
CSS_PSEUDO_ELEMENT(before, ":before", CSS_PSEUDO_ELEMENT_IS_CSS2)
|
||||
|
||||
// XXX: ::slotted() is treated as if it were a pseudo-class, and
|
||||
// is never parsed as a pseudo-element.
|
||||
// XXX: ::slotted() and ::part() are treated as if they were pseudo-classes,
|
||||
// and are never parsed as pseudo-elements.
|
||||
CSS_PSEUDO_ELEMENT(slotted, ":slotted",
|
||||
CSS_PSEUDO_ELEMENT_SUPPORTS_TREE_ABIDING)
|
||||
CSS_PSEUDO_ELEMENT(part, ":part",
|
||||
CSS_PSEUDO_ELEMENT_SUPPORTS_TREE_ABIDING |
|
||||
CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE)
|
||||
|
||||
CSS_PSEUDO_ELEMENT(backdrop, ":backdrop", 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ nsCSSPseudoElements::IsCSS2PseudoElement(nsIAtom *aAtom)
|
|||
/* static */ bool
|
||||
nsCSSPseudoElements::IsHybridPseudoElement(CSSPseudoElementType aType)
|
||||
{
|
||||
return aType == CSSPseudoElementType::slotted;
|
||||
return aType == CSSPseudoElementType::slotted ||
|
||||
aType == CSSPseudoElementType::part;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue