Bug 1552313 - Implement disableShadow; r=smaug,edgar

Differential Revision: https://phabricator.services.mozilla.com/D52157

--HG--
extra : moz-landing-system : lando
This commit is contained in:
John Dai 2019-11-11 15:42:58 +00:00
parent e95dd01125
commit 708988da6b
9 changed files with 61 additions and 28 deletions

View File

@ -839,6 +839,7 @@ void CustomElementRegistry::Define(
nsTArray<RefPtr<nsAtom>> observedAttributes;
AutoTArray<RefPtr<nsAtom>, 2> disabledFeatures;
bool disableInternals = false;
bool disableShadow = false;
{ // Set mIsCustomDefinitionRunning.
/**
* 9. Set this CustomElementRegistry's element definition is running flag.
@ -923,6 +924,11 @@ void CustomElementRegistry::Define(
// "internals".
disableInternals = disabledFeatures.Contains(
static_cast<nsStaticAtom*>(nsGkAtoms::internals));
// 14.10. Set disableShadow to true if disabledFeaturesSequence contains
// "shadow".
disableShadow = disabledFeatures.Contains(
static_cast<nsStaticAtom*>(nsGkAtoms::shadow));
}
} // Unset mIsCustomDefinitionRunning
@ -946,7 +952,7 @@ void CustomElementRegistry::Define(
RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(
nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor,
std::move(observedAttributes), std::move(callbacksHolder),
disableInternals);
disableInternals, disableShadow);
CustomElementDefinition* def = definition.get();
mCustomDefinitions.Put(nameAtom, definition.forget());
@ -1083,8 +1089,19 @@ already_AddRefed<Promise> CustomElementRegistry::WhenDefined(
namespace {
MOZ_CAN_RUN_SCRIPT
static void DoUpgrade(Element* aElement, CustomElementConstructor* aConstructor,
static void DoUpgrade(Element* aElement, CustomElementDefinition* aDefinition,
CustomElementConstructor* aConstructor,
ErrorResult& aRv) {
if (aDefinition->mDisableShadow && aElement->GetShadowRoot()) {
aRv.ThrowDOMException(
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
nsPrintfCString(
"Custom element upgrade to '%s' is disabled due to shadow root "
"already exists",
NS_ConvertUTF16toUTF8(aDefinition->mType->GetUTF16String()).get()));
return;
}
JS::Rooted<JS::Value> constructResult(RootingCx());
// Rethrow the exception since it might actually throw the exception from the
// upgrade steps back out to the caller of document.createElement.
@ -1155,7 +1172,8 @@ void CustomElementRegistry::Upgrade(Element* aElement,
AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
// Step 6 and step 7.
DoUpgrade(aElement, MOZ_KnownLive(aDefinition->mConstructor), aRv);
DoUpgrade(aElement, aDefinition, MOZ_KnownLive(aDefinition->mConstructor),
aRv);
if (aRv.Failed()) {
data->mState = CustomElementData::State::eFailed;
// Empty element's custom element reaction queue.
@ -1436,14 +1454,16 @@ CustomElementDefinition::CustomElementDefinition(
nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID,
CustomElementConstructor* aConstructor,
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
UniquePtr<LifecycleCallbacks>&& aCallbacks, bool aDisableInternals)
UniquePtr<LifecycleCallbacks>&& aCallbacks, bool aDisableInternals,
bool aDisableShadow)
: mType(aType),
mLocalName(aLocalName),
mNamespaceID(aNamespaceID),
mConstructor(aConstructor),
mObservedAttributes(std::move(aObservedAttributes)),
mCallbacks(std::move(aCallbacks)),
mDisableInternals(aDisableInternals) {}
mDisableInternals(aDisableInternals),
mDisableShadow(aDisableShadow) {}
} // namespace dom
} // namespace mozilla

View File

@ -138,7 +138,7 @@ struct CustomElementDefinition {
CustomElementConstructor* aConstructor,
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
UniquePtr<LifecycleCallbacks>&& aCallbacks,
bool aDisableInternals);
bool aDisableInternals, bool aDisableShadow);
// The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
// this would be x-foo.
@ -162,6 +162,9 @@ struct CustomElementDefinition {
// Determine whether to allow to attachInternals() for this custom element.
bool mDisableInternals = false;
// Determine whether to allow to attachShadow() for this custom element.
bool mDisableShadow = false;
// A construction stack. Use nullptr to represent an "already constructed
// marker".
nsTArray<RefPtr<Element>> mConstructionStack;

View File

@ -977,8 +977,8 @@ bool Element::CanAttachShadowDOM() const {
* return false.
*/
nsAtom* nameAtom = NodeInfo()->NameAtom();
if (!(nsContentUtils::IsCustomElementName(nameAtom,
NodeInfo()->NamespaceID()) ||
uint32_t namespaceID = NodeInfo()->NamespaceID();
if (!(nsContentUtils::IsCustomElementName(nameAtom, namespaceID) ||
nameAtom == nsGkAtoms::article || nameAtom == nsGkAtoms::aside ||
nameAtom == nsGkAtoms::blockquote || nameAtom == nsGkAtoms::body ||
nameAtom == nsGkAtoms::div || nameAtom == nsGkAtoms::footer ||
@ -991,6 +991,30 @@ bool Element::CanAttachShadowDOM() const {
return false;
}
/**
* 3. If context objects local name is a valid custom element name, or
* context objects is value is not null, then:
* If definition is not null and definitions disable shadow is true, then
* return false.
*/
// It will always have CustomElementData when the element is a valid custom
// element or has is value.
CustomElementData* ceData = GetCustomElementData();
if (StaticPrefs::dom_webcomponents_elementInternals_enabled() && ceData) {
CustomElementDefinition* definition = ceData->GetCustomElementDefinition();
// If the definition is null, the element possible hasn't yet upgraded.
// Fallback to use LookupCustomElementDefinition to find its definition.
if (!definition) {
definition = nsContentUtils::LookupCustomElementDefinition(
NodeInfo()->GetDocument(), nameAtom, namespaceID,
ceData->GetCustomElementType());
}
if (definition && definition->mDisableShadow) {
return false;
}
}
return true;
}
@ -1009,11 +1033,11 @@ already_AddRefed<ShadowRoot> Element::AttachShadow(const ShadowRootInit& aInit,
}
/**
* 3. If context object is a shadow host, then throw
* an "InvalidStateError" DOMException.
* 4. If context object is a shadow host, then throw
* an "NotSupportedError" DOMException.
*/
if (GetShadowRoot()) {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}

View File

@ -1,5 +0,0 @@
[upgrading.html]
max-asserts: 4
[If definition's disable shadow is true and element's shadow root is non-null, then throw a "NotSupportedError" DOMException.]
expected: FAIL

View File

@ -1,7 +0,0 @@
[Element-interface-attachShadow-custom-element.html]
[Element.attachShadow for an autonomous custom element with disabledFeatures=["shadow"\] should throw a NotSupportedError]
expected: FAIL
[Element.attachShadow for a customized built-in element with disabledFeatures=["shadow"\] should throw a NotSupportedError]
expected: FAIL

View File

@ -1,4 +0,0 @@
[Element-interface-attachShadow.html]
[Element.attachShadow must throw a NotSupportedError if the context object already hosts a shadow tree]
expected: FAIL

View File

@ -0,0 +1 @@
prefs: [dom.webcomponents.elementInternals.enabled:true]

View File

@ -77,7 +77,7 @@ test(() => {
test(() => {
class CapitalShadowDisabledElement extends HTMLElement {
static get disabledFeatures() { return ['shadow']; }
static get disabledFeatures() { return ['SHADOW']; }
}
customElements.define('capital-shadow-disabled-element', CapitalShadowDisabledElement);

View File

@ -1088,6 +1088,7 @@ STATIC_ATOMS = [
Atom("seltype", "seltype"),
Atom("setcookie", "set-cookie"),
Atom("setter", "setter"),
Atom("shadow", "shadow"),
Atom("shape", "shape"),
Atom("show", "show"),
Atom("showcaret", "showcaret"),