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-11 15:42:56 +00:00
Родитель 5188ad0370
Коммит e95dd01125
6 изменённых файлов: 103 добавлений и 62 удалений

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

@ -636,6 +636,61 @@ int32_t CustomElementRegistry::InferNamespace(
return kNameSpaceID_XHTML; 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 // https://html.spec.whatwg.org/multipage/scripting.html#element-definition
void CustomElementRegistry::Define( void CustomElementRegistry::Define(
JSContext* aCx, const nsAString& aName, JSContext* aCx, const nsAString& aName,
@ -782,6 +837,8 @@ void CustomElementRegistry::Define(
auto callbacksHolder = MakeUnique<LifecycleCallbacks>(); auto callbacksHolder = MakeUnique<LifecycleCallbacks>();
nsTArray<RefPtr<nsAtom>> observedAttributes; nsTArray<RefPtr<nsAtom>> observedAttributes;
AutoTArray<RefPtr<nsAtom>, 2> disabledFeatures;
bool disableInternals = false;
{ // Set mIsCustomDefinitionRunning. { // Set mIsCustomDefinitionRunning.
/** /**
* 9. Set this CustomElementRegistry's element definition is running flag. * 9. Set this CustomElementRegistry's element definition is running flag.
@ -841,58 +898,31 @@ void CustomElementRegistry::Define(
* any exceptions from the conversion. * any exceptions from the conversion.
*/ */
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) { 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)) { * 14.6. Let disabledFeatures be an empty sequence<DOMString>.
aRv.NoteJSContextException(aCx); * 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; return;
} }
if (!observedAttributesIterable.isUndefined()) { // 14.9. Set disableInternals to true if disabledFeaturesSequence contains
if (!observedAttributesIterable.isObject()) { // "internals".
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>( disableInternals = disabledFeatures.Contains(
NS_LITERAL_STRING("observedAttributes")); static_cast<nsStaticAtom*>(nsGkAtoms::internals));
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;
}
}
}
} }
} // Unset mIsCustomDefinitionRunning } // Unset mIsCustomDefinitionRunning
@ -915,7 +945,8 @@ void CustomElementRegistry::Define(
RefPtr<CustomElementDefinition> definition = new CustomElementDefinition( RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(
nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor, nameAtom, localNameAtom, nameSpaceID, &aFunctionConstructor,
std::move(observedAttributes), std::move(callbacksHolder)); std::move(observedAttributes), std::move(callbacksHolder),
disableInternals);
CustomElementDefinition* def = definition.get(); CustomElementDefinition* def = definition.get();
mCustomDefinitions.Put(nameAtom, definition.forget()); mCustomDefinitions.Put(nameAtom, definition.forget());
@ -1405,13 +1436,14 @@ CustomElementDefinition::CustomElementDefinition(
nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID, nsAtom* aType, nsAtom* aLocalName, int32_t aNamespaceID,
CustomElementConstructor* aConstructor, CustomElementConstructor* aConstructor,
nsTArray<RefPtr<nsAtom>>&& aObservedAttributes, nsTArray<RefPtr<nsAtom>>&& aObservedAttributes,
UniquePtr<LifecycleCallbacks>&& aCallbacks) UniquePtr<LifecycleCallbacks>&& aCallbacks, bool aDisableInternals)
: mType(aType), : mType(aType),
mLocalName(aLocalName), mLocalName(aLocalName),
mNamespaceID(aNamespaceID), mNamespaceID(aNamespaceID),
mConstructor(aConstructor), mConstructor(aConstructor),
mObservedAttributes(std::move(aObservedAttributes)), mObservedAttributes(std::move(aObservedAttributes)),
mCallbacks(std::move(aCallbacks)) {} mCallbacks(std::move(aCallbacks)),
mDisableInternals(aDisableInternals) {}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

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

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

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

@ -2620,6 +2620,12 @@
value: false value: false
mirror: always 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? # Is support for the Web GPU API enabled?
- name: dom.webgpu.enable - name: dom.webgpu.enable
type: RelaxedAtomicBool type: RelaxedAtomicBool

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

@ -17,18 +17,11 @@
[customElements.define must rethrow an exception thrown while getting additional formAssociated callbacks on the constructor prototype] [customElements.define must rethrow an exception thrown while getting additional formAssociated callbacks on the constructor prototype]
expected: FAIL 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] [customElements.define must get four additional callbacks on the prototype if formAssociated is converted to true]
expected: FAIL expected: FAIL
[customElements.define must rethrow an exception thrown while getting disabledFeatures on the constructor prototype] [customElements.define must not throw when defining another custom element in a different global object during Get(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>]
expected: FAIL 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("insertion", "insertion"),
Atom("integer", "integer"), Atom("integer", "integer"),
Atom("integrity", "integrity"), Atom("integrity", "integrity"),
Atom("internals", "internals"),
Atom("intersection", "intersection"), Atom("intersection", "intersection"),
Atom("intersectionobserverlist", "intersectionobserverlist"), Atom("intersectionobserverlist", "intersectionobserverlist"),
Atom("is", "is"), Atom("is", "is"),