Bug 1552313 - Implement custom element disabledFeatures and disableInternals; r=smaug,edgar

- Introduce `dom.webcomponents.elementInternals.enabled` for custom element's elementInternals.
- Implement disabledFeatures static field and disableInternals.
- Refactor get observedAttributes sequence.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
John Dai 2019-11-12 11:27:45 +00:00
Родитель e8e03f5a05
Коммит 128e81de25
6 изменённых файлов: 103 добавлений и 62 удалений

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

@ -636,6 +636,61 @@ int32_t CustomElementRegistry::InferNamespace(
return kNameSpaceID_XHTML;
}
bool CustomElementRegistry::JSObjectToAtomArray(
JSContext* aCx, JS::Handle<JSObject*> aConstructor, const char16_t* aName,
nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv) {
JS::RootedValue iterable(aCx, JS::UndefinedValue());
if (!JS_GetUCProperty(aCx, aConstructor, aName,
std::char_traits<char16_t>::length(aName), &iterable)) {
aRv.NoteJSContextException(aCx);
return false;
}
if (!iterable.isUndefined()) {
if (!iterable.isObject()) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(nsDependentString(aName));
return false;
}
JS::ForOfIterator iter(aCx);
if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) {
aRv.NoteJSContextException(aCx);
return false;
}
if (!iter.valueIsIterable()) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(nsDependentString(aName));
return false;
}
JS::Rooted<JS::Value> attribute(aCx);
while (true) {
bool done;
if (!iter.next(&attribute, &done)) {
aRv.NoteJSContextException(aCx);
return false;
}
if (done) {
break;
}
nsAutoString attrStr;
if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify,
attrStr)) {
aRv.NoteJSContextException(aCx);
return false;
}
if (!aArray.AppendElement(NS_Atomize(attrStr))) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return false;
}
}
}
return true;
}
// https://html.spec.whatwg.org/multipage/scripting.html#element-definition
void CustomElementRegistry::Define(
JSContext* aCx, const nsAString& aName,
@ -782,6 +837,8 @@ void CustomElementRegistry::Define(
auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
nsTArray<RefPtr<nsAtom>> observedAttributes;
AutoTArray<RefPtr<nsAtom>, 2> disabledFeatures;
bool disableInternals = false;
{ // Set mIsCustomDefinitionRunning.
/**
* 9. Set this CustomElementRegistry's element definition is running flag.
@ -841,58 +898,31 @@ void CustomElementRegistry::Define(
* any exceptions from the conversion.
*/
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
JS::Rooted<JS::Value> observedAttributesIterable(aCx);
if (!JSObjectToAtomArray(aCx, constructor, u"observedAttributes",
observedAttributes, aRv)) {
return;
}
}
if (!JS_GetProperty(aCx, constructor, "observedAttributes",
&observedAttributesIterable)) {
aRv.NoteJSContextException(aCx);
/**
* 14.6. Let disabledFeatures be an empty sequence<DOMString>.
* 14.7. Let disabledFeaturesIterable be Get(constructor,
* "disabledFeatures"). Rethrow any exceptions.
* 14.8. If disabledFeaturesIterable is not undefined, then set
* disabledFeatures to the result of converting
* disabledFeaturesIterable to a sequence<DOMString>.
* Rethrow any exceptions from the conversion.
*/
if (StaticPrefs::dom_webcomponents_elementInternals_enabled()) {
if (!JSObjectToAtomArray(aCx, constructor, u"disabledFeatures",
disabledFeatures, aRv)) {
return;
}
if (!observedAttributesIterable.isUndefined()) {
if (!observedAttributesIterable.isObject()) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
NS_LITERAL_STRING("observedAttributes"));
return;
}
JS::ForOfIterator iter(aCx);
if (!iter.init(observedAttributesIterable,
JS::ForOfIterator::AllowNonIterable)) {
aRv.NoteJSContextException(aCx);
return;
}
if (!iter.valueIsIterable()) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
NS_LITERAL_STRING("observedAttributes"));
return;
}
JS::Rooted<JS::Value> attribute(aCx);
while (true) {
bool done;
if (!iter.next(&attribute, &done)) {
aRv.NoteJSContextException(aCx);
return;
}
if (done) {
break;
}
nsAutoString attrStr;
if (!ConvertJSValueToString(aCx, attribute, eStringify, eStringify,
attrStr)) {
aRv.NoteJSContextException(aCx);
return;
}
if (!observedAttributes.AppendElement(NS_Atomize(attrStr))) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
}
// 14.9. Set disableInternals to true if disabledFeaturesSequence contains
// "internals".
disableInternals = disabledFeatures.Contains(
static_cast<nsStaticAtom*>(nsGkAtoms::internals));
}
} // Unset mIsCustomDefinitionRunning
@ -915,7 +945,8 @@ void CustomElementRegistry::Define(
RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(
nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor,
std::move(observedAttributes), std::move(callbacksHolder));
std::move(observedAttributes), std::move(callbacksHolder),
disableInternals);
CustomElementDefinition* def = definition.get();
mCustomDefinitions.Put(nameAtom, definition.forget());
@ -1405,13 +1436,14 @@ CustomElementDefinition::CustomElementDefinition(
nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID,
CustomElementConstructor* aConstructor,
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
UniquePtr<LifecycleCallbacks>&& aCallbacks)
UniquePtr<LifecycleCallbacks>&& aCallbacks, bool aDisableInternals)
: mType(aType),
mLocalName(aLocalName),
mNamespaceID(aNamespaceID),
mConstructor(aConstructor),
mObservedAttributes(std::move(aObservedAttributes)),
mCallbacks(std::move(aCallbacks)) {}
mCallbacks(std::move(aCallbacks)),
mDisableInternals(aDisableInternals) {}
} // namespace dom
} // namespace mozilla

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

@ -137,7 +137,8 @@ struct CustomElementDefinition {
int32_t aNamespaceID,
CustomElementConstructor* aConstructor,
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
UniquePtr<LifecycleCallbacks>&& aCallbacks);
UniquePtr<LifecycleCallbacks>&& aCallbacks,
bool aDisableInternals);
// The type (name) for this custom element, for <button is="x-foo"> or <x-foo>
// this would be x-foo.
@ -158,6 +159,9 @@ struct CustomElementDefinition {
// The lifecycle callbacks to call for this custom element.
UniquePtr<LifecycleCallbacks> mCallbacks;
// Determine whether to allow to attachInternals() for this custom element.
bool mDisableInternals = false;
// A construction stack. Use nullptr to represent an "already constructed
// marker".
nsTArray<RefPtr<Element>> mConstructionStack;
@ -458,6 +462,10 @@ class CustomElementRegistry final : public nsISupports, public nsWrapperCache {
private:
~CustomElementRegistry();
bool JSObjectToAtomArray(JSContext* aCx, JS::Handle<JSObject*> aConstructor,
const char16_t* aName,
nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv);
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
Document::ElementCallbackType aType, Element* aCustomElement,
LifecycleCallbackArgs* aArgs,

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

@ -2620,6 +2620,12 @@
value: false
mirror: always
# Is support for elementInternals enabled?
- name: dom.webcomponents.elementInternals.enabled
type: bool
value: @IS_NIGHTLY_BUILD@
mirror: always
# Is support for the Web GPU API enabled?
- name: dom.webgpu.enable
type: RelaxedAtomicBool

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

@ -17,18 +17,11 @@
[customElements.define must rethrow an exception thrown while getting additional formAssociated callbacks on the constructor prototype]
expected: FAIL
[customElements.define must rethrow an exception thrown while retrieving Symbol.iterator on disabledFeatures]
expected: FAIL
[customElements.define must get four additional callbacks on the prototype if formAssociated is converted to true]
expected: FAIL
[customElements.define must rethrow an exception thrown while getting disabledFeatures on the constructor prototype]
expected: FAIL
[customElements.define must rethrow an exception thrown while iterating over disabledFeatures to sequence<DOMString>]
expected: FAIL
[customElements.define must rethrow an exception thrown while converting the value of disabledFeatures to sequence<DOMString>]
[customElements.define must not throw when defining another custom element in a different global object during Get(constructor, "prototype")]
expected: FAIL
[customElements.define must get "prototype" property of the constructor]
expected: FAIL

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

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

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

@ -537,6 +537,7 @@ STATIC_ATOMS = [
Atom("insertion", "insertion"),
Atom("integer", "integer"),
Atom("integrity", "integrity"),
Atom("internals", "internals"),
Atom("intersection", "intersection"),
Atom("intersectionobserverlist", "intersectionobserverlist"),
Atom("is", "is"),