diff options
author | athenian200 <athenian200@outlook.com> | 2020-01-27 22:59:08 -0600 |
---|---|---|
committer | athenian200 <athenian200@outlook.com> | 2020-01-27 22:59:08 -0600 |
commit | 3c4f414db74b84f7d2a6fb13fd888a47a153699b (patch) | |
tree | ea81fca559849967a79d598a6f460830762ec9ea /dom | |
parent | 1f8d508258ac5d7d57fc4eb35cac90f28bc8ca03 (diff) | |
parent | c4b0715baaffc541670fd1158557aa7e61e521d3 (diff) | |
download | UXP-3c4f414db74b84f7d2a6fb13fd888a47a153699b.tar UXP-3c4f414db74b84f7d2a6fb13fd888a47a153699b.tar.gz UXP-3c4f414db74b84f7d2a6fb13fd888a47a153699b.tar.lz UXP-3c4f414db74b84f7d2a6fb13fd888a47a153699b.tar.xz UXP-3c4f414db74b84f7d2a6fb13fd888a47a153699b.zip |
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into form-disabled-issue
Diffstat (limited to 'dom')
204 files changed, 4036 insertions, 3068 deletions
diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 3f202d33b..99452df65 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -6,9 +6,11 @@ #include "mozilla/dom/CustomElementRegistry.h" +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/dom/CustomElementRegistryBinding.h" #include "mozilla/dom/HTMLElementBinding.h" #include "mozilla/dom/WebComponentsBinding.h" +#include "mozilla/dom/DocGroup.h" #include "nsIParserService.h" #include "jsapi.h" @@ -18,40 +20,21 @@ namespace dom { void CustomElementCallback::Call() { - ErrorResult rv; + IgnoredErrorResult rv; switch (mType) { - case nsIDocument::eCreated: - { - // For the duration of this callback invocation, the element is being created - // flag must be set to true. - mOwnerData->mElementIsBeingCreated = true; - - // The callback hasn't actually been invoked yet, but we need to flip - // this now in order to enqueue the attached callback. This is a spec - // bug (w3c bug 27437). - mOwnerData->mCreatedCallbackInvoked = true; - - // If ELEMENT is in a document and this document has a browsing context, - // enqueue attached callback for ELEMENT. - nsIDocument* document = mThisObject->GetComposedDoc(); - if (document && document->GetDocShell()) { - nsContentUtils::EnqueueLifecycleCallback( - document, nsIDocument::eAttached, mThisObject); - } - - static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv); - mOwnerData->mElementIsBeingCreated = false; + case nsIDocument::eConnected: + static_cast<LifecycleConnectedCallback *>(mCallback.get())->Call(mThisObject, rv); break; - } - case nsIDocument::eAttached: - static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv); + case nsIDocument::eDisconnected: + static_cast<LifecycleDisconnectedCallback *>(mCallback.get())->Call(mThisObject, rv); break; - case nsIDocument::eDetached: - static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv); + case nsIDocument::eAdopted: + static_cast<LifecycleAdoptedCallback *>(mCallback.get())->Call(mThisObject, + mAdoptedCallbackArgs.mOldDocument, mAdoptedCallbackArgs.mNewDocument, rv); break; case nsIDocument::eAttributeChanged: static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject, - mArgs.name, mArgs.oldValue, mArgs.newValue, rv); + mArgs.name, mArgs.oldValue, mArgs.newValue, mArgs.namespaceURI, rv); break; } } @@ -68,87 +51,164 @@ CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const CustomElementCallback::CustomElementCallback(Element* aThisObject, nsIDocument::ElementCallbackType aCallbackType, - mozilla::dom::CallbackFunction* aCallback, - CustomElementData* aOwnerData) + mozilla::dom::CallbackFunction* aCallback) : mThisObject(aThisObject), mCallback(aCallback), - mType(aCallbackType), - mOwnerData(aOwnerData) + mType(aCallbackType) +{ +} + +//----------------------------------------------------- +// CustomElementConstructor + +already_AddRefed<Element> +CustomElementConstructor::Construct(const char* aExecutionReason, + ErrorResult& aRv) { + CallSetup s(this, aRv, aExecutionReason, + CallbackFunction::eRethrowExceptions); + + JSContext* cx = s.GetContext(); + if (!cx) { + MOZ_ASSERT(aRv.Failed()); + return nullptr; + } + + JS::Rooted<JSObject*> result(cx); + JS::Rooted<JS::Value> constructor(cx, JS::ObjectValue(*mCallback)); + if (!JS::Construct(cx, constructor, JS::HandleValueArray::empty(), &result)) { + aRv.NoteJSContextException(cx); + return nullptr; + } + + RefPtr<Element> element; + if (NS_FAILED(UNWRAP_OBJECT(Element, &result, element))) { + return nullptr; + } + + return element.forget(); } +//----------------------------------------------------- +// CustomElementData + CustomElementData::CustomElementData(nsIAtom* aType) - : mType(aType), - mCurrentCallback(-1), - mElementIsBeingCreated(false), - mCreatedCallbackInvoked(true), - mAssociatedMicroTask(-1) + : CustomElementData(aType, CustomElementData::State::eUndefined) +{ +} + +CustomElementData::CustomElementData(nsIAtom* aType, State aState) + : mState(aState) + , mType(aType) { } void -CustomElementData::RunCallbackQueue() +CustomElementData::SetCustomElementDefinition(CustomElementDefinition* aDefinition) { - // Note: It's possible to re-enter this method. - while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) { - mCallbackQueue[mCurrentCallback]->Call(); + MOZ_ASSERT(mState == State::eCustom); + MOZ_ASSERT(!mCustomElementDefinition); + MOZ_ASSERT(aDefinition->mType == mType); + + mCustomElementDefinition = aDefinition; +} + +CustomElementDefinition* +CustomElementData::GetCustomElementDefinition() +{ + MOZ_ASSERT(mCustomElementDefinition ? mState == State::eCustom + : mState != State::eCustom); + + return mCustomElementDefinition; +} + +nsIAtom* +CustomElementData::GetCustomElementType() +{ + return mType; +} + +void +CustomElementData::Traverse(nsCycleCollectionTraversalCallback& aCb) const +{ + for (uint32_t i = 0; i < mReactionQueue.Length(); i++) { + if (mReactionQueue[i]) { + mReactionQueue[i]->Traverse(aCb); + } } - mCallbackQueue.Clear(); - mCurrentCallback = -1; + if (mCustomElementDefinition) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCustomElementDefinition"); + aCb.NoteNativeChild(mCustomElementDefinition, + NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition)); + } } +void +CustomElementData::Unlink() +{ + mReactionQueue.Clear(); + mCustomElementDefinition = nullptr; +} + +//----------------------------------------------------- +// CustomElementRegistry + +namespace { + +class MOZ_RAII AutoConstructionStackEntry final +{ +public: + AutoConstructionStackEntry(nsTArray<RefPtr<nsGenericHTMLElement>>& aStack, + nsGenericHTMLElement* aElement) + : mStack(aStack) + { + mIndex = mStack.Length(); + mStack.AppendElement(aElement); + } + + ~AutoConstructionStackEntry() + { + MOZ_ASSERT(mIndex == mStack.Length() - 1, + "Removed element should be the last element"); + mStack.RemoveElementAt(mIndex); + } + +private: + nsTArray<RefPtr<nsGenericHTMLElement>>& mStack; + uint32_t mIndex; +}; + +} // namespace anonymous + // Only needed for refcounted objects. NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry) - tmp->mCustomDefinitions.Clear(); + tmp->mConstructors.clear(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomDefinitions) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry) - for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { - nsAutoPtr<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks; - - if (callbacks->mAttributeChangedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mAttributeChangedCallback"); - cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value()); - } - - if (callbacks->mCreatedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mCreatedCallback"); - cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value()); - } - - if (callbacks->mAttachedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mAttachedCallback"); - cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value()); - } - - if (callbacks->mDetachedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mDetachedCallback"); - cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value()); - } - } + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomDefinitions) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry) for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { - aCallbacks.Trace(&iter.UserData()->mConstructor, - "mCustomDefinitions constructor", - aClosure); aCallbacks.Trace(&iter.UserData()->mPrototype, "mCustomDefinitions prototype", aClosure); } + for (ConstructorMap::Enum iter(tmp->mConstructors); !iter.empty(); iter.popFront()) { + aCallbacks.Trace(&iter.front().mutableKey(), + "mConstructors key", + aClosure); + } NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_END @@ -163,97 +223,52 @@ NS_INTERFACE_MAP_END /* static */ bool CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject) { - return Preferences::GetBool("dom.webcomponents.customelements.enabled") || - Preferences::GetBool("dom.webcomponents.enabled"); + return nsContentUtils::IsCustomElementsEnabled(); } -/* static */ already_AddRefed<CustomElementRegistry> -CustomElementRegistry::Create(nsPIDOMWindowInner* aWindow) +CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow) + : mWindow(aWindow) + , mIsCustomDefinitionRunning(false) { MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow->IsInnerWindow()); + MOZ_ALWAYS_TRUE(mConstructors.init()); - if (!aWindow->GetDocShell()) { - return nullptr; - } - - if (!IsCustomElementEnabled()) { - return nullptr; - } - - RefPtr<CustomElementRegistry> customElementRegistry = - new CustomElementRegistry(aWindow); - return customElementRegistry.forget(); -} - -/* static */ void -CustomElementRegistry::ProcessTopElementQueue() -{ - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - - nsTArray<RefPtr<CustomElementData>>& stack = *sProcessingStack; - uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr); - - for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) { - // Callback queue may have already been processed in an earlier - // element queue or in an element queue that was popped - // off more recently. - if (stack[i]->mAssociatedMicroTask != -1) { - stack[i]->RunCallbackQueue(); - stack[i]->mAssociatedMicroTask = -1; - } - } - - // If this was actually the base element queue, don't bother trying to pop - // the first "queue" marker (sentinel). - if (firstQueue != 0) { - stack.SetLength(firstQueue); - } else { - // Don't pop sentinel for base element queue. - stack.SetLength(1); - } + mozilla::HoldJSObjects(this); } -/* static */ void -CustomElementRegistry::XPCOMShutdown() +CustomElementRegistry::~CustomElementRegistry() { - sProcessingStack.reset(); + mozilla::DropJSObjects(this); } -/* static */ Maybe<nsTArray<RefPtr<CustomElementData>>> -CustomElementRegistry::sProcessingStack; - -CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow) - : mWindow(aWindow) - , mIsCustomDefinitionRunning(false) +CustomElementDefinition* +CustomElementRegistry::LookupCustomElementDefinition(nsIAtom* aNameAtom, + nsIAtom* aTypeAtom) const { - mozilla::HoldJSObjects(this); - - if (!sProcessingStack) { - sProcessingStack.emplace(); - // Add the base queue sentinel to the processing stack. - sProcessingStack->AppendElement((CustomElementData*) nullptr); + CustomElementDefinition* data = mCustomDefinitions.GetWeak(aTypeAtom); + if (data && data->mLocalName == aNameAtom) { + return data; } -} -CustomElementRegistry::~CustomElementRegistry() -{ - mozilla::DropJSObjects(this); + return nullptr; } CustomElementDefinition* -CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName, - const nsAString* aIs) const +CustomElementRegistry::LookupCustomElementDefinition(JSContext* aCx, + JSObject* aConstructor) const { - nsCOMPtr<nsIAtom> localNameAtom = NS_Atomize(aLocalName); - nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom; + JS::Rooted<JSObject*> constructor(aCx, js::CheckedUnwrap(aConstructor)); - CustomElementDefinition* data = mCustomDefinitions.Get(typeAtom); - if (data && data->mLocalName == localNameAtom) { - return data; + const auto& ptr = mConstructors.lookup(constructor); + if (!ptr) { + return nullptr; } - return nullptr; + CustomElementDefinition* definition = mCustomDefinitions.GetWeak(ptr->value()); + MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions"); + + return definition; } void @@ -269,7 +284,7 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy typeName = info->NameAtom(); } - if (mCustomDefinitions.Get(typeName)) { + if (mCustomDefinitions.GetWeak(typeName)) { return; } @@ -282,171 +297,129 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy } void -CustomElementRegistry::SetupCustomElement(Element* aElement, - const nsAString* aTypeExtension) +CustomElementRegistry::UnregisterUnresolvedElement(Element* aElement, + nsIAtom* aTypeName) { - nsCOMPtr<nsIAtom> tagAtom = aElement->NodeInfo()->NameAtom(); - nsCOMPtr<nsIAtom> typeAtom = aTypeExtension ? - NS_Atomize(*aTypeExtension) : tagAtom; - - if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) { - // Custom element setup in the parser happens after the "is" - // attribute is added. - aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true); - } - - CustomElementDefinition* data = LookupCustomElementDefinition( - aElement->NodeInfo()->LocalName(), aTypeExtension); - - if (!data) { - // The type extension doesn't exist in the registry, - // thus we don't need to enqueue callback or adjust - // the "is" attribute, but it is possibly an upgrade candidate. - RegisterUnresolvedElement(aElement, typeAtom); - return; - } - - if (data->mLocalName != tagAtom) { - // The element doesn't match the local name for the - // definition, thus the element isn't a custom element - // and we don't need to do anything more. - return; + nsTArray<nsWeakPtr>* candidates; + if (mCandidatesMap.Get(aTypeName, &candidates)) { + MOZ_ASSERT(candidates); + // We don't need to iterate the candidates array and remove the element from + // the array for performance reason. It'll be handled by bug 1396620. + for (size_t i = 0; i < candidates->Length(); ++i) { + nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i)); + if (elem && elem.get() == aElement) { + candidates->RemoveElementAt(i); + } + } } - - // Enqueuing the created callback will set the CustomElementData on the - // element, causing prototype swizzling to occur in Element::WrapObject. - EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data); } -void -CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, - Element* aCustomElement, - LifecycleCallbackArgs* aArgs, - CustomElementDefinition* aDefinition) +/* static */ UniquePtr<CustomElementCallback> +CustomElementRegistry::CreateCustomElementCallback( + nsIDocument::ElementCallbackType aType, Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, + CustomElementDefinition* aDefinition) { - CustomElementData* elementData = aCustomElement->GetCustomElementData(); - - // Let DEFINITION be ELEMENT's definition - CustomElementDefinition* definition = aDefinition; - if (!definition) { - mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo(); - - // Make sure we get the correct definition in case the element - // is a extended custom element e.g. <button is="x-button">. - nsCOMPtr<nsIAtom> typeAtom = elementData ? - elementData->mType.get() : info->NameAtom(); + MOZ_ASSERT(aDefinition, "CustomElementDefinition should not be null"); - definition = mCustomDefinitions.Get(typeAtom); - if (!definition || definition->mLocalName != info->NameAtom()) { - // Trying to enqueue a callback for an element that is not - // a custom element. We are done, nothing to do. - return; - } - } - - if (!elementData) { - // Create the custom element data the first time - // that we try to enqueue a callback. - elementData = new CustomElementData(definition->mType); - // aCustomElement takes ownership of elementData - aCustomElement->SetCustomElementData(elementData); - MOZ_ASSERT(aType == nsIDocument::eCreated, - "First callback should be the created callback"); - } + MOZ_ASSERT(aCustomElement->GetCustomElementData(), + "CustomElementData should exist"); // Let CALLBACK be the callback associated with the key NAME in CALLBACKS. CallbackFunction* func = nullptr; switch (aType) { - case nsIDocument::eCreated: - if (definition->mCallbacks->mCreatedCallback.WasPassed()) { - func = definition->mCallbacks->mCreatedCallback.Value(); + case nsIDocument::eConnected: + if (aDefinition->mCallbacks->mConnectedCallback.WasPassed()) { + func = aDefinition->mCallbacks->mConnectedCallback.Value(); } break; - case nsIDocument::eAttached: - if (definition->mCallbacks->mAttachedCallback.WasPassed()) { - func = definition->mCallbacks->mAttachedCallback.Value(); + case nsIDocument::eDisconnected: + if (aDefinition->mCallbacks->mDisconnectedCallback.WasPassed()) { + func = aDefinition->mCallbacks->mDisconnectedCallback.Value(); } break; - case nsIDocument::eDetached: - if (definition->mCallbacks->mDetachedCallback.WasPassed()) { - func = definition->mCallbacks->mDetachedCallback.Value(); + case nsIDocument::eAdopted: + if (aDefinition->mCallbacks->mAdoptedCallback.WasPassed()) { + func = aDefinition->mCallbacks->mAdoptedCallback.Value(); } break; case nsIDocument::eAttributeChanged: - if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) { - func = definition->mCallbacks->mAttributeChangedCallback.Value(); + if (aDefinition->mCallbacks->mAttributeChangedCallback.WasPassed()) { + func = aDefinition->mCallbacks->mAttributeChangedCallback.Value(); } break; } // If there is no such callback, stop. if (!func) { - return; - } - - if (aType == nsIDocument::eCreated) { - elementData->mCreatedCallbackInvoked = false; - } else if (!elementData->mCreatedCallbackInvoked) { - // Callbacks other than created callback must not be enqueued - // until after the created callback has been invoked. - return; + return nullptr; } // Add CALLBACK to ELEMENT's callback queue. - CustomElementCallback* callback = new CustomElementCallback(aCustomElement, - aType, - func, - elementData); - // Ownership of callback is taken by mCallbackQueue. - elementData->mCallbackQueue.AppendElement(callback); + auto callback = + MakeUnique<CustomElementCallback>(aCustomElement, aType, func); + if (aArgs) { callback->SetArgs(*aArgs); } - if (!elementData->mElementIsBeingCreated) { - CustomElementData* lastData = - sProcessingStack->SafeLastElement(nullptr); - - // A new element queue needs to be pushed if the queue at the - // top of the stack is associated with another microtask level. - bool shouldPushElementQueue = - (!lastData || lastData->mAssociatedMicroTask < - static_cast<int32_t>(nsContentUtils::MicroTaskLevel())); + if (aAdoptedCallbackArgs) { + callback->SetAdoptedCallbackArgs(*aAdoptedCallbackArgs); + } + return Move(callback); +} - // Push a new element queue onto the processing stack when appropriate - // (when we enter a new microtask). - if (shouldPushElementQueue) { - // Push a sentinel value on the processing stack to mark the - // boundary between the element queues. - sProcessingStack->AppendElement((CustomElementData*) nullptr); +/* static */ void +CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, + Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, + CustomElementDefinition* aDefinition) +{ + CustomElementDefinition* definition = aDefinition; + if (!definition) { + definition = aCustomElement->GetCustomElementDefinition(); + if (!definition || + definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) { + return; } + } - sProcessingStack->AppendElement(elementData); - elementData->mAssociatedMicroTask = - static_cast<int32_t>(nsContentUtils::MicroTaskLevel()); - - // Add a script runner to pop and process the element queue at - // the top of the processing stack. - if (shouldPushElementQueue) { - // Lifecycle callbacks enqueued by user agent implementation - // should be invoked prior to returning control back to script. - // Create a script runner to process the top of the processing - // stack as soon as it is safe to run script. - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction(&CustomElementRegistry::ProcessTopElementQueue); - nsContentUtils::AddScriptRunner(runnable); + auto callback = + CreateCustomElementCallback(aType, aCustomElement, aArgs, + aAdoptedCallbackArgs, definition); + if (!callback) { + return; + } + + DocGroup* docGroup = aCustomElement->OwnerDoc()->GetDocGroup(); + if (!docGroup) { + return; + } + + if (aType == nsIDocument::eAttributeChanged) { + nsCOMPtr<nsIAtom> attrName = NS_Atomize(aArgs->name); + if (definition->mObservedAttributes.IsEmpty() || + !definition->mObservedAttributes.Contains(attrName)) { + return; } } + + CustomElementReactionsStack* reactionsStack = + docGroup->CustomElementReactionsStack(); + reactionsStack->EnqueueCallbackReaction(aCustomElement, Move(callback)); } void CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom, JS::MutableHandle<JSObject*> aPrototype) { - mozilla::dom::CustomElementDefinition* definition = mCustomDefinitions.Get(aAtom); + mozilla::dom::CustomElementDefinition* definition = + mCustomDefinitions.GetWeak(aAtom); if (definition) { aPrototype.set(definition->mPrototype); } else { @@ -455,48 +428,29 @@ CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom, } void -CustomElementRegistry::UpgradeCandidates(JSContext* aCx, - nsIAtom* aKey, - CustomElementDefinition* aDefinition) +CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey, + CustomElementDefinition* aDefinition, + ErrorResult& aRv) { + DocGroup* docGroup = mWindow->GetDocGroup(); + if (!docGroup) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return; + } + + // TODO: Bug 1326028 - Upgrade custom element in shadow-including tree order nsAutoPtr<nsTArray<nsWeakPtr>> candidates; mCandidatesMap.RemoveAndForget(aKey, candidates); if (candidates) { + CustomElementReactionsStack* reactionsStack = + docGroup->CustomElementReactionsStack(); for (size_t i = 0; i < candidates->Length(); ++i) { nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i)); if (!elem) { continue; } - elem->RemoveStates(NS_EVENT_STATE_UNRESOLVED); - - // Make sure that the element name matches the name in the definition. - // (e.g. a definition for x-button extending button should match - // <button is="x-button"> but not <x-button>. - if (elem->NodeInfo()->NameAtom() != aDefinition->mLocalName) { - //Skip over this element because definition does not apply. - continue; - } - - MOZ_ASSERT(elem->IsHTMLElement(aDefinition->mLocalName)); - nsWrapperCache* cache; - CallQueryInterface(elem, &cache); - MOZ_ASSERT(cache, "Element doesn't support wrapper cache?"); - - // We want to set the custom prototype in the caller's comparment. - // In the case that element is in a different compartment, - // this will set the prototype on the element's wrapper and - // thus only visible in the wrapper's compartment. - JS::RootedObject wrapper(aCx); - JS::Rooted<JSObject*> prototype(aCx, aDefinition->mPrototype); - if ((wrapper = cache->GetWrapper()) && JS_WrapObject(aCx, &wrapper)) { - if (!JS_SetPrototype(aCx, wrapper, prototype)) { - continue; - } - } - - nsContentUtils::EnqueueLifecycleCallback( - elem->OwnerDoc(), nsIDocument::eCreated, elem, nullptr, aDefinition); + reactionsStack->EnqueueUpgradeReaction(elem, aDefinition); } } } @@ -516,11 +470,7 @@ static const char* kLifeCycleCallbackNames[] = { "connectedCallback", "disconnectedCallback", "adoptedCallback", - "attributeChangedCallback", - // The life cycle callbacks from v0 spec. - "createdCallback", - "attachedCallback", - "detachedCallback" + "attributeChangedCallback" }; static void @@ -600,7 +550,7 @@ CustomElementRegistry::Define(const nsAString& aName, * 3. If this CustomElementRegistry contains an entry with name name, then * throw a "NotSupportedError" DOMException and abort these steps. */ - if (mCustomDefinitions.Get(nameAtom)) { + if (mCustomDefinitions.GetWeak(nameAtom)) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return; } @@ -609,9 +559,13 @@ CustomElementRegistry::Define(const nsAString& aName, * 4. If this CustomElementRegistry contains an entry with constructor constructor, * then throw a "NotSupportedError" DOMException and abort these steps. */ - // TODO: Step 3 of HTMLConstructor also needs a way to look up definition by - // using constructor. So I plans to figure out a solution to support both of - // them in bug 1274159. + const auto& ptr = mConstructors.lookup(constructorUnwrapped); + if (ptr) { + MOZ_ASSERT(mCustomDefinitions.GetWeak(ptr->value()), + "Definition must be found in mCustomDefinitions"); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return; + } /** * 5. Let localName be name. @@ -663,6 +617,7 @@ CustomElementRegistry::Define(const nsAString& aName, JS::Rooted<JSObject*> constructorPrototype(cx); nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks()); + nsCOMArray<nsIAtom> observedAttributes; { // Set mIsCustomDefinitionRunning. /** * 9. Set this CustomElementRegistry's element definition is running flag. @@ -724,6 +679,14 @@ CustomElementRegistry::Define(const nsAString& aName, return; } + // Note: We call the init from the constructorProtoUnwrapped's compartment + // here. + JS::RootedValue rootedv(cx, JS::ObjectValue(*constructorProtoUnwrapped)); + if (!JS_WrapValue(cx, &rootedv) || !callbacksHolder->Init(cx, rootedv)) { + aRv.StealExceptionFromJSContext(cx); + return; + } + /** * 10.5. Let observedAttributes be an empty sequence<DOMString>. * 10.6. If the value of the entry in lifecycleCallbacks with key @@ -735,15 +698,54 @@ CustomElementRegistry::Define(const nsAString& aName, * observedAttributesIterable to a sequence<DOMString>. Rethrow * any exceptions from the conversion. */ - // TODO: Bug 1293921 - Implement connected/disconnected/adopted/attributeChanged lifecycle callbacks for custom elements + if (callbacksHolder->mAttributeChangedCallback.WasPassed()) { + // Enter constructor's compartment. + JSAutoCompartment ac(cx, constructor); + JS::Rooted<JS::Value> observedAttributesIterable(cx); + + if (!JS_GetProperty(cx, constructor, "observedAttributes", + &observedAttributesIterable)) { + aRv.StealExceptionFromJSContext(cx); + return; + } - // Note: We call the init from the constructorProtoUnwrapped's compartment - // here. - JS::RootedValue rootedv(cx, JS::ObjectValue(*constructorProtoUnwrapped)); - if (!JS_WrapValue(cx, &rootedv) || !callbacksHolder->Init(cx, rootedv)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + if (!observedAttributesIterable.isUndefined()) { + if (!observedAttributesIterable.isObject()) { + aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes")); + return; + } + + JS::ForOfIterator iter(cx); + if (!iter.init(observedAttributesIterable, JS::ForOfIterator::AllowNonIterable)) { + aRv.StealExceptionFromJSContext(cx); + return; + } + + if (!iter.valueIsIterable()) { + aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(NS_LITERAL_STRING("observedAttributes")); + return; + } + + JS::Rooted<JS::Value> attribute(cx); + while (true) { + bool done; + if (!iter.next(&attribute, &done)) { + aRv.StealExceptionFromJSContext(cx); + return; + } + if (done) { + break; + } + + nsAutoString attrStr; + if (!ConvertJSValueToString(cx, attribute, eStringify, eStringify, attrStr)) { + aRv.StealExceptionFromJSContext(cx); + return; + } + observedAttributes.AppendElement(NS_Atomize(attrStr)); + } + } + } // Leave constructor's compartment. } // Leave constructorProtoUnwrapped's compartment. } // Unset mIsCustomDefinitionRunning @@ -756,24 +758,34 @@ CustomElementRegistry::Define(const nsAString& aName, // Associate the definition with the custom element. nsCOMPtr<nsIAtom> localNameAtom(NS_Atomize(localName)); LifecycleCallbacks* callbacks = callbacksHolder.forget(); - CustomElementDefinition* definition = + + /** + * 12. Add definition to this CustomElementRegistry. + */ + if (!mConstructors.put(constructorUnwrapped, nameAtom)) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + RefPtr<CustomElementDefinition> definition = new CustomElementDefinition(nameAtom, localNameAtom, - constructor, + &aFunctionConstructor, + Move(observedAttributes), constructorPrototype, callbacks, 0 /* TODO dependent on HTML imports. Bug 877072 */); - /** - * 12. Add definition to this CustomElementRegistry. - */ - mCustomDefinitions.Put(nameAtom, definition); + CustomElementDefinition* def = definition.get(); + mCustomDefinitions.Put(nameAtom, definition.forget()); + + MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(), + "Number of entries should be the same"); /** * 13. 14. 15. Upgrade candidates */ - // TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm - UpgradeCandidates(cx, nameAtom, definition); + UpgradeCandidates(nameAtom, def, aRv); /** * 16. If this CustomElementRegistry's when-defined promise map contains an @@ -796,14 +808,14 @@ CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName, JS::MutableHandle<JS::Value> aRetVal) { nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName)); - CustomElementDefinition* data = mCustomDefinitions.Get(nameAtom); + CustomElementDefinition* data = mCustomDefinitions.GetWeak(nameAtom); if (!data) { aRetVal.setUndefined(); return; } - aRetVal.setObject(*data->mConstructor); + aRetVal.setObjectOrNull(data->mConstructor->Callable()); return; } @@ -823,7 +835,7 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv) return promise.forget(); } - if (mCustomDefinitions.Get(nameAtom)) { + if (mCustomDefinitions.GetWeak(nameAtom)) { promise->MaybeResolve(JS::UndefinedHandleValue); return promise.forget(); } @@ -837,20 +849,346 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv) return promise.forget(); } +namespace { + +static void +DoUpgrade(Element* aElement, + CustomElementConstructor* aConstructor, + ErrorResult& aRv) +{ + // Rethrow the exception since it might actually throw the exception from the + // upgrade steps back out to the caller of document.createElement. + RefPtr<Element> constructResult = + aConstructor->Construct("Custom Element Upgrade", aRv); + if (aRv.Failed()) { + return; + } + + if (!constructResult || constructResult.get() != aElement) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } +} + +} // anonymous namespace + +// https://html.spec.whatwg.org/multipage/scripting.html#upgrades +/* static */ void +CustomElementRegistry::Upgrade(Element* aElement, + CustomElementDefinition* aDefinition, + ErrorResult& aRv) +{ + aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED); + + RefPtr<CustomElementData> data = aElement->GetCustomElementData(); + MOZ_ASSERT(data, "CustomElementData should exist"); + + // Step 1 and step 2. + if (data->mState == CustomElementData::State::eCustom || + data->mState == CustomElementData::State::eFailed) { + return; + } + + // Step 3. + if (!aDefinition->mObservedAttributes.IsEmpty()) { + uint32_t count = aElement->GetAttrCount(); + for (uint32_t i = 0; i < count; i++) { + mozilla::dom::BorrowedAttrInfo info = aElement->GetAttrInfoAt(i); + + const nsAttrName* name = info.mName; + nsIAtom* attrName = name->LocalName(); + + if (aDefinition->IsInObservedAttributeList(attrName)) { + int32_t namespaceID = name->NamespaceID(); + nsAutoString attrValue, namespaceURI; + info.mValue->ToString(attrValue); + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, + namespaceURI); + + LifecycleCallbackArgs args = { + nsDependentAtomString(attrName), + NullString(), + attrValue, + (namespaceURI.IsEmpty() ? NullString() : namespaceURI) + }; + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, + aElement, + &args, nullptr, aDefinition); + } + } + } + + // Step 4. + if (aElement->IsInComposedDoc()) { + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, aElement, + nullptr, nullptr, aDefinition); + } + + // Step 5. + AutoConstructionStackEntry acs(aDefinition->mConstructionStack, + nsGenericHTMLElement::FromContent(aElement)); + + // Step 6 and step 7. + DoUpgrade(aElement, aDefinition->mConstructor, aRv); + if (aRv.Failed()) { + data->mState = CustomElementData::State::eFailed; + // Empty element's custom element reaction queue. + data->mReactionQueue.Clear(); + return; + } + + // Step 8. + data->mState = CustomElementData::State::eCustom; + + // Step 9. + aElement->SetCustomElementDefinition(aDefinition); +} + +//----------------------------------------------------- +// CustomElementReactionsStack + +void +CustomElementReactionsStack::CreateAndPushElementQueue() +{ + MOZ_ASSERT(mRecursionDepth); + MOZ_ASSERT(!mIsElementQueuePushedForCurrentRecursionDepth); + + // Push a new element queue onto the custom element reactions stack. + mReactionsStack.AppendElement(MakeUnique<ElementQueue>()); + mIsElementQueuePushedForCurrentRecursionDepth = true; +} + +void +CustomElementReactionsStack::PopAndInvokeElementQueue() +{ + MOZ_ASSERT(mRecursionDepth); + MOZ_ASSERT(mIsElementQueuePushedForCurrentRecursionDepth); + MOZ_ASSERT(!mReactionsStack.IsEmpty(), + "Reaction stack shouldn't be empty"); + + // Pop the element queue from the custom element reactions stack, + // and invoke custom element reactions in that queue. + const uint32_t lastIndex = mReactionsStack.Length() - 1; + ElementQueue* elementQueue = mReactionsStack.ElementAt(lastIndex).get(); + // Check element queue size in order to reduce function call overhead. + if (!elementQueue->IsEmpty()) { + // It is still not clear what error reporting will look like in custom + // element, see https://github.com/w3c/webcomponents/issues/635. + // We usually report the error to entry global in gecko, so just follow the + // same behavior here. + // This may be null if it's called from parser, see the case of + // attributeChangedCallback in + // https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token + // In that case, the exception of callback reactions will be automatically + // reported in CallSetup. + nsIGlobalObject* global = GetEntryGlobal(); + InvokeReactions(elementQueue, global); + } + + // InvokeReactions() might create other custom element reactions, but those + // new reactions should be already consumed and removed at this point. + MOZ_ASSERT(lastIndex == mReactionsStack.Length() - 1, + "reactions created by InvokeReactions() should be consumed and removed"); + + mReactionsStack.RemoveElementAt(lastIndex); + mIsElementQueuePushedForCurrentRecursionDepth = false; +} + +void +CustomElementReactionsStack::EnqueueUpgradeReaction(Element* aElement, + CustomElementDefinition* aDefinition) +{ + Enqueue(aElement, new CustomElementUpgradeReaction(aDefinition)); +} + +void +CustomElementReactionsStack::EnqueueCallbackReaction(Element* aElement, + UniquePtr<CustomElementCallback> aCustomElementCallback) +{ + Enqueue(aElement, new CustomElementCallbackReaction(Move(aCustomElementCallback))); +} + +void +CustomElementReactionsStack::Enqueue(Element* aElement, + CustomElementReaction* aReaction) +{ + RefPtr<CustomElementData> elementData = aElement->GetCustomElementData(); + MOZ_ASSERT(elementData, "CustomElementData should exist"); + + if (mRecursionDepth) { + // If the element queue is not created for current recursion depth, create + // and push an element queue to reactions stack first. + if (!mIsElementQueuePushedForCurrentRecursionDepth) { + CreateAndPushElementQueue(); + } + + MOZ_ASSERT(!mReactionsStack.IsEmpty()); + // Add element to the current element queue. + mReactionsStack.LastElement()->AppendElement(aElement); + elementData->mReactionQueue.AppendElement(aReaction); + return; + } + + // If the custom element reactions stack is empty, then: + // Add element to the backup element queue. + MOZ_ASSERT(mReactionsStack.IsEmpty(), + "custom element reactions stack should be empty"); + MOZ_ASSERT(!aReaction->IsUpgradeReaction(), + "Upgrade reaction should not be scheduled to backup queue"); + mBackupQueue.AppendElement(aElement); + elementData->mReactionQueue.AppendElement(aReaction); + + if (mIsBackupQueueProcessing) { + return; + } + + CycleCollectedJSContext* context = CycleCollectedJSContext::Get(); + RefPtr<BackupQueueMicroTask> bqmt = new BackupQueueMicroTask(this); + context->DispatchMicroTaskRunnable(bqmt.forget()); +} + +void +CustomElementReactionsStack::InvokeBackupQueue() +{ + // Check backup queue size in order to reduce function call overhead. + if (!mBackupQueue.IsEmpty()) { + // Upgrade reactions won't be scheduled in backup queue and the exception of + // callback reactions will be automatically reported in CallSetup. + // If the reactions are invoked from backup queue (in microtask check point), + // we don't need to pass global object for error reporting. + InvokeReactions(&mBackupQueue, nullptr); + } + MOZ_ASSERT(mBackupQueue.IsEmpty(), + "There are still some reactions in BackupQueue not being consumed!?!"); +} + +void +CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue, + nsIGlobalObject* aGlobal) +{ + // This is used for error reporting. + Maybe<AutoEntryScript> aes; + if (aGlobal) { + aes.emplace(aGlobal, "custom elements reaction invocation"); + } + + // Note: It's possible to re-enter this method. + for (uint32_t i = 0; i < aElementQueue->Length(); ++i) { + Element* element = aElementQueue->ElementAt(i); + + // ElementQueue hold a element's strong reference, it should not be a nullptr. + MOZ_ASSERT(element); + + RefPtr<CustomElementData> elementData = element->GetCustomElementData(); + if (!elementData) { + // This happens when the document is destroyed and the element is already + // unlinked, no need to fire the callbacks in this case. + continue; + } + + auto& reactions = elementData->mReactionQueue; + for (uint32_t j = 0; j < reactions.Length(); ++j) { + // Transfer the ownership of the entry due to reentrant invocation of + // this funciton. The entry will be removed when bug 1379573 is landed. + auto reaction(Move(reactions.ElementAt(j))); + if (reaction) { + ErrorResult rv; + reaction->Invoke(element, rv); + if (aes) { + JSContext* cx = aes->cx(); + if (rv.MaybeSetPendingException(cx)) { + aes->ReportException(); + } + MOZ_ASSERT(!JS_IsExceptionPending(cx)); + } + MOZ_ASSERT(!rv.Failed()); + } + } + reactions.Clear(); + } + aElementQueue->Clear(); +} + +//----------------------------------------------------- +// CustomElementDefinition + +NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementDefinition) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementDefinition) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructor) + tmp->mPrototype = nullptr; + tmp->mCallbacks = nullptr; +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementDefinition) + mozilla::dom::LifecycleCallbacks* callbacks = tmp->mCallbacks.get(); + + if (callbacks->mAttributeChangedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mCallbacks->mAttributeChangedCallback"); + cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value()); + } + + if (callbacks->mConnectedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mConnectedCallback"); + cb.NoteXPCOMChild(callbacks->mConnectedCallback.Value()); + } + + if (callbacks->mDisconnectedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mDisconnectedCallback"); + cb.NoteXPCOMChild(callbacks->mDisconnectedCallback.Value()); + } + + if (callbacks->mAdoptedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mAdoptedCallback"); + cb.NoteXPCOMChild(callbacks->mAdoptedCallback.Value()); + } + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mConstructor"); + cb.NoteXPCOMChild(tmp->mConstructor); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementDefinition) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPrototype) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CustomElementDefinition, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CustomElementDefinition, Release) + CustomElementDefinition::CustomElementDefinition(nsIAtom* aType, nsIAtom* aLocalName, - JSObject* aConstructor, + Function* aConstructor, + nsCOMArray<nsIAtom>&& aObservedAttributes, JSObject* aPrototype, LifecycleCallbacks* aCallbacks, uint32_t aDocOrder) : mType(aType), mLocalName(aLocalName), - mConstructor(aConstructor), + mConstructor(new CustomElementConstructor(aConstructor)), + mObservedAttributes(Move(aObservedAttributes)), mPrototype(aPrototype), mCallbacks(aCallbacks), mDocOrder(aDocOrder) { } +//----------------------------------------------------- +// CustomElementUpgradeReaction + +/* virtual */ void +CustomElementUpgradeReaction::Invoke(Element* aElement, ErrorResult& aRv) +{ + CustomElementRegistry::Upgrade(aElement, mDefinition, aRv); +} + +//----------------------------------------------------- +// CustomElementCallbackReaction + +/* virtual */ void +CustomElementCallbackReaction::Invoke(Element* aElement, ErrorResult& aRv) +{ + mCustomElementCallback->Call(); +} + } // namespace dom -} // namespace mozilla
\ No newline at end of file +} // namespace mozilla diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index ff803a054..c416e5043 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -7,13 +7,16 @@ #ifndef mozilla_dom_CustomElementRegistry_h #define mozilla_dom_CustomElementRegistry_h +#include "js/GCHashTable.h" #include "js/TypeDecls.h" #include "mozilla/Attributes.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/FunctionBinding.h" +#include "mozilla/dom/WebComponentsBinding.h" #include "nsCycleCollectionParticipant.h" +#include "nsGenericHTMLElement.h" #include "nsWrapperCache.h" -#include "mozilla/dom/FunctionBinding.h" class nsDocument; @@ -22,8 +25,8 @@ namespace dom { struct CustomElementData; struct ElementDefinitionOptions; -struct LifecycleCallbacks; class CallbackFunction; +class CustomElementReaction; class Function; class Promise; @@ -32,6 +35,13 @@ struct LifecycleCallbackArgs nsString name; nsString oldValue; nsString newValue; + nsString namespaceURI; +}; + +struct LifecycleAdoptedCallbackArgs +{ + nsCOMPtr<nsIDocument> mOldDocument; + nsCOMPtr<nsIDocument> mNewDocument; }; class CustomElementCallback @@ -39,8 +49,7 @@ class CustomElementCallback public: CustomElementCallback(Element* aThisObject, nsIDocument::ElementCallbackType aCallbackType, - CallbackFunction* aCallback, - CustomElementData* aOwnerData); + CallbackFunction* aCallback); void Traverse(nsCycleCollectionTraversalCallback& aCb) const; void Call(); void SetArgs(LifecycleCallbackArgs& aArgs) @@ -50,6 +59,13 @@ public: mArgs = aArgs; } + void SetAdoptedCallbackArgs(LifecycleAdoptedCallbackArgs& aAdoptedCallbackArgs) + { + MOZ_ASSERT(mType == nsIDocument::eAdopted, + "Arguments are only used by adopted callback."); + mAdoptedCallbackArgs = aAdoptedCallbackArgs; + } + private: // The this value to use for invocation of the callback. RefPtr<Element> mThisObject; @@ -59,9 +75,19 @@ private: // Arguments to be passed to the callback, // used by the attribute changed callback. LifecycleCallbackArgs mArgs; - // CustomElementData that contains this callback in the - // callback queue. - CustomElementData* mOwnerData; + LifecycleAdoptedCallbackArgs mAdoptedCallbackArgs; +}; + +class CustomElementConstructor final : public CallbackFunction +{ +public: + explicit CustomElementConstructor(CallbackFunction* aOther) + : CallbackFunction(aOther) + { + MOZ_ASSERT(JS::IsConstructor(mCallback)); + } + + already_AddRefed<Element> Construct(const char* aExecutionReason, ErrorResult& aRv); }; // Each custom element has an associated callback queue and an element is @@ -70,63 +96,299 @@ struct CustomElementData { NS_INLINE_DECL_REFCOUNTING(CustomElementData) + // https://dom.spec.whatwg.org/#concept-element-custom-element-state + // CustomElementData is only created on the element which is a custom element + // or an upgrade candidate, so the state of an element without + // CustomElementData is "uncustomized". + enum class State { + eUndefined, + eFailed, + eCustom + }; + explicit CustomElementData(nsIAtom* aType); - // Objects in this array are transient and empty after each microtask - // checkpoint. - nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue; - // Custom element type, for <button is="x-button"> or <x-button> - // this would be x-button. - nsCOMPtr<nsIAtom> mType; - // The callback that is next to be processed upon calling RunCallbackQueue. - int32_t mCurrentCallback; - // Element is being created flag as described in the custom elements spec. - bool mElementIsBeingCreated; - // Flag to determine if the created callback has been invoked, thus it - // determines if other callbacks can be enqueued. - bool mCreatedCallbackInvoked; - // The microtask level associated with the callbacks in the callback queue, - // it is used to determine if a new queue needs to be pushed onto the - // processing stack. - int32_t mAssociatedMicroTask; - - // Empties the callback queue. - void RunCallbackQueue(); + CustomElementData(nsIAtom* aType, State aState); + + // Custom element state as described in the custom element spec. + State mState; + // custom element reaction queue as described in the custom element spec. + // There is 1 reaction in reaction queue, when 1) it becomes disconnected, + // 2) it’s adopted into a new document, 3) its attributes are changed, + // appended, removed, or replaced. + // There are 3 reactions in reaction queue when doing upgrade operation, + // e.g., create an element, insert a node. + AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue; + + void SetCustomElementDefinition(CustomElementDefinition* aDefinition); + CustomElementDefinition* GetCustomElementDefinition(); + nsIAtom* GetCustomElementType(); + + void Traverse(nsCycleCollectionTraversalCallback& aCb) const; + void Unlink(); private: virtual ~CustomElementData() {} + + // Custom element type, for <button is="x-button"> or <x-button> + // this would be x-button. + RefPtr<nsIAtom> mType; + RefPtr<CustomElementDefinition> mCustomElementDefinition; }; +#define ALEADY_CONSTRUCTED_MARKER nullptr + // The required information for a custom element as defined in: // https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition struct CustomElementDefinition { + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CustomElementDefinition) + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CustomElementDefinition) + CustomElementDefinition(nsIAtom* aType, nsIAtom* aLocalName, - JSObject* aConstructor, + Function* aConstructor, + nsCOMArray<nsIAtom>&& aObservedAttributes, JSObject* aPrototype, mozilla::dom::LifecycleCallbacks* aCallbacks, uint32_t aDocOrder); - // The type (name) for this custom element. + // The type (name) for this custom element, for <button is="x-foo"> or <x-foo> + // this would be x-foo. nsCOMPtr<nsIAtom> mType; // The localname to (e.g. <button is=type> -- this would be button). nsCOMPtr<nsIAtom> mLocalName; // The custom element constructor. - JS::Heap<JSObject *> mConstructor; + RefPtr<CustomElementConstructor> mConstructor; + + // The list of attributes that this custom element observes. + nsCOMArray<nsIAtom> mObservedAttributes; // The prototype to use for new custom elements of this type. JS::Heap<JSObject *> mPrototype; // The lifecycle callbacks to call for this custom element. - nsAutoPtr<mozilla::dom::LifecycleCallbacks> mCallbacks; + UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks; - // A construction stack. - // TODO: Bug 1287348 - Implement construction stack for upgrading an element + // A construction stack. Use nullptr to represent an "already constructed marker". + nsTArray<RefPtr<nsGenericHTMLElement>> mConstructionStack; // The document custom element order. uint32_t mDocOrder; + + bool IsCustomBuiltIn() + { + return mType != mLocalName; + } + + bool IsInObservedAttributeList(nsIAtom* aName) + { + if (mObservedAttributes.IsEmpty()) { + return false; + } + + return mObservedAttributes.Contains(aName); + } + +private: + ~CustomElementDefinition() {} +}; + +class CustomElementReaction +{ +public: + virtual ~CustomElementReaction() = default; + virtual void Invoke(Element* aElement, ErrorResult& aRv) = 0; + virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const + { + } + +#if DEBUG + bool IsUpgradeReaction() + { + return mIsUpgradeReaction; + } + +protected: + bool mIsUpgradeReaction = false; +#endif +}; + +class CustomElementUpgradeReaction final : public CustomElementReaction +{ +public: + explicit CustomElementUpgradeReaction(CustomElementDefinition* aDefinition) + : mDefinition(aDefinition) + { +#if DEBUG + mIsUpgradeReaction = true; +#endif + } + +private: + virtual void Invoke(Element* aElement, ErrorResult& aRv) override; + + CustomElementDefinition* mDefinition; +}; + +class CustomElementCallbackReaction final : public CustomElementReaction +{ + public: + explicit CustomElementCallbackReaction(UniquePtr<CustomElementCallback> aCustomElementCallback) + : mCustomElementCallback(Move(aCustomElementCallback)) + { + } + + virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override + { + mCustomElementCallback->Traverse(aCb); + } + + private: + virtual void Invoke(Element* aElement, ErrorResult& aRv) override; + UniquePtr<CustomElementCallback> mCustomElementCallback; +}; + +// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions-stack +class CustomElementReactionsStack +{ +public: + NS_INLINE_DECL_REFCOUNTING(CustomElementReactionsStack) + + CustomElementReactionsStack() + : mIsBackupQueueProcessing(false) + , mRecursionDepth(0) + , mIsElementQueuePushedForCurrentRecursionDepth(false) + { + } + + // Hold a strong reference of Element so that it does not get cycle collected + // before the reactions in its reaction queue are invoked. + // The element reaction queues are stored in CustomElementData. + // We need to lookup ElementReactionQueueMap again to get relevant reaction queue. + // The choice of 1 for the auto size here is based on gut feeling. + typedef AutoTArray<RefPtr<Element>, 1> ElementQueue; + + /** + * Enqueue a custom element upgrade reaction + * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction + */ + void EnqueueUpgradeReaction(Element* aElement, + CustomElementDefinition* aDefinition); + + /** + * Enqueue a custom element callback reaction + * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-callback-reaction + */ + void EnqueueCallbackReaction(Element* aElement, + UniquePtr<CustomElementCallback> aCustomElementCallback); + + /** + * [CEReactions] Before executing the algorithm's steps. + * Increase the current recursion depth, and the element queue is pushed + * lazily when we really enqueue reactions. + * + * @return true if the element queue is pushed for "previous" recursion depth. + */ + bool EnterCEReactions() + { + bool temp = mIsElementQueuePushedForCurrentRecursionDepth; + mRecursionDepth++; + // The is-element-queue-pushed flag is initially false when entering a new + // recursion level. The original value will be cached in AutoCEReaction + // and restored after leaving this recursion level. + mIsElementQueuePushedForCurrentRecursionDepth = false; + return temp; + } + + /** + * [CEReactions] After executing the algorithm's steps. + * Pop and invoke the element queue if it is created and pushed for current + * recursion depth, then decrease the current recursion depth. + * + * @param aCx JSContext used for handling exception thrown by algorithm's + * steps, this could be a nullptr. + * aWasElementQueuePushed used for restoring status after leaving + * current recursion. + */ + void LeaveCEReactions(JSContext* aCx, bool aWasElementQueuePushed) + { + MOZ_ASSERT(mRecursionDepth); + + if (mIsElementQueuePushedForCurrentRecursionDepth) { + Maybe<JS::AutoSaveExceptionState> ases; + if (aCx) { + ases.emplace(aCx); + } + PopAndInvokeElementQueue(); + } + mRecursionDepth--; + // Restore the is-element-queue-pushed flag cached in AutoCEReaction when + // leaving the recursion level. + mIsElementQueuePushedForCurrentRecursionDepth = aWasElementQueuePushed; + + MOZ_ASSERT_IF(!mRecursionDepth, mReactionsStack.IsEmpty()); + } + +private: + ~CustomElementReactionsStack() {}; + + /** + * Push a new element queue onto the custom element reactions stack. + */ + void CreateAndPushElementQueue(); + + /** + * Pop the element queue from the custom element reactions stack, and invoke + * custom element reactions in that queue. + */ + void PopAndInvokeElementQueue(); + + // The choice of 8 for the auto size here is based on gut feeling. + AutoTArray<UniquePtr<ElementQueue>, 8> mReactionsStack; + ElementQueue mBackupQueue; + // https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue + bool mIsBackupQueueProcessing; + + void InvokeBackupQueue(); + + /** + * Invoke custom element reactions + * https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions + */ + void InvokeReactions(ElementQueue* aElementQueue, nsIGlobalObject* aGlobal); + + void Enqueue(Element* aElement, CustomElementReaction* aReaction); + + // Current [CEReactions] recursion depth. + uint32_t mRecursionDepth; + // True if the element queue is pushed into reaction stack for current + // recursion depth. This will be cached in AutoCEReaction when entering a new + // CEReaction recursion and restored after leaving the recursion. + bool mIsElementQueuePushedForCurrentRecursionDepth; + +private: + class BackupQueueMicroTask final : public mozilla::MicroTaskRunnable { + public: + explicit BackupQueueMicroTask(CustomElementReactionsStack* aReactionStack) + : MicroTaskRunnable() + , mReactionStack(aReactionStack) + { + MOZ_ASSERT(!mReactionStack->mIsBackupQueueProcessing, + "mIsBackupQueueProcessing should be initially false"); + mReactionStack->mIsBackupQueueProcessing = true; + } + + virtual void Run(AutoSlowOperation& aAso) override + { + mReactionStack->InvokeBackupQueue(); + mReactionStack->mIsBackupQueueProcessing = false; + } + + private: + RefPtr<CustomElementReactionsStack> mReactionStack; + }; }; class CustomElementRegistry final : public nsISupports, @@ -142,36 +404,33 @@ public: public: static bool IsCustomElementEnabled(JSContext* aCx = nullptr, JSObject* aObject = nullptr); - static already_AddRefed<CustomElementRegistry> Create(nsPIDOMWindowInner* aWindow); - static void ProcessTopElementQueue(); - static void XPCOMShutdown(); + explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow); /** * Looking up a custom element definition. * https://html.spec.whatwg.org/#look-up-a-custom-element-definition */ CustomElementDefinition* LookupCustomElementDefinition( - const nsAString& aLocalName, const nsAString* aIs = nullptr) const; + nsIAtom* aNameAtom, nsIAtom* aTypeAtom) const; - /** - * Enqueue created callback or register upgrade candidate for - * newly created custom elements, possibly extending an existing type. - * ex. <x-button>, <button is="x-button> (type extension) - */ - void SetupCustomElement(Element* aElement, const nsAString* aTypeExtension); + CustomElementDefinition* LookupCustomElementDefinition( + JSContext* aCx, JSObject *aConstructor) const; - void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, - Element* aCustomElement, - LifecycleCallbackArgs* aArgs, - CustomElementDefinition* aDefinition); + static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, + Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, + CustomElementDefinition* aDefinition); void GetCustomPrototype(nsIAtom* aAtom, JS::MutableHandle<JSObject*> aPrototype); -private: - explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow); - ~CustomElementRegistry(); + /** + * Upgrade an element. + * https://html.spec.whatwg.org/multipage/scripting.html#upgrades + */ + static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv); /** * Registers an unresolved custom element that is a candidate for @@ -184,23 +443,48 @@ private: void RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName = nullptr); - void UpgradeCandidates(JSContext* aCx, - nsIAtom* aKey, - CustomElementDefinition* aDefinition); + /** + * Unregister an unresolved custom element that is a candidate for + * upgrade when a custom element is removed from tree. + */ + void UnregisterUnresolvedElement(Element* aElement, + nsIAtom* aTypeName = nullptr); +private: + ~CustomElementRegistry(); + + static UniquePtr<CustomElementCallback> CreateCustomElementCallback( + nsIDocument::ElementCallbackType aType, Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, + CustomElementDefinition* aDefinition); - typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition> + void UpgradeCandidates(nsIAtom* aKey, + CustomElementDefinition* aDefinition, + ErrorResult& aRv); + + typedef nsRefPtrHashtable<nsISupportsHashKey, CustomElementDefinition> DefinitionMap; typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>> CandidateMap; + typedef JS::GCHashMap<JS::Heap<JSObject*>, + nsCOMPtr<nsIAtom>, + js::MovableCellHasher<JS::Heap<JSObject*>>, + js::SystemAllocPolicy> ConstructorMap; // Hashtable for custom element definitions in web components. // Custom prototypes are stored in the compartment where // registerElement was called. DefinitionMap mCustomDefinitions; + // Hashtable for looking up definitions by using constructor as key. + // Custom elements' name are stored here and we need to lookup + // mCustomDefinitions again to get definitions. + ConstructorMap mConstructors; + typedef nsRefPtrHashtable<nsISupportsHashKey, Promise> WhenDefinedPromiseMap; WhenDefinedPromiseMap mWhenDefinedPromiseMap; + // The "upgrade candidates map" from the web components spec. Maps from a // namespace id and local name to a list of elements to upgrade if that // element is registered as a custom element. @@ -208,14 +492,6 @@ private: nsCOMPtr<nsPIDOMWindowInner> mWindow; - // Array representing the processing stack in the custom elements - // specification. The processing stack is conceptually a stack of - // element queues. Each queue is represented by a sequence of - // CustomElementData in this array, separated by nullptr that - // represent the boundaries of the items in the stack. The first - // queue in the stack is the base element queue. - static mozilla::Maybe<nsTArray<RefPtr<CustomElementData>>> sProcessingStack; - // It is used to prevent reentrant invocations of element definition. bool mIsCustomDefinitionRunning; @@ -252,6 +528,31 @@ public: already_AddRefed<Promise> WhenDefined(const nsAString& aName, ErrorResult& aRv); }; +class MOZ_RAII AutoCEReaction final { + public: + // JSContext is allowed to be a nullptr if we are guaranteeing that we're + // not doing something that might throw but not finish reporting a JS + // exception during the lifetime of the AutoCEReaction. + AutoCEReaction(CustomElementReactionsStack* aReactionsStack, JSContext* aCx) + : mReactionsStack(aReactionsStack) + , mCx(aCx) + { + mIsElementQueuePushedForPreviousRecursionDepth = + mReactionsStack->EnterCEReactions(); + } + + ~AutoCEReaction() + { + mReactionsStack->LeaveCEReactions( + mCx, mIsElementQueuePushedForPreviousRecursionDepth); + } + + private: + RefPtr<CustomElementReactionsStack> mReactionsStack; + JSContext* mCx; + bool mIsElementQueuePushedForPreviousRecursionDepth; +}; + } // namespace dom } // namespace mozilla diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp index 226879985..30c058f0c 100644 --- a/dom/base/DocGroup.cpp +++ b/dom/base/DocGroup.cpp @@ -46,6 +46,9 @@ DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey) DocGroup::~DocGroup() { MOZ_ASSERT(mDocuments.IsEmpty()); + if (!NS_IsMainThread()) { + NS_ReleaseOnMainThread(mReactionsStack.forget()); + } mTabGroup->mDocGroups.RemoveEntry(mKey); } diff --git a/dom/base/DocGroup.h b/dom/base/DocGroup.h index f4f7ac8ad..5b8f627cc 100644 --- a/dom/base/DocGroup.h +++ b/dom/base/DocGroup.h @@ -14,6 +14,7 @@ #include "nsString.h" #include "mozilla/RefPtr.h" +#include "mozilla/dom/CustomElementRegistry.h" namespace mozilla { namespace dom { @@ -52,6 +53,14 @@ public: { return mTabGroup; } + mozilla::dom::CustomElementReactionsStack* CustomElementReactionsStack() + { + if (!mReactionsStack) { + mReactionsStack = new mozilla::dom::CustomElementReactionsStack(); + } + + return mReactionsStack; + } void RemoveDocument(nsIDocument* aWindow); // Iterators for iterating over every document within the DocGroup @@ -71,6 +80,7 @@ private: nsCString mKey; RefPtr<TabGroup> mTabGroup; nsTArray<nsIDocument*> mDocuments; + RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack; }; } // namespace dom diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 0054f4800..c8467e036 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -479,9 +479,13 @@ Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) if (data) { // If this is a registered custom element then fix the prototype. nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(), - data->mType, &customProto); + data->GetCustomElementType(), &customProto); if (customProto && NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) { + // The custom element prototype could be in different compartment. + if (!JS_WrapObject(aCx, &customProto)) { + return nullptr; + } // Just go ahead and create with the right proto up front. Set // customProto to null to flag that we don't need to do any post-facto // proto fixups here. @@ -1595,7 +1599,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent, #endif { if (aBindingParent) { - nsDOMSlots *slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); slots->mBindingParent = aBindingParent; // Weak, so no addref happens. } @@ -1618,7 +1622,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent, } ShadowRoot* parentContainingShadow = aParent->GetContainingShadow(); if (parentContainingShadow) { - DOMSlots()->mContainingShadow = parentContainingShadow; + ExtendedDOMSlots()->mContainingShadow = parentContainingShadow; } } @@ -1684,14 +1688,17 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent, SetSubtreeRootPointer(aParent->SubtreeRoot()); } - nsIDocument* composedDoc = GetComposedDoc(); - if (composedDoc) { - // Attached callback must be enqueued whenever custom element is inserted into a - // document and this document has a browsing context. - if (GetCustomElementData() && composedDoc->GetDocShell()) { - // Enqueue an attached callback for the custom element. - nsContentUtils::EnqueueLifecycleCallback( - composedDoc, nsIDocument::eAttached, this); + if (CustomElementRegistry::IsCustomElementEnabled() && IsInComposedDoc()) { + // Connected callback must be enqueued whenever a custom element becomes + // connected. + CustomElementData* data = GetCustomElementData(); + if (data) { + if (data->mState == CustomElementData::State::eCustom) { + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this); + } else { + // Step 7.7.2.2 https://dom.spec.whatwg.org/#concept-node-insert + nsContentUtils::TryToUpgradeElement(this); + } } } @@ -1986,12 +1993,21 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) document->ClearBoxObjectFor(this); - // Detached must be enqueued whenever custom element is removed from - // the document and this document has a browsing context. - if (GetCustomElementData() && document->GetDocShell()) { - // Enqueue a detached callback for the custom element. - nsContentUtils::EnqueueLifecycleCallback( - document, nsIDocument::eDetached, this); + // Disconnected must be enqueued whenever a connected custom element becomes + // disconnected. + if (CustomElementRegistry::IsCustomElementEnabled()) { + CustomElementData* data = GetCustomElementData(); + if (data) { + if (data->mState == CustomElementData::State::eCustom) { + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eDisconnected, + this); + } else { + // Remove an unresolved custom element that is a candidate for + // upgrade when a custom element is disconnected. + // We will make sure it's shadow-including tree order in bug 1326028. + nsContentUtils::UnregisterUnresolvedElement(this); + } + } } } @@ -2007,7 +2023,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) } #endif - nsDOMSlots* slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { if (clearBindingParent) { slots->mBindingParent = nullptr; @@ -2055,7 +2071,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) nsICSSDeclaration* Element::GetSMILOverrideStyle() { - Element::nsDOMSlots *slots = DOMSlots(); + Element::nsExtendedDOMSlots* slots = ExtendedDOMSlots(); if (!slots->mSMILOverrideStyle) { slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true); @@ -2067,7 +2083,7 @@ Element::GetSMILOverrideStyle() DeclarationBlock* Element::GetSMILOverrideStyleDeclaration() { - Element::nsDOMSlots *slots = GetExistingDOMSlots(); + Element::nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); return slots ? slots->mSMILOverrideStyleDeclaration.get() : nullptr; } @@ -2075,7 +2091,7 @@ nsresult Element::SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration, bool aNotify) { - Element::nsDOMSlots *slots = DOMSlots(); + Element::nsExtendedDOMSlots* slots = ExtendedDOMSlots(); slots->mSMILOverrideStyleDeclaration = aDeclaration; @@ -2586,19 +2602,32 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, UpdateState(aNotify); - nsIDocument* ownerDoc = OwnerDoc(); - if (ownerDoc && GetCustomElementData()) { - nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom(); - nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom(); - LifecycleCallbackArgs args = { - nsDependentAtomString(aName), - aModType == nsIDOMMutationEvent::ADDITION ? - NullString() : nsDependentAtomString(oldValueAtom), - nsDependentAtomString(newValueAtom) - }; - - nsContentUtils::EnqueueLifecycleCallback( - ownerDoc, nsIDocument::eAttributeChanged, this, &args); + if (CustomElementRegistry::IsCustomElementEnabled()) { + if (CustomElementData* data = GetCustomElementData()) { + if (CustomElementDefinition* definition = + nsContentUtils::GetElementDefinitionIfObservingAttr(this, + data->GetCustomElementType(), + aName)) { + MOZ_ASSERT(data->mState == CustomElementData::State::eCustom, + "AttributeChanged callback should fire only if " + "custom element state is custom"); + nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom(); + nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom(); + nsAutoString ns; + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns); + + LifecycleCallbackArgs args = { + nsDependentAtomString(aName), + aModType == nsIDOMMutationEvent::ADDITION ? + NullString() : nsDependentAtomString(oldValueAtom), + nsDependentAtomString(newValueAtom), + (ns.IsEmpty() ? NullString() : ns) + }; + + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, + this, &args, nullptr, definition); + } + } } if (aCallAfterSetAttr) { @@ -2843,17 +2872,30 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName, UpdateState(aNotify); - nsIDocument* ownerDoc = OwnerDoc(); - if (ownerDoc && GetCustomElementData()) { - nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom(); - LifecycleCallbackArgs args = { - nsDependentAtomString(aName), - nsDependentAtomString(oldValueAtom), - NullString() - }; - - nsContentUtils::EnqueueLifecycleCallback( - ownerDoc, nsIDocument::eAttributeChanged, this, &args); + if (CustomElementRegistry::IsCustomElementEnabled()) { + if (CustomElementData* data = GetCustomElementData()) { + if (CustomElementDefinition* definition = + nsContentUtils::GetElementDefinitionIfObservingAttr(this, + data->GetCustomElementType(), + aName)) { + MOZ_ASSERT(data->mState == CustomElementData::State::eCustom, + "AttributeChanged callback should fire only if " + "custom element state is custom"); + nsAutoString ns; + nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns); + + nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom(); + LifecycleCallbackArgs args = { + nsDependentAtomString(aName), + nsDependentAtomString(oldValueAtom), + NullString(), + (ns.IsEmpty() ? NullString() : ns) + }; + + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, + this, &args, nullptr, definition); + } + } } if (aNotify) { @@ -3988,7 +4030,7 @@ Element::ClearDataset() nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* Element::RegisteredIntersectionObservers() { - nsDOMSlots* slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); return &slots->mRegisteredIntersectionObservers; } @@ -4037,3 +4079,31 @@ Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32 } return false; } + +void +Element::SetCustomElementData(CustomElementData* aData) +{ + nsExtendedDOMSlots *slots = ExtendedDOMSlots(); + MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set."); + slots->mCustomElementData = aData; +} + +CustomElementDefinition* +Element::GetCustomElementDefinition() const +{ + CustomElementData* data = GetCustomElementData(); + if (!data) { + return nullptr; + } + + return data->GetCustomElementDefinition(); +} + +void +Element::SetCustomElementDefinition(CustomElementDefinition* aDefinition) +{ + CustomElementData* data = GetCustomElementData(); + MOZ_ASSERT(data); + + data->SetCustomElementDefinition(aDefinition); +} diff --git a/dom/base/Element.h b/dom/base/Element.h index ce84b74fb..782004703 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -390,6 +390,45 @@ public: Directionality GetComputedDirectionality() const; + /** + * Gets the custom element data used by web components custom element. + * Custom element data is created at the first attempt to enqueue a callback. + * + * @return The custom element data or null if none. + */ + inline CustomElementData* GetCustomElementData() const + { + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); + if (slots) { + return slots->mCustomElementData; + } + return nullptr; + } + + /** + * Sets the custom element data, ownership of the + * callback data is taken by this element. + * + * @param aData The custom element data. + */ + void SetCustomElementData(CustomElementData* aData); + + /** + * Gets the custom element definition used by web components custom element. + * + * @return The custom element definition or null if element is not a custom + * element or custom element is not defined yet. + */ + CustomElementDefinition* GetCustomElementDefinition() const; + + /** + * Sets the custom element definition, called when custom element is created + * or upgraded. + * + * @param aDefinition The custom element definition. + */ + void SetCustomElementDefinition(CustomElementDefinition* aDefinition); + protected: /** * Method to get the _intrinsic_ content state of this element. This is the @@ -814,7 +853,7 @@ public: ShadowRoot *FastGetShadowRoot() const { - nsDOMSlots* slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); return slots ? slots->mShadowRoot.get() : nullptr; } diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 9106778df..526c3c9d4 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -530,8 +530,7 @@ nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr) //---------------------------------------------------------------------- FragmentOrElement::nsDOMSlots::nsDOMSlots() : nsINode::nsSlots(), - mDataset(nullptr), - mBindingParent(nullptr) + mDataset(nullptr) { } @@ -543,84 +542,104 @@ FragmentOrElement::nsDOMSlots::~nsDOMSlots() } void -FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL) +FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle"); cb.NoteXPCOMChild(mStyle.get()); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle"); - cb.NoteXPCOMChild(mSMILOverrideStyle.get()); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap"); cb.NoteXPCOMChild(mAttributeMap.get()); - if (aIsXUL) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers"); - cb.NoteXPCOMChild(mControllers); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList)); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList"); + cb.NoteXPCOMChild(mClassList.get()); + + if (!mExtendedSlots) { + return; } - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLBinding"); - cb.NoteNativeChild(mXBLBinding, NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mSMILOverrideStyle"); + cb.NoteXPCOMChild(mExtendedSlots->mSMILOverrideStyle.get()); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent"); - cb.NoteXPCOMChild(mXBLInsertionParent.get()); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mControllers"); + cb.NoteXPCOMChild(mExtendedSlots->mControllers); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mShadowRoot"); - cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mShadowRoot)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mLabelsList"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*,mExtendedSlots-> mLabelsList)); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow"); - cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mShadowRoot"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mShadowRoot)); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList"); - cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow)); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList"); - cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding"); + cb.NoteNativeChild(mExtendedSlots->mXBLBinding, + NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding)); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList"); - cb.NoteXPCOMChild(mClassList.get()); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLInsertionParent"); + cb.NoteXPCOMChild(mExtendedSlots->mXBLInsertionParent.get()); - if (mCustomElementData) { - for (uint32_t i = 0; i < mCustomElementData->mCallbackQueue.Length(); i++) { - mCustomElementData->mCallbackQueue[i]->Traverse(cb); - } + if (mExtendedSlots->mCustomElementData) { + mExtendedSlots->mCustomElementData->Traverse(cb); } - for (auto iter = mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + for (auto iter = mExtendedSlots->mRegisteredIntersectionObservers.Iter(); + !iter.Done(); iter.Next()) { DOMIntersectionObserver* observer = iter.Key(); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mRegisteredIntersectionObservers[i]"); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mExtendedSlots->mRegisteredIntersectionObservers[i]"); cb.NoteXPCOMChild(observer); } + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mFrameLoaderOrOpener"); + cb.NoteXPCOMChild(mExtendedSlots->mFrameLoaderOrOpener); } void -FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL) +FragmentOrElement::nsDOMSlots::Unlink() { mStyle = nullptr; - mSMILOverrideStyle = nullptr; if (mAttributeMap) { mAttributeMap->DropReference(); mAttributeMap = nullptr; } - if (aIsXUL) - NS_IF_RELEASE(mControllers); - - MOZ_ASSERT(!mXBLBinding); - - mXBLInsertionParent = nullptr; - mShadowRoot = nullptr; - mContainingShadow = nullptr; mChildrenList = nullptr; - mLabelsList = nullptr; - mCustomElementData = nullptr; mClassList = nullptr; - mRegisteredIntersectionObservers.Clear(); + + if (!mExtendedSlots) { + return; + } + + mExtendedSlots->mSMILOverrideStyle = nullptr; + mExtendedSlots->mControllers = nullptr; + mExtendedSlots->mLabelsList = nullptr; + mExtendedSlots->mShadowRoot = nullptr; + mExtendedSlots->mContainingShadow = nullptr; + MOZ_ASSERT(!(mExtendedSlots->mXBLBinding)); + mExtendedSlots->mXBLInsertionParent = nullptr; + if (mExtendedSlots->mCustomElementData) { + mExtendedSlots->mCustomElementData->Unlink(); + mExtendedSlots->mCustomElementData = nullptr; + } + mExtendedSlots->mRegisteredIntersectionObservers.Clear(); + nsCOMPtr<nsIFrameLoader> frameLoader = + do_QueryInterface(mExtendedSlots->mFrameLoaderOrOpener); + if (frameLoader) { + static_cast<nsFrameLoader*>(frameLoader.get())->Destroy(); + } + mExtendedSlots->mFrameLoaderOrOpener = nullptr; } size_t FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = aMallocSizeOf(this); + if (mExtendedSlots) { + n += aMallocSizeOf(mExtendedSlots.get()); + } if (mAttributeMap) { n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf); @@ -641,6 +660,19 @@ FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) c return n; } +FragmentOrElement::nsExtendedDOMSlots::nsExtendedDOMSlots() + : mBindingParent(nullptr) +{ +} + +FragmentOrElement::nsExtendedDOMSlots::~nsExtendedDOMSlots() +{ + nsCOMPtr<nsIFrameLoader> frameLoader = do_QueryInterface(mFrameLoaderOrOpener); + if (frameLoader) { + static_cast<nsFrameLoader*>(frameLoader.get())->Destroy(); + } +} + FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) : nsIContent(aNodeInfo) { @@ -962,7 +994,7 @@ FragmentOrElement::IsLink(nsIURI** aURI) const nsIContent* FragmentOrElement::GetBindingParent() const { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { return slots->mBindingParent; @@ -974,7 +1006,7 @@ nsXBLBinding* FragmentOrElement::GetXBLBinding() const { if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { return slots->mXBLBinding; } @@ -1009,11 +1041,11 @@ FragmentOrElement::SetXBLBinding(nsXBLBinding* aBinding, if (aBinding) { SetFlags(NODE_MAY_BE_IN_BINDING_MNGR); - nsDOMSlots *slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); slots->mXBLBinding = aBinding; bindingManager->AddBoundContent(this); } else { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { slots->mXBLBinding = nullptr; } @@ -1028,7 +1060,7 @@ nsIContent* FragmentOrElement::GetXBLInsertionParent() const { if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { return slots->mXBLInsertionParent; } @@ -1040,7 +1072,7 @@ FragmentOrElement::GetXBLInsertionParent() const ShadowRoot* FragmentOrElement::GetContainingShadow() const { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { return slots->mContainingShadow; } @@ -1050,21 +1082,21 @@ FragmentOrElement::GetContainingShadow() const void FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot) { - nsDOMSlots *slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); slots->mShadowRoot = aShadowRoot; } nsTArray<nsIContent*>& FragmentOrElement::DestInsertionPoints() { - nsDOMSlots *slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); return slots->mDestInsertionPoints; } nsTArray<nsIContent*>* FragmentOrElement::GetExistingDestInsertionPoints() const { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { return &slots->mDestInsertionPoints; } @@ -1075,35 +1107,17 @@ void FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent) { if (aContent) { - nsDOMSlots *slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); SetFlags(NODE_MAY_BE_IN_BINDING_MNGR); slots->mXBLInsertionParent = aContent; } else { - nsDOMSlots *slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { slots->mXBLInsertionParent = nullptr; } } } -CustomElementData* -FragmentOrElement::GetCustomElementData() const -{ - nsDOMSlots *slots = GetExistingDOMSlots(); - if (slots) { - return slots->mCustomElementData; - } - return nullptr; -} - -void -FragmentOrElement::SetCustomElementData(CustomElementData* aData) -{ - nsDOMSlots *slots = DOMSlots(); - MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set."); - slots->mCustomElementData = aData; -} - nsresult FragmentOrElement::InsertChildAt(nsIContent* aKid, uint32_t aIndex, @@ -1366,14 +1380,15 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement) { nsDOMSlots *slots = tmp->GetExistingDOMSlots(); if (slots) { - if (tmp->IsElement()) { + if (slots->mExtendedSlots && tmp->IsElement()) { Element* elem = tmp->AsElement(); - for (auto iter = slots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + for (auto iter = slots->mExtendedSlots->mRegisteredIntersectionObservers.Iter(); + !iter.Done(); iter.Next()) { DOMIntersectionObserver* observer = iter.Key(); observer->UnlinkTarget(*elem); } } - slots->Unlink(tmp->IsXULElement()); + slots->Unlink(); } } @@ -1938,7 +1953,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement) { nsDOMSlots *slots = tmp->GetExistingDOMSlots(); if (slots) { - slots->Traverse(cb, tmp->IsXULElement()); + slots->Traverse(cb); } } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h index f0cc29f22..4edd88908 100644 --- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -15,6 +15,7 @@ #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/UniquePtr.h" #include "nsAttrAndChildArray.h" // member #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_* #include "nsIContent.h" // base class @@ -37,6 +38,7 @@ class nsIURI; namespace mozilla { class DeclarationBlock; namespace dom { +struct CustomElementData; class DOMIntersectionObserver; class Element; } // namespace dom @@ -159,9 +161,6 @@ public: virtual void SetXBLInsertionParent(nsIContent* aContent) override; virtual bool IsLink(nsIURI** aURI) const override; - virtual CustomElementData *GetCustomElementData() const override; - virtual void SetCustomElementData(CustomElementData* aData) override; - virtual void DestroyContent() override; virtual void SaveSubtreeState() override; @@ -241,8 +240,6 @@ protected: nsresult CopyInnerTo(FragmentOrElement* aDest); public: - // Because of a bug in MS C++ compiler nsDOMSlots must be declared public, - // otherwise nsXULElement::nsXULSlots doesn't compile. /** * There are a set of DOM- and scripting-specific instance variables * that may only be instantiated when a content object is accessed @@ -251,29 +248,13 @@ public: * in a side structure that's only allocated when the content is * accessed through the DOM. */ - class nsDOMSlots : public nsINode::nsSlots + + class nsExtendedDOMSlots { public: - nsDOMSlots(); - virtual ~nsDOMSlots(); - - void Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL); - void Unlink(bool aIsXUL); - - size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; - - /** - * The .style attribute (an interface that forwards to the actual - * style rules) - * @see nsGenericHTMLElement::GetStyle - */ - nsCOMPtr<nsICSSDeclaration> mStyle; + nsExtendedDOMSlots(); - /** - * The .dataset attribute. - * @see nsGenericHTMLElement::GetDataset - */ - nsDOMStringMap* mDataset; // [Weak] + ~nsExtendedDOMSlots(); /** * SMIL Overridde style rules (for SMIL animation of CSS properties) @@ -287,35 +268,17 @@ public: RefPtr<mozilla::DeclarationBlock> mSMILOverrideStyleDeclaration; /** - * An object implementing nsIDOMMozNamedAttrMap for this content (attributes) - * @see FragmentOrElement::GetAttributes - */ - RefPtr<nsDOMAttributeMap> mAttributeMap; - - union { - /** - * The nearest enclosing content node with a binding that created us. - * @see FragmentOrElement::GetBindingParent - */ - nsIContent* mBindingParent; // [Weak] - - /** - * The controllers of the XUL Element. - */ - nsIControllers* mControllers; // [OWNER] - }; + * The nearest enclosing content node with a binding that created us. + * @see FragmentOrElement::GetBindingParent + */ + nsIContent* mBindingParent; // [Weak] /** - * An object implementing the .children property for this element. - */ - RefPtr<nsContentList> mChildrenList; + * The controllers of the XUL Element. + */ + nsCOMPtr<nsIControllers> mControllers; /** - * An object implementing the .classList property for this element. - */ - RefPtr<nsDOMTokenList> mClassList; - - /* * An object implementing the .labels property for this element. */ RefPtr<nsLabelsNodeList> mLabelsList; @@ -356,6 +319,55 @@ public: */ nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t> mRegisteredIntersectionObservers; + + /** + * For XUL to hold either frameloader or opener. + */ + nsCOMPtr<nsISupports> mFrameLoaderOrOpener; + + }; + + class nsDOMSlots : public nsINode::nsSlots + { + public: + nsDOMSlots(); + virtual ~nsDOMSlots(); + + void Traverse(nsCycleCollectionTraversalCallback &cb); + void Unlink(); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + /** + * The .style attribute (an interface that forwards to the actual + * style rules) + * @see nsGenericHTMLElement::GetStyle + */ + nsCOMPtr<nsICSSDeclaration> mStyle; + + /** + * The .dataset attribute. + * @see nsGenericHTMLElement::GetDataset + */ + nsDOMStringMap* mDataset; // [Weak] + + /** + * An object implementing nsIDOMMozNamedAttrMap for this content (attributes) + * @see FragmentOrElement::GetAttributes + */ + RefPtr<nsDOMAttributeMap> mAttributeMap; + + /** + * An object implementing the .children property for this element. + */ + RefPtr<nsContentList> mChildrenList; + + /** + * An object implementing the .classList property for this element. + */ + RefPtr<nsDOMTokenList> mClassList; + + mozilla::UniquePtr<nsExtendedDOMSlots> mExtendedSlots; }; protected: @@ -375,6 +387,26 @@ protected: return static_cast<nsDOMSlots*>(GetExistingSlots()); } + nsExtendedDOMSlots* ExtendedDOMSlots() + { + nsDOMSlots* slots = DOMSlots(); + if (!slots->mExtendedSlots) { + slots->mExtendedSlots = MakeUnique<nsExtendedDOMSlots>(); + } + + return slots->mExtendedSlots.get(); + } + + nsExtendedDOMSlots* GetExistingExtendedDOMSlots() const + { + nsDOMSlots* slots = GetExistingDOMSlots(); + if (slots) { + return slots->mExtendedSlots.get(); + } + + return nullptr; + } + /** * Calls SetIsElementInStyleScopeFlagOnSubtree for each shadow tree attached * to this node, which is assumed to be an Element. diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp index 9540754f7..831987a96 100644 --- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -75,8 +75,8 @@ ShadowRoot::ShadowRoot(nsIContent* aContent, SetFlags(NODE_IS_IN_SHADOW_TREE); - DOMSlots()->mBindingParent = aContent; - DOMSlots()->mContainingShadow = this; + ExtendedDOMSlots()->mBindingParent = aContent; + ExtendedDOMSlots()->mContainingShadow = this; // Add the ShadowRoot as a mutation observer on the host to watch // for mutations because the insertion points in this ShadowRoot diff --git a/dom/base/crashtests/1341693.html b/dom/base/crashtests/1341693.html new file mode 100644 index 000000000..677305ba5 --- /dev/null +++ b/dom/base/crashtests/1341693.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<body> +<script> + var o1 = document.documentElement; + var o2 = document.createElement("frame"); + document.documentElement.appendChild(o2); + var o3 = o2.contentWindow; + o1.parentNode.removeChild(o1); + o3.customElements; +</script> +</body> +</html> diff --git a/dom/base/crashtests/crashtests.list b/dom/base/crashtests/crashtests.list index a0739f074..0fb597b30 100644 --- a/dom/base/crashtests/crashtests.list +++ b/dom/base/crashtests/crashtests.list @@ -209,3 +209,4 @@ load 1230422.html load 1251361.html load 1304437.html pref(clipboard.autocopy,true) load 1385272-1.html +pref(dom.webcomponents.customelements.enabled,true) load 1341693.html diff --git a/dom/base/nsContentCreatorFunctions.h b/dom/base/nsContentCreatorFunctions.h index 9576d9ba8..a5c210500 100644 --- a/dom/base/nsContentCreatorFunctions.h +++ b/dom/base/nsContentCreatorFunctions.h @@ -24,6 +24,7 @@ namespace mozilla { namespace dom { class Element; class NodeInfo; +struct CustomElementDefinition; } // namespace dom } // namespace mozilla @@ -41,7 +42,8 @@ nsresult NS_NewHTMLElement(mozilla::dom::Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, mozilla::dom::FromParser aFromParser, - const nsAString* aIs = nullptr); + const nsAString* aIs = nullptr, + mozilla::dom::CustomElementDefinition* aDefinition = nullptr); // First argument should be nsHTMLTag, but that adds dependency to parser // for a bunch of files. diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 800f40fa1..b6cbbbace 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -227,6 +227,7 @@ extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware, const char** colon); class imgLoader; +class nsIAtom; using namespace mozilla::dom; using namespace mozilla::ipc; @@ -258,7 +259,6 @@ nsIWordBreaker *nsContentUtils::sWordBreaker; nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr; uint32_t nsContentUtils::sScriptBlockerCount = 0; uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; -uint32_t nsContentUtils::sMicroTaskLevel = 0; AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr; uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; @@ -284,6 +284,8 @@ bool nsContentUtils::sIsResourceTimingEnabled = false; bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false; bool nsContentUtils::sIsUserTimingLoggingEnabled = false; bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false; +bool nsContentUtils::sIsWebComponentsEnabled = false; +bool nsContentUtils::sIsCustomElementsEnabled = false; bool nsContentUtils::sEncodeDecodeURLHash = false; bool nsContentUtils::sGettersDecodeURLHash = false; bool nsContentUtils::sPrivacyResistFingerprinting = false; @@ -584,6 +586,12 @@ nsContentUtils::Init() Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled, "dom.forms.autocomplete.experimental", false); + Preferences::AddBoolVarCache(&sIsWebComponentsEnabled, + "dom.webcomponents.enabled", false); + + Preferences::AddBoolVarCache(&sIsCustomElementsEnabled, + "dom.webcomponents.customelements.enabled", false); + Preferences::AddBoolVarCache(&sEncodeDecodeURLHash, "dom.url.encode_decode_hash", false); @@ -5293,51 +5301,6 @@ nsContentUtils::RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable) CycleCollectedJSContext::Get()->RunInMetastableState(Move(aRunnable)); } -void -nsContentUtils::EnterMicroTask() -{ - MOZ_ASSERT(NS_IsMainThread()); - ++sMicroTaskLevel; -} - -void -nsContentUtils::LeaveMicroTask() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (--sMicroTaskLevel == 0) { - PerformMainThreadMicroTaskCheckpoint(); - } -} - -bool -nsContentUtils::IsInMicroTask() -{ - MOZ_ASSERT(NS_IsMainThread()); - return sMicroTaskLevel != 0; -} - -uint32_t -nsContentUtils::MicroTaskLevel() -{ - MOZ_ASSERT(NS_IsMainThread()); - return sMicroTaskLevel; -} - -void -nsContentUtils::SetMicroTaskLevel(uint32_t aLevel) -{ - MOZ_ASSERT(NS_IsMainThread()); - sMicroTaskLevel = aLevel; -} - -void -nsContentUtils::PerformMainThreadMicroTaskCheckpoint() -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsDOMMutationObserver::HandleMutations(); -} - /* * Helper function for nsContentUtils::ProcessViewportInfo. * @@ -9567,11 +9530,34 @@ nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument) return false; } +/* static */ void +nsContentUtils::TryToUpgradeElement(Element* aElement) +{ + NodeInfo* nodeInfo = aElement->NodeInfo(); + RefPtr<nsIAtom> typeAtom = + aElement->GetCustomElementData()->GetCustomElementType(); + + MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())); + CustomElementDefinition* definition = + nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), + nodeInfo->NameAtom(), + nodeInfo->NamespaceID(), + typeAtom); + if (definition) { + nsContentUtils::EnqueueUpgradeReaction(aElement, definition); + } else { + // Add an unresolved custom element that is a candidate for + // upgrade when a custom element is connected to the document. + // We will make sure it's shadow-including tree order in bug 1326028. + nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom); + } +} + /* static */ CustomElementDefinition* nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc, - const nsAString& aLocalName, + nsIAtom* aNameAtom, uint32_t aNameSpaceID, - const nsAString* aIs) + nsIAtom* aTypeAtom) { MOZ_ASSERT(aDoc); @@ -9593,30 +9579,37 @@ nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc, return nullptr; } - return registry->LookupCustomElementDefinition(aLocalName, aIs); + return registry->LookupCustomElementDefinition(aNameAtom, aTypeAtom); } /* static */ void -nsContentUtils::SetupCustomElement(Element* aElement, - const nsAString* aTypeExtension) +nsContentUtils::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName) { MOZ_ASSERT(aElement); - nsCOMPtr<nsIDocument> doc = aElement->OwnerDoc(); - - if (!doc) { + nsIDocument* doc = aElement->OwnerDoc(); + nsPIDOMWindowInner* window(doc->GetInnerWindow()); + if (!window) { return; } - // To support imported document. - doc = doc->MasterDocument(); - - if (aElement->GetNameSpaceID() != kNameSpaceID_XHTML || - !doc->GetDocShell()) { + RefPtr<CustomElementRegistry> registry(window->CustomElements()); + if (!registry) { return; } - nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow()); + registry->RegisterUnresolvedElement(aElement, aTypeName); +} + +/* static */ void +nsContentUtils::UnregisterUnresolvedElement(Element* aElement) +{ + MOZ_ASSERT(aElement); + + RefPtr<nsIAtom> typeAtom = + aElement->GetCustomElementData()->GetCustomElementType(); + nsIDocument* doc = aElement->OwnerDoc(); + nsPIDOMWindowInner* window(doc->GetInnerWindow()); if (!window) { return; } @@ -9626,36 +9619,59 @@ nsContentUtils::SetupCustomElement(Element* aElement, return; } - return registry->SetupCustomElement(aElement, aTypeExtension); + registry->UnregisterUnresolvedElement(aElement, typeAtom); +} + +/* static */ CustomElementDefinition* +nsContentUtils::GetElementDefinitionIfObservingAttr(Element* aCustomElement, + nsIAtom* aExtensionType, + nsIAtom* aAttrName) +{ + CustomElementDefinition* definition = + aCustomElement->GetCustomElementDefinition(); + + // Custom element not defined yet or attribute is not in the observed + // attribute list. + if (!definition || !definition->IsInObservedAttributeList(aAttrName)) { + return nullptr; + } + + return definition; } /* static */ void -nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc, - nsIDocument::ElementCallbackType aType, - Element* aCustomElement, - LifecycleCallbackArgs* aArgs, - CustomElementDefinition* aDefinition) +nsContentUtils::EnqueueUpgradeReaction(Element* aElement, + CustomElementDefinition* aDefinition) { - MOZ_ASSERT(aDoc); + MOZ_ASSERT(aElement); - // To support imported document. - nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument(); + nsIDocument* doc = aElement->OwnerDoc(); - if (!doc->GetDocShell()) { + // No DocGroup means no custom element reactions stack. + if (!doc->GetDocGroup()) { return; } - nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow()); - if (!window) { - return; - } + CustomElementReactionsStack* stack = + doc->GetDocGroup()->CustomElementReactionsStack(); + stack->EnqueueUpgradeReaction(aElement, aDefinition); +} - RefPtr<CustomElementRegistry> registry(window->CustomElements()); - if (!registry) { +/* static */ void +nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, + Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs, + CustomElementDefinition* aDefinition) +{ + // No DocGroup means no custom element reactions stack. + if (!aCustomElement->OwnerDoc()->GetDocGroup()) { return; } - registry->EnqueueLifecycleCallback(aType, aCustomElement, aArgs, aDefinition); + CustomElementRegistry::EnqueueLifecycleCallback(aType, aCustomElement, aArgs, + aAdoptedCallbackArgs, + aDefinition); } /* static */ void @@ -9834,4 +9850,4 @@ nsContentUtils::IsLocalRefURL(const nsString& aString) } return false; -}
\ No newline at end of file +} diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 606d67de9..bf6a59dcd 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -126,6 +126,7 @@ class EventTarget; class IPCDataTransfer; class IPCDataTransferItem; struct LifecycleCallbackArgs; +struct LifecycleAdoptedCallbackArgs; class NodeInfo; class nsIContentChild; class nsIContentParent; @@ -1739,17 +1740,6 @@ public: */ static void RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable); - // Call EnterMicroTask when you're entering JS execution. - // Usually the best way to do this is to use nsAutoMicroTask. - static void EnterMicroTask(); - static void LeaveMicroTask(); - - static bool IsInMicroTask(); - static uint32_t MicroTaskLevel(); - static void SetMicroTaskLevel(uint32_t aLevel); - - static void PerformMainThreadMicroTaskCheckpoint(); - /* Process viewport META data. This gives us information for the scale * and zoom of a page on mobile devices. We stick the information in * the document header and use it later on after rendering. @@ -2711,22 +2701,36 @@ public: static bool HttpsStateIsModern(nsIDocument* aDocument); /** + * Try to upgrade an element. + * https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade + */ + static void TryToUpgradeElement(Element* aElement); + + /** * Looking up a custom element definition. * https://html.spec.whatwg.org/#look-up-a-custom-element-definition */ static mozilla::dom::CustomElementDefinition* LookupCustomElementDefinition(nsIDocument* aDoc, - const nsAString& aLocalName, + nsIAtom* aNameAtom, uint32_t aNameSpaceID, - const nsAString* aIs = nullptr); + nsIAtom* aTypeAtom); - static void SetupCustomElement(Element* aElement, - const nsAString* aTypeExtension = nullptr); + static void RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName); + static void UnregisterUnresolvedElement(Element* aElement); - static void EnqueueLifecycleCallback(nsIDocument* aDoc, - nsIDocument::ElementCallbackType aType, + static mozilla::dom::CustomElementDefinition* + GetElementDefinitionIfObservingAttr(Element* aCustomElement, + nsIAtom* aExtensionType, + nsIAtom* aAttrName); + + static void EnqueueUpgradeReaction(Element* aElement, + mozilla::dom::CustomElementDefinition* aDefinition); + + static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, Element* aCustomElement, mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr, + mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr, mozilla::dom::CustomElementDefinition* aDefinition = nullptr); static void GetCustomPrototype(nsIDocument* aDoc, @@ -2743,6 +2747,12 @@ public: static bool IsLocalRefURL(const nsString& aString); + static bool + IsWebComponentsEnabled() { return sIsWebComponentsEnabled; } + + static bool + IsCustomElementsEnabled() { return sIsCustomElementsEnabled; } + private: static bool InitializeEventTable(); @@ -2829,7 +2839,6 @@ private: static bool sInitialized; static uint32_t sScriptBlockerCount; static uint32_t sDOMNodeRemovedSuppressCount; - static uint32_t sMicroTaskLevel; // Not an nsCOMArray because removing elements from those is slower static AutoTArray<nsCOMPtr<nsIRunnable>, 8>* sBlockedScriptRunners; static uint32_t sRunnersCountAtFirstBlocker; @@ -2850,6 +2859,8 @@ private: static bool sIsUserTimingLoggingEnabled; static bool sIsFrameTimingPrefEnabled; static bool sIsExperimentalAutocompleteEnabled; + static bool sIsWebComponentsEnabled; + static bool sIsCustomElementsEnabled; static bool sEncodeDecodeURLHash; static bool sGettersDecodeURLHash; static bool sPrivacyResistFingerprinting; @@ -2905,19 +2916,6 @@ public: } }; -class MOZ_STACK_CLASS nsAutoMicroTask -{ -public: - nsAutoMicroTask() - { - nsContentUtils::EnterMicroTask(); - } - ~nsAutoMicroTask() - { - nsContentUtils::LeaveMicroTask(); - } -}; - namespace mozilla { namespace dom { diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index 858a30ce5..4c4731c11 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -32,8 +32,6 @@ using mozilla::dom::Element; AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* nsDOMMutationObserver::sScheduledMutationObservers = nullptr; -nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr; - uint32_t nsDOMMutationObserver::sMutationLevel = 0; uint64_t nsDOMMutationObserver::sCount = 0; @@ -597,10 +595,32 @@ nsDOMMutationObserver::ScheduleForRun() RescheduleForRun(); } +class MutationObserverMicroTask final : public MicroTaskRunnable +{ +public: + virtual void Run(AutoSlowOperation& aAso) override + { + nsDOMMutationObserver::HandleMutations(aAso); + } + + virtual bool Suppressed() override + { + return nsDOMMutationObserver::AllScheduledMutationObserversAreSuppressed(); + } +}; + void nsDOMMutationObserver::RescheduleForRun() { if (!sScheduledMutationObservers) { + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (!ccjs) { + return; + } + + RefPtr<MutationObserverMicroTask> momt = + new MutationObserverMicroTask(); + ccjs->DispatchMicroTaskRunnable(momt.forget()); sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>; } @@ -862,36 +882,9 @@ nsDOMMutationObserver::HandleMutation() mCallback->Call(this, mutations, *this); } -class AsyncMutationHandler : public mozilla::Runnable -{ -public: - NS_IMETHOD Run() override - { - nsDOMMutationObserver::HandleMutations(); - return NS_OK; - } -}; - void -nsDOMMutationObserver::HandleMutationsInternal() +nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso) { - if (!nsContentUtils::IsSafeToRunScript()) { - nsContentUtils::AddScriptRunner(new AsyncMutationHandler()); - return; - } - static RefPtr<nsDOMMutationObserver> sCurrentObserver; - if (sCurrentObserver && !sCurrentObserver->Suppressed()) { - // In normal cases sScheduledMutationObservers will be handled - // after previous mutations are handled. But in case some - // callback calls a sync API, which spins the eventloop, we need to still - // process other mutations happening during that sync call. - // This does *not* catch all cases, but should work for stuff running - // in separate tabs. - return; - } - - mozilla::AutoSlowOperation aso; - nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr; while (sScheduledMutationObservers) { @@ -899,20 +892,21 @@ nsDOMMutationObserver::HandleMutationsInternal() sScheduledMutationObservers; sScheduledMutationObservers = nullptr; for (uint32_t i = 0; i < observers->Length(); ++i) { - sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]); - if (!sCurrentObserver->Suppressed()) { - sCurrentObserver->HandleMutation(); + RefPtr<nsDOMMutationObserver> currentObserver = + static_cast<nsDOMMutationObserver*>((*observers)[i]); + if (!currentObserver->Suppressed()) { + currentObserver->HandleMutation(); } else { if (!suppressedObservers) { suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >; } - if (!suppressedObservers->Contains(sCurrentObserver)) { - suppressedObservers->AppendElement(sCurrentObserver); + if (!suppressedObservers->Contains(currentObserver)) { + suppressedObservers->AppendElement(currentObserver); } } } delete observers; - aso.CheckForInterrupt(); + aAso.CheckForInterrupt(); } if (suppressedObservers) { @@ -923,7 +917,6 @@ nsDOMMutationObserver::HandleMutationsInternal() delete suppressedObservers; suppressedObservers = nullptr; } - sCurrentObserver = nullptr; } nsDOMMutationRecord* diff --git a/dom/base/nsDOMMutationObserver.h b/dom/base/nsDOMMutationObserver.h index cde32c57b..a8babc603 100644 --- a/dom/base/nsDOMMutationObserver.h +++ b/dom/base/nsDOMMutationObserver.h @@ -552,13 +552,29 @@ public: } // static methods - static void HandleMutations() + static void HandleMutations(mozilla::AutoSlowOperation& aAso) { if (sScheduledMutationObservers) { - HandleMutationsInternal(); + HandleMutationsInternal(aAso); } } + static bool AllScheduledMutationObserversAreSuppressed() + { + if (sScheduledMutationObservers) { + uint32_t len = sScheduledMutationObservers->Length(); + if (len > 0) { + for (uint32_t i = 0; i < len; ++i) { + if (!(*sScheduledMutationObservers)[i]->Suppressed()) { + return false; + } + } + return true; + } + } + return false; + } + static void EnterMutationHandling(); static void LeaveMutationHandling(); @@ -594,7 +610,7 @@ protected: return false; } - static void HandleMutationsInternal(); + static void HandleMutationsInternal(mozilla::AutoSlowOperation& aAso); static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver, uint32_t aMutationLevel); @@ -622,7 +638,6 @@ protected: static uint64_t sCount; static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers; - static nsDOMMutationObserver* sCurrentObserver; static uint32_t sMutationLevel; static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>* diff --git a/dom/base/nsDeprecatedOperationList.h b/dom/base/nsDeprecatedOperationList.h index ea4b05289..96a6c3ac0 100644 --- a/dom/base/nsDeprecatedOperationList.h +++ b/dom/base/nsDeprecatedOperationList.h @@ -34,7 +34,6 @@ DEPRECATED_OPERATION(UseOfCaptureEvents) DEPRECATED_OPERATION(UseOfReleaseEvents) DEPRECATED_OPERATION(UseOfDOM3LoadMethod) DEPRECATED_OPERATION(ChromeUseOfDOM3LoadMethod) -DEPRECATED_OPERATION(ShowModalDialog) DEPRECATED_OPERATION(Window_Content) DEPRECATED_OPERATION(SyncXMLHttpRequest) DEPRECATED_OPERATION(DataContainerEvent) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index afe88a454..293e48eb0 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1329,7 +1329,8 @@ nsIDocument::nsIDocument() mFrameRequestCallbacksScheduled(false), mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS), mPartID(0), - mUserHasInteracted(false) + mUserHasInteracted(false), + mThrowOnDynamicMarkupInsertionCounter(0) { SetIsInDocument(); @@ -5395,18 +5396,14 @@ nsDocument::CreateElement(const nsAString& aTagName, } const nsString* is = nullptr; - if (aOptions.IsElementCreationOptions()) { - // Throw NotFoundError if 'is' is not-null and definition is null - is = CheckCustomElementName(aOptions.GetAsElementCreationOptions(), - needsLowercase ? lcTagName : aTagName, mDefaultElementType, rv); - if (rv.Failed()) { - return nullptr; - } - } RefPtr<Element> elem = CreateElem( needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is); + if (is) { + elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true); + } + return elem.forget(); } @@ -5443,14 +5440,6 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, } const nsString* is = nullptr; - if (aOptions.IsElementCreationOptions()) { - // Throw NotFoundError if 'is' is not-null and definition is null - is = CheckCustomElementName(aOptions.GetAsElementCreationOptions(), - aQualifiedName, nodeInfo->NamespaceID(), rv); - if (rv.Failed()) { - return nullptr; - } - } nsCOMPtr<Element> element; rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), @@ -5459,6 +5448,10 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, return nullptr; } + if (is) { + element->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true); + } + return element.forget(); } @@ -5681,24 +5674,70 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* } nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName)); - CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom); + CustomElementDefinition* definition = + registry->mCustomDefinitions.GetWeak(typeAtom); if (!definition) { return true; } - nsDependentAtomString localName(definition->mLocalName); + RefPtr<Element> element; + + // We integrate with construction stack and do prototype swizzling here, so + // that old upgrade behavior could also share the new upgrade steps. + // And this old upgrade will be remove at some point (when everything is + // switched to latest custom element spec). + nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack = + definition->mConstructionStack; + if (constructionStack.Length()) { + element = constructionStack.LastElement(); + NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false); + + // Do prototype swizzling if dom reflector exists. + JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper()); + if (reflector) { + Maybe<JSAutoCompartment> ac; + JS::Rooted<JSObject*> prototype(aCx, definition->mPrototype); + if (element->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) { + ac.emplace(aCx, reflector); + if (!JS_WrapObject(aCx, &prototype) || + !JS_SetPrototype(aCx, reflector, prototype)) { + return false; + } + } else { + // We want to set the custom prototype in the compartment where it was + // registered. We store the prototype from define() without unwrapped, + // hence the prototype's compartment is the compartment where it was + // registered. + // In the case that |reflector| and |prototype| are in different + // compartments, this will set the prototype on the |reflector|'s wrapper + // and thus only visible in the wrapper's compartment, since we know + // reflector's principal does not subsume prototype's in this case. + ac.emplace(aCx, prototype); + if (!JS_WrapObject(aCx, &reflector) || + !JS_SetPrototype(aCx, reflector, prototype)) { + return false; + } + } - nsCOMPtr<Element> element = - document->CreateElem(localName, nullptr, kNameSpaceID_XHTML); - NS_ENSURE_TRUE(element, true); + // Wrap into current context. + if (!JS_WrapObject(aCx, &reflector)) { + return false; + } - if (definition->mLocalName != typeAtom) { - // This element is a custom element by extension, thus we need to - // do some special setup. For non-extended custom elements, this happens - // when the element is created. - nsContentUtils::SetupCustomElement(element, &elemName); + args.rval().setObject(*reflector); + return true; + } + } else { + nsDependentAtomString localName(definition->mLocalName); + element = + document->CreateElem(localName, nullptr, kNameSpaceID_XHTML, + (definition->mLocalName != typeAtom) ? &elemName + : nullptr); + NS_ENSURE_TRUE(element, false); } + // The prototype setup happens in Element::WrapObject(). + nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval()); NS_ENSURE_SUCCESS(rv, true); @@ -5710,7 +5749,7 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) { JS::Rooted<JSObject*> obj(aCx, aObject); - if (Preferences::GetBool("dom.webcomponents.enabled")) { + if (nsContentUtils::IsWebComponentsEnabled()) { return true; } @@ -5726,7 +5765,7 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) bool nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo) { - if (Preferences::GetBool("dom.webcomponents.enabled")) { + if (nsContentUtils::IsWebComponentsEnabled()) { return true; } @@ -5770,6 +5809,8 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType, return; } + AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(), + aCx); // Unconditionally convert TYPE to lowercase. nsAutoString lcType; nsContentUtils::ASCIIToLower(aType, lcType); @@ -6536,6 +6577,49 @@ nsIDocument::GetHtmlChildElement(nsIAtom* aTag) return nullptr; } +nsGenericHTMLElement* +nsIDocument::GetBody() +{ + Element* html = GetHtmlElement(); + if (!html) { + return nullptr; + } + + for (nsIContent* child = html->GetFirstChild(); + child; + child = child->GetNextSibling()) { + if (child->IsHTMLElement(nsGkAtoms::body) || + child->IsHTMLElement(nsGkAtoms::frameset)) { + return static_cast<nsGenericHTMLElement*>(child); + } + } + + return nullptr; +} + +void +nsIDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv) +{ + nsCOMPtr<Element> root = GetRootElement(); + + // The body element must be either a body tag or a frameset tag. And we must + // have a root element to be able to add kids to it. + if (!newBody || + !newBody->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset) || + !root) { + rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + return; + } + + // Use DOM methods so that we pass through the appropriate security checks. + nsCOMPtr<Element> currentBody = GetBody(); + if (currentBody) { + root->ReplaceChild(*newBody, *currentBody, rv); + } else { + root->AppendChild(*newBody, rv); + } +} + Element* nsDocument::GetTitleElement() { @@ -12526,8 +12610,12 @@ MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData) nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc) { - mMicroTaskLevel = nsContentUtils::MicroTaskLevel(); - nsContentUtils::SetMicroTaskLevel(0); + mMicroTaskLevel = 0; + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + mMicroTaskLevel = ccjs->MicroTaskLevel(); + ccjs->SetMicroTaskLevel(0); + } if (aDoc) { if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) { if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) { @@ -12543,7 +12631,10 @@ nsAutoSyncOperation::~nsAutoSyncOperation() for (int32_t i = 0; i < mDocuments.Count(); ++i) { mDocuments[i]->SetIsInSyncOperation(false); } - nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel); + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + ccjs->SetMicroTaskLevel(mMicroTaskLevel); + } } gfxUserFontSet* @@ -12713,30 +12804,6 @@ nsIDocument::UpdateStyleBackendType() #endif } -const nsString* -nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions, - const nsAString& aLocalName, - uint32_t aNamespaceID, - ErrorResult& rv) -{ - // only check aOptions if 'is' is passed and the webcomponents preference - // is enabled - if (!aOptions.mIs.WasPassed() || - !CustomElementRegistry::IsCustomElementEnabled()) { - return nullptr; - } - - const nsString* is = &aOptions.mIs.Value(); - - // Throw NotFoundError if 'is' is not-null and definition is null - if (!nsContentUtils::LookupCustomElementDefinition(this, aLocalName, - aNamespaceID, is)) { - rv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); - } - - return is; -} - Selection* nsIDocument::GetSelection(ErrorResult& aRv) { diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 8ea4993f0..90e511dcb 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -1388,20 +1388,6 @@ protected: private: static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp); - /** - * Check if the passed custom element name, aOptions.mIs, is a registered - * custom element type or not, then return the custom element name for future - * usage. - * - * If there is no existing custom element definition for this name, throw a - * NotFoundError. - */ - const nsString* CheckCustomElementName( - const mozilla::dom::ElementCreationOptions& aOptions, - const nsAString& aLocalName, - uint32_t aNamespaceID, - ErrorResult& rv); - public: virtual already_AddRefed<mozilla::dom::CustomElementRegistry> GetCustomElementRegistry() override; diff --git a/dom/base/nsGenericDOMDataNode.cpp b/dom/base/nsGenericDOMDataNode.cpp index 0ae15e09e..73463ea5e 100644 --- a/dom/base/nsGenericDOMDataNode.cpp +++ b/dom/base/nsGenericDOMDataNode.cpp @@ -793,17 +793,6 @@ nsGenericDOMDataNode::SetXBLInsertionParent(nsIContent* aContent) } } -CustomElementData * -nsGenericDOMDataNode::GetCustomElementData() const -{ - return nullptr; -} - -void -nsGenericDOMDataNode::SetCustomElementData(CustomElementData* aData) -{ -} - bool nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const { diff --git a/dom/base/nsGenericDOMDataNode.h b/dom/base/nsGenericDOMDataNode.h index 63aa64e74..e8818b518 100644 --- a/dom/base/nsGenericDOMDataNode.h +++ b/dom/base/nsGenericDOMDataNode.h @@ -162,9 +162,6 @@ public: virtual bool IsNodeOfType(uint32_t aFlags) const override; virtual bool IsLink(nsIURI** aURI) const override; - virtual mozilla::dom::CustomElementData* GetCustomElementData() const override; - virtual void SetCustomElementData(mozilla::dom::CustomElementData* aData) override; - NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override; NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 47b46dda0..c965d5b97 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -909,7 +909,6 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter *aOuterWindow) mMayHaveMouseEnterLeaveEventListener(false), mMayHavePointerEnterLeaveEventListener(false), mInnerObjectsFreed(false), - mIsModalContentWindow(false), mIsActive(false), mIsBackground(false), mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground", true) ? nsISuspendedTypes::SUSPENDED_BLOCK : nsISuspendedTypes::NONE_SUSPENDED), @@ -1957,7 +1956,6 @@ nsGlobalWindow::CleanUp() } mArguments = nullptr; - mDialogArguments = nullptr; CleanupCachedXBLHandlers(this); @@ -2195,7 +2193,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) @@ -2274,7 +2271,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments) NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue) NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) @@ -3019,8 +3015,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, } else { if (thisChrome) { newInnerWindow = nsGlobalChromeWindow::Create(this); - } else if (mIsModalContentWindow) { - newInnerWindow = nsGlobalModalWindow::Create(this); } else { newInnerWindow = nsGlobalWindow::Create(this); } @@ -3871,31 +3865,16 @@ nsGlobalWindow::SetArguments(nsIArray *aArguments) MOZ_ASSERT(IsOuterWindow()); nsresult rv; - // Historically, we've used the same machinery to handle openDialog arguments - // (exposed via window.arguments) and showModalDialog arguments (exposed via - // window.dialogArguments), even though the former is XUL-only and uses an XPCOM - // array while the latter is web-exposed and uses an arbitrary JS value. - // Moreover, per-spec |dialogArguments| is a property of the browsing context - // (outer), whereas |arguments| lives on the inner. - // // We've now mostly separated them, but the difference is still opaque to // nsWindowWatcher (the caller of SetArguments in this little back-and-forth // embedding waltz we do here). // // So we need to demultiplex the two cases here. nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); - if (mIsModalContentWindow) { - // nsWindowWatcher blindly converts the original nsISupports into an array - // of length 1. We need to recover it, and then cast it back to the concrete - // object we know it to be. - nsCOMPtr<nsISupports> supports = do_QueryElementAt(aArguments, 0, &rv); - NS_ENSURE_SUCCESS(rv, rv); - mDialogArguments = static_cast<DialogValueHolder*>(supports.get()); - } else { - mArguments = aArguments; - rv = currentInner->DefineArgumentsProperty(aArguments); - NS_ENSURE_SUCCESS(rv, rv); - } + + mArguments = aArguments; + rv = currentInner->DefineArgumentsProperty(aArguments); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -3904,7 +3883,6 @@ nsresult nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments) { MOZ_ASSERT(IsInnerWindow()); - MOZ_ASSERT(!mIsModalContentWindow); // Handled separately. nsIScriptContext *ctx = GetOuterWindowInternal()->mContext; NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED); @@ -4263,8 +4241,9 @@ CustomElementRegistry* nsGlobalWindow::CustomElements() { MOZ_RELEASE_ASSERT(IsInnerWindow()); + if (!mCustomElements) { - mCustomElements = CustomElementRegistry::Create(AsInner()); + mCustomElements = new CustomElementRegistry(AsInner()); } return mCustomElements; @@ -5040,21 +5019,6 @@ nsGlobalWindow::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj) nsContentUtils::ObjectPrincipal(aObj) == nsContentUtils::GetSystemPrincipal(); } -/* static */ bool -nsGlobalWindow::IsShowModalDialogEnabled(JSContext*, JSObject*) -{ - static bool sAddedPrefCache = false; - static bool sIsDisabled; - static const char sShowModalDialogPref[] = "dom.disable_window_showModalDialog"; - - if (!sAddedPrefCache) { - Preferences::AddBoolVarCache(&sIsDisabled, sShowModalDialogPref, false); - sAddedPrefCache = true; - } - - return !sIsDisabled && !XRE_IsContentProcess(); -} - nsIDOMOfflineResourceList* nsGlobalWindow::GetApplicationCache(ErrorResult& aError) { @@ -9741,126 +9705,6 @@ nsGlobalWindow::ConvertDialogOptions(const nsAString& aOptions, } } -already_AddRefed<nsIVariant> -nsGlobalWindow::ShowModalDialogOuter(const nsAString& aUrl, - nsIVariant* aArgument, - const nsAString& aOptions, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - MOZ_RELEASE_ASSERT(IsOuterWindow()); - - if (mDoc) { - mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog); - } - - if (!IsShowModalDialogEnabled()) { - aError.Throw(NS_ERROR_NOT_AVAILABLE); - return nullptr; - } - - RefPtr<DialogValueHolder> argHolder = - new DialogValueHolder(&aSubjectPrincipal, aArgument); - - // Before bringing up the window/dialog, unsuppress painting and flush - // pending reflows. - EnsureReflowFlushAndPaint(); - - if (!AreDialogsEnabled()) { - // We probably want to keep throwing here; silently doing nothing is a bit - // weird given the typical use cases of showModalDialog(). - aError.Throw(NS_ERROR_NOT_AVAILABLE); - return nullptr; - } - - if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) { - aError.Throw(NS_ERROR_NOT_AVAILABLE); - return nullptr; - } - - nsCOMPtr<nsPIDOMWindowOuter> dlgWin; - nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1")); - - ConvertDialogOptions(aOptions, options); - - options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0"); - - EnterModalState(); - uint32_t oldMicroTaskLevel = nsContentUtils::MicroTaskLevel(); - nsContentUtils::SetMicroTaskLevel(0); - aError = OpenInternal(aUrl, EmptyString(), options, - false, // aDialog - true, // aContentModal - true, // aCalledNoScript - true, // aDoJSFixups - true, // aNavigate - nullptr, argHolder, // args - nullptr, // aLoadInfo - false, // aForceNoOpener - getter_AddRefs(dlgWin)); - nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel); - LeaveModalState(); - if (aError.Failed()) { - return nullptr; - } - - nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin); - if (!dialog) { - return nullptr; - } - - nsCOMPtr<nsIVariant> retVal; - aError = dialog->GetReturnValue(getter_AddRefs(retVal)); - MOZ_ASSERT(!aError.Failed()); - - return retVal.forget(); -} - -already_AddRefed<nsIVariant> -nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument, - const nsAString& aOptions, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - FORWARD_TO_OUTER_OR_THROW(ShowModalDialogOuter, - (aUrl, aArgument, aOptions, aSubjectPrincipal, - aError), aError, nullptr); -} - -void -nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl, - JS::Handle<JS::Value> aArgument, - const nsAString& aOptions, - JS::MutableHandle<JS::Value> aRetval, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - MOZ_ASSERT(IsInnerWindow()); - - nsCOMPtr<nsIVariant> args; - aError = nsContentUtils::XPConnect()->JSToVariant(aCx, - aArgument, - getter_AddRefs(args)); - if (aError.Failed()) { - return; - } - - nsCOMPtr<nsIVariant> retVal = - ShowModalDialog(aUrl, args, aOptions, aSubjectPrincipal, aError); - if (aError.Failed()) { - return; - } - - JS::Rooted<JS::Value> result(aCx); - if (retVal) { - aError = nsContentUtils::XPConnect()->VariantToJS(aCx, - FastGetGlobalJSObject(), - retVal, aRetval); - } else { - aRetval.setNull(); - } -} - class ChildCommandDispatcher : public Runnable { public: @@ -14613,70 +14457,6 @@ nsGlobalChromeWindow::TakeOpenerForInitialContentBrowser(mozIDOMWindowProxy** aO return NS_OK; } -// nsGlobalModalWindow implementation - -// QueryInterface implementation for nsGlobalModalWindow -NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow) - NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow) -NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow) - -NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow) -NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow) - - -void -nsGlobalWindow::GetDialogArgumentsOuter(JSContext* aCx, - JS::MutableHandle<JS::Value> aRetval, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(IsModalContentWindow(), - "This should only be called on modal windows!"); - - if (!mDialogArguments) { - MOZ_ASSERT(mIsClosed, "This window should be closed!"); - aRetval.setUndefined(); - return; - } - - // This does an internal origin check, and returns undefined if the subject - // does not subsumes the origin of the arguments. - JS::Rooted<JSObject*> wrapper(aCx, GetWrapper()); - JSAutoCompartment ac(aCx, wrapper); - mDialogArguments->Get(aCx, wrapper, &aSubjectPrincipal, aRetval, aError); -} - -void -nsGlobalWindow::GetDialogArguments(JSContext* aCx, - JS::MutableHandle<JS::Value> aRetval, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - FORWARD_TO_OUTER_OR_THROW(GetDialogArgumentsOuter, - (aCx, aRetval, aSubjectPrincipal, aError), - aError, ); -} - -/* static */ already_AddRefed<nsGlobalModalWindow> -nsGlobalModalWindow::Create(nsGlobalWindow *aOuterWindow) -{ - RefPtr<nsGlobalModalWindow> window = new nsGlobalModalWindow(aOuterWindow); - window->InitWasOffline(); - return window.forget(); -} - -NS_IMETHODIMP -nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments) -{ - FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments), - NS_ERROR_NOT_INITIALIZED); - - // This does an internal origin check, and returns undefined if the subject - // does not subsumes the origin of the arguments. - return mDialogArguments->Get(nsContentUtils::SubjectPrincipal(), aArguments); -} - /* static */ already_AddRefed<nsGlobalWindow> nsGlobalWindow::Create(nsGlobalWindow *aOuterWindow) { @@ -14691,96 +14471,6 @@ nsGlobalWindow::InitWasOffline() mWasOffline = NS_IsOffline(); } -void -nsGlobalWindow::GetReturnValueOuter(JSContext* aCx, - JS::MutableHandle<JS::Value> aReturnValue, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(IsModalContentWindow(), - "This should only be called on modal windows!"); - - if (mReturnValue) { - JS::Rooted<JSObject*> wrapper(aCx, GetWrapper()); - JSAutoCompartment ac(aCx, wrapper); - mReturnValue->Get(aCx, wrapper, &aSubjectPrincipal, aReturnValue, aError); - } else { - aReturnValue.setUndefined(); - } -} - -void -nsGlobalWindow::GetReturnValue(JSContext* aCx, - JS::MutableHandle<JS::Value> aReturnValue, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - FORWARD_TO_OUTER_OR_THROW(GetReturnValueOuter, - (aCx, aReturnValue, aSubjectPrincipal, aError), - aError, ); -} - -NS_IMETHODIMP -nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal) -{ - FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK); - - if (!mReturnValue) { - nsCOMPtr<nsIVariant> variant = CreateVoidVariant(); - variant.forget(aRetVal); - return NS_OK; - } - return mReturnValue->Get(nsContentUtils::SubjectPrincipal(), aRetVal); -} - -void -nsGlobalWindow::SetReturnValueOuter(JSContext* aCx, - JS::Handle<JS::Value> aReturnValue, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - MOZ_RELEASE_ASSERT(IsOuterWindow()); - MOZ_ASSERT(IsModalContentWindow(), - "This should only be called on modal windows!"); - - nsCOMPtr<nsIVariant> returnValue; - aError = - nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue, - getter_AddRefs(returnValue)); - if (!aError.Failed()) { - mReturnValue = new DialogValueHolder(&aSubjectPrincipal, returnValue); - } -} - -void -nsGlobalWindow::SetReturnValue(JSContext* aCx, - JS::Handle<JS::Value> aReturnValue, - nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) -{ - FORWARD_TO_OUTER_OR_THROW(SetReturnValueOuter, - (aCx, aReturnValue, aSubjectPrincipal, aError), - aError, ); -} - -NS_IMETHODIMP -nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal) -{ - FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK); - - mReturnValue = new DialogValueHolder(nsContentUtils::SubjectPrincipal(), - aRetVal); - return NS_OK; -} - -/* static */ -bool -nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal) -{ - return xpc::WindowOrNull(aGlobal)->IsModalContentWindow(); -} - #if defined(MOZ_WIDGET_ANDROID) int16_t nsGlobalWindow::Orientation(CallerType aCallerType) const diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 1f420895c..5cfd3f056 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -458,9 +458,6 @@ public: static bool IsPrivilegedChromeWindow(JSContext* /* unused */, JSObject* aObj); - static bool IsShowModalDialogEnabled(JSContext* /* unused */ = nullptr, - JSObject* /* unused */ = nullptr); - bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId, JS::MutableHandle<JS::PropertyDescriptor> aDesc); @@ -583,9 +580,6 @@ public: return mIsChrome; } - using nsPIDOMWindow::IsModalContentWindow; - static bool IsModalContentWindow(JSContext* aCx, JSObject* aGlobal); - // GetScrollFrame does not flush. Callers should do it themselves as needed, // depending on which info they actually want off the scrollable frame. nsIScrollableFrame *GetScrollFrame(); @@ -950,12 +944,6 @@ public: mozilla::ErrorResult& aRv); void PrintOuter(mozilla::ErrorResult& aError); void Print(mozilla::ErrorResult& aError); - void ShowModalDialog(JSContext* aCx, const nsAString& aUrl, - JS::Handle<JS::Value> aArgument, - const nsAString& aOptions, - JS::MutableHandle<JS::Value> aRetval, - nsIPrincipal& aSubjectPrincipal, - mozilla::ErrorResult& aError); void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, const mozilla::dom::Optional<mozilla::dom::Sequence<JS::Value > >& aTransfer, @@ -1227,12 +1215,6 @@ public: mozilla::dom::Element* aPanel, mozilla::ErrorResult& aError); - void GetDialogArgumentsOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, - nsIPrincipal& aSubjectPrincipal, - mozilla::ErrorResult& aError); - void GetDialogArguments(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, - nsIPrincipal& aSubjectPrincipal, - mozilla::ErrorResult& aError); void GetReturnValueOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue, nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); @@ -1681,18 +1663,6 @@ protected: nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); - already_AddRefed<nsIVariant> - ShowModalDialogOuter(const nsAString& aUrl, nsIVariant* aArgument, - const nsAString& aOptions, - nsIPrincipal& aSubjectPrincipal, - mozilla::ErrorResult& aError); - - already_AddRefed<nsIVariant> - ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument, - const nsAString& aOptions, - nsIPrincipal& aSubjectPrincipal, - mozilla::ErrorResult& aError); - // Ask the user if further dialogs should be blocked, if dialogs are currently // being abused. This is used in the cases where we have no modifiable UI to // show, in that case we show a separate dialog to ask this question. @@ -1832,9 +1802,6 @@ protected: // For |window.arguments|, via |openDialog|. nsCOMPtr<nsIArray> mArguments; - // For |window.dialogArguments|, via |showModalDialog|. - RefPtr<DialogValueHolder> mDialogArguments; - // Only used in the outer. RefPtr<DialogValueHolder> mReturnValue; @@ -2067,40 +2034,14 @@ public: nsCOMPtr<mozIDOMWindowProxy> mOpenerForInitialContentBrowser; }; -/* - * nsGlobalModalWindow inherits from nsGlobalWindow. It is the global - * object created for a modal content windows only (i.e. not modal - * chrome dialogs). - */ -class nsGlobalModalWindow : public nsGlobalWindow, - public nsIDOMModalContentWindow -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIDOMMODALCONTENTWINDOW - - static already_AddRefed<nsGlobalModalWindow> Create(nsGlobalWindow *aOuterWindow); - -protected: - explicit nsGlobalModalWindow(nsGlobalWindow *aOuterWindow) - : nsGlobalWindow(aOuterWindow) - { - mIsModalContentWindow = true; - } - - ~nsGlobalModalWindow() {} -}; - /* factory function */ inline already_AddRefed<nsGlobalWindow> -NS_NewScriptGlobalObject(bool aIsChrome, bool aIsModalContentWindow) +NS_NewScriptGlobalObject(bool aIsChrome) { RefPtr<nsGlobalWindow> global; if (aIsChrome) { global = nsGlobalChromeWindow::Create(nullptr); - } else if (aIsModalContentWindow) { - global = nsGlobalModalWindow::Create(nullptr); } else { global = nsGlobalWindow::Create(nullptr); } diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index 405090865..dcdc632b4 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -26,7 +26,6 @@ namespace mozilla { class EventChainPreVisitor; namespace dom { class ShadowRoot; -struct CustomElementData; } // namespace dom namespace widget { struct IMEState; @@ -730,22 +729,6 @@ public: nsINode *GetFlattenedTreeParentNodeInternal() const; /** - * Gets the custom element data used by web components custom element. - * Custom element data is created at the first attempt to enqueue a callback. - * - * @return The custom element data or null if none. - */ - virtual mozilla::dom::CustomElementData *GetCustomElementData() const = 0; - - /** - * Sets the custom element data, ownership of the - * callback data is taken by this content. - * - * @param aCallbackData The custom element data. - */ - virtual void SetCustomElementData(mozilla::dom::CustomElementData* aData) = 0; - - /** * API to check if this is a link that's traversed in response to user input * (e.g. a click event). Specializations for HTML/SVG/generic XML allow for * different types of link in different types of content. diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index fdaee39ca..125816c95 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -61,6 +61,7 @@ class nsFrameLoader; class nsHTMLCSSStyleSheet; class nsHTMLDocument; class nsHTMLStyleSheet; +class nsGenericHTMLElement; class nsIAtom; class nsIBFCacheEntry; class nsIChannel; @@ -1036,6 +1037,11 @@ public: Element* GetHeadElement() { return GetHtmlChildElement(nsGkAtoms::head); } + // Get the "body" in the sense of document.body: The first <body> or + // <frameset> that's a child of a root <html> + nsGenericHTMLElement* GetBody(); + // Set the "body" in the sense of document.body. + void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv); /** * Accessors to the collection of stylesheets owned by this document. @@ -2573,9 +2579,9 @@ public: } enum ElementCallbackType { - eCreated, - eAttached, - eDetached, + eConnected, + eDisconnected, + eAdopted, eAttributeChanged }; @@ -2872,6 +2878,22 @@ public: virtual void ScheduleIntersectionObserverNotification() = 0; virtual void NotifyIntersectionObservers() = 0; + bool ShouldThrowOnDynamicMarkupInsertion() + { + return mThrowOnDynamicMarkupInsertionCounter; + } + + void IncrementThrowOnDynamicMarkupInsertionCounter() + { + ++mThrowOnDynamicMarkupInsertionCounter; + } + + void DecrementThrowOnDynamicMarkupInsertionCounter() + { + MOZ_ASSERT(mThrowOnDynamicMarkupInsertionCounter); + --mThrowOnDynamicMarkupInsertionCounter; + } + protected: bool GetUseCounter(mozilla::UseCounter aUseCounter) { @@ -3319,6 +3341,11 @@ protected: uint32_t mBlockDOMContentLoaded; + // Used in conjunction with the create-an-element-for-the-token algorithm to + // prevent custom element constructors from being able to use document.open(), + // document.close(), and document.write() when they are invoked by the parser. + uint32_t mThrowOnDynamicMarkupInsertionCounter; + // Our live MediaQueryLists PRCList mDOMMediaQueryLists; @@ -3392,6 +3419,23 @@ private: uint32_t mMicroTaskLevel; }; +class MOZ_RAII AutoSetThrowOnDynamicMarkupInsertionCounter final { + public: + explicit AutoSetThrowOnDynamicMarkupInsertionCounter( + nsIDocument* aDocument) + : mDocument(aDocument) + { + mDocument->IncrementThrowOnDynamicMarkupInsertionCounter(); + } + + ~AutoSetThrowOnDynamicMarkupInsertionCounter() { + mDocument->DecrementThrowOnDynamicMarkupInsertionCounter(); + } + + private: + nsIDocument* mDocument; +}; + // XXX These belong somewhere else nsresult NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false); diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 98b367b66..b6c843065 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -25,7 +25,7 @@ #include "xpcpublic.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" - +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Date.h" #include "mozilla/dom/Element.h" @@ -159,7 +159,8 @@ nsJSUtils::EvaluateString(JSContext* aCx, aEvaluationGlobal); MOZ_ASSERT_IF(aOffThreadToken, aCompileOptions.noScriptRval); MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(nsContentUtils::IsInMicroTask()); + MOZ_ASSERT(CycleCollectedJSContext::Get() && + CycleCollectedJSContext::Get()->MicroTaskLevel()); // Unfortunately, the JS engine actually compiles scripts with a return value // in a different, less efficient way. Furthermore, it can't JIT them in many @@ -293,7 +294,8 @@ nsJSUtils::CompileModule(JSContext* aCx, aEvaluationGlobal); MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal); MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(nsContentUtils::IsInMicroTask()); + MOZ_ASSERT(CycleCollectedJSContext::Get() && + CycleCollectedJSContext::Get()->MicroTaskLevel()); NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK); @@ -330,7 +332,8 @@ nsJSUtils::ModuleEvaluation(JSContext* aCx, JS::Handle<JSObject*> aModule) MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(nsContentUtils::IsInMicroTask()); + MOZ_ASSERT(CycleCollectedJSContext::Get() && + CycleCollectedJSContext::Get()->MicroTaskLevel()); NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK); diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp index 75d408151..384e56cde 100644 --- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -301,9 +301,12 @@ nsNodeUtils::LastRelease(nsINode* aNode) Element* elem = aNode->AsElement(); FragmentOrElement::nsDOMSlots* domSlots = static_cast<FragmentOrElement::nsDOMSlots*>(slots); - for (auto iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { - DOMIntersectionObserver* observer = iter.Key(); - observer->UnlinkTarget(*elem); + if (domSlots->mExtendedSlots) { + for (auto iter = domSlots->mExtendedSlots->mRegisteredIntersectionObservers.Iter(); + !iter.Done(); iter.Next()) { + DOMIntersectionObserver* observer = iter.Key(); + observer->UnlinkTarget(*elem); + } } } @@ -476,19 +479,33 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, rv = aNode->Clone(nodeInfo, getter_AddRefs(clone)); NS_ENSURE_SUCCESS(rv, rv); - if (clone->IsElement()) { + if (CustomElementRegistry::IsCustomElementEnabled() && + clone->IsHTMLElement()) { // The cloned node may be a custom element that may require - // enqueing created callback and prototype swizzling. - Element* elem = clone->AsElement(); - if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) { - nsContentUtils::SetupCustomElement(elem); - } else { - // Check if node may be custom element by type extension. - // ex. <button is="x-button"> - nsAutoString extension; - if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) && - !extension.IsEmpty()) { - nsContentUtils::SetupCustomElement(elem, &extension); + // enqueing upgrade reaction. + Element* cloneElem = clone->AsElement(); + RefPtr<nsIAtom> tagAtom = nodeInfo->NameAtom(); + CustomElementData* data = elem->GetCustomElementData(); + + // Check if node may be custom element by type extension. + // ex. <button is="x-button"> + nsAutoString extension; + if (!data || data->GetCustomElementType() != tagAtom) { + cloneElem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension); + } + + if (data || !extension.IsEmpty()) { + RefPtr<nsIAtom> typeAtom = extension.IsEmpty() ? tagAtom : NS_Atomize(extension); + cloneElem->SetCustomElementData(new CustomElementData(typeAtom)); + + MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())); + CustomElementDefinition* definition = + nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), + nodeInfo->NameAtom(), + nodeInfo->NamespaceID(), + typeAtom); + if (definition) { + nsContentUtils::EnqueueUpgradeReaction(cloneElem, definition); } } } @@ -523,6 +540,23 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, nsIDocument* newDoc = aNode->OwnerDoc(); if (newDoc) { + if (CustomElementRegistry::IsCustomElementEnabled()) { + // Adopted callback must be enqueued whenever a node’s + // shadow-including inclusive descendants that is custom. + Element* element = aNode->IsElement() ? aNode->AsElement() : nullptr; + if (element) { + CustomElementData* data = element->GetCustomElementData(); + if (data && data->mState == CustomElementData::State::eCustom) { + LifecycleAdoptedCallbackArgs args = { + oldDoc, + newDoc + }; + nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAdopted, + element, nullptr, &args); + } + } + } + // XXX what if oldDoc is null, we don't know if this should be // registered or not! Can that really happen? if (wasRegistered) { diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 47affbb06..5c07bf4d4 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -303,11 +303,6 @@ public: virtual bool CanClose() = 0; virtual void ForceClose() = 0; - bool IsModalContentWindow() const - { - return mIsModalContentWindow; - } - /** * Call this to indicate that some node (this window, its document, * or content in that document) has a paint event listener. @@ -629,11 +624,6 @@ protected: // This member is only used by inner windows. bool mInnerObjectsFreed; - - // This variable is used on both inner and outer windows (and they - // should match). - bool mIsModalContentWindow; - // Tracks activation state that's used for :-moz-window-inactive. // Only used on outer windows. bool mIsActive; diff --git a/dom/base/nsSandboxFlags.h b/dom/base/nsSandboxFlags.h index d18527597..b8c9ac357 100644 --- a/dom/base/nsSandboxFlags.h +++ b/dom/base/nsSandboxFlags.h @@ -29,8 +29,7 @@ const unsigned long SANDBOXED_NAVIGATION = 0x1; /** * This flag prevents content from creating new auxiliary browsing contexts, - * e.g. using the target attribute, the window.open() method, or the - * showModalDialog() method. + * e.g. using the target attribute, or the window.open() method. */ const unsigned long SANDBOXED_AUXILIARY_NAVIGATION = 0x2; diff --git a/dom/base/test/chrome/registerElement_ep.js b/dom/base/test/chrome/registerElement_ep.js index de32ba51c..9189593c0 100644 --- a/dom/base/test/chrome/registerElement_ep.js +++ b/dom/base/test/chrome/registerElement_ep.js @@ -1,8 +1,8 @@ var proto = Object.create(HTMLElement.prototype); proto.magicNumber = 42; -proto.createdCallback = function() { +proto.connectedCallback = function() { finishTest(this.magicNumber === 42); }; document.registerElement("x-foo", { prototype: proto }); -document.createElement("x-foo"); +document.firstChild.appendChild(document.createElement("x-foo")); diff --git a/dom/base/test/chrome/test_registerElement_content.xul b/dom/base/test/chrome/test_registerElement_content.xul index 9a918f2d7..bf00ed53d 100644 --- a/dom/base/test/chrome/test_registerElement_content.xul +++ b/dom/base/test/chrome/test_registerElement_content.xul @@ -21,19 +21,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028 <script type="application/javascript"><![CDATA[ /** Test for Bug 1130028 **/ - SimpleTest.waitForExplicitFinish(); + var connectedCallbackCount = 0; - var createdCallbackCount = 0; - - // Callback should be called once by element created in chrome, - // and once by element created in content. - function createdCallbackCalled() { - createdCallbackCount++; - ok(true, "Created callback called, should be called twice in test."); + // Callback should be called only once by element created in content. + function connectedCallbackCalled() { + connectedCallbackCount++; + is(connectedCallbackCount, 1, "Connected callback called, should be called once in test."); is(this.magicNumber, 42, "Callback should be able to see the custom prototype."); - if (createdCallbackCount == 2) { - SimpleTest.finish(); - } } function startTests() { @@ -45,10 +39,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028 var proto = Object.create(frame.contentWindow.HTMLElement.prototype); proto.magicNumber = 42; - proto.createdCallback = createdCallbackCalled; + proto.connectedCallback = connectedCallbackCalled; + frame.contentDocument.registerElement("x-bar", { prototype: proto }); + is(connectedCallbackCount, 1, "Connected callback should be called by element created in content."); - frame.contentDocument.createElement("x-bar"); + var element = frame.contentDocument.createElement("x-bar"); + is(element.magicNumber, 42, "Should be able to see the custom prototype on created element."); } ]]></script> diff --git a/dom/base/test/chrome/test_registerElement_ep.xul b/dom/base/test/chrome/test_registerElement_ep.xul index 6f1745268..b6a160c2e 100644 --- a/dom/base/test/chrome/test_registerElement_ep.xul +++ b/dom/base/test/chrome/test_registerElement_ep.xul @@ -26,8 +26,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028 SimpleTest.waitForExplicitFinish(); function finishTest(canSeePrototype) { - ok(true, "createdCallback called when reigsterElement was called with an extended principal."); - ok(canSeePrototype, "createdCallback should be able to see custom prototype."); + ok(true, "connectedCallback called when reigsterElement was called with an extended principal."); + ok(canSeePrototype, "connectedCallback should be able to see custom prototype."); SimpleTest.finish(); } diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index b3b804ce4..3dfd666f8 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -196,7 +196,6 @@ support-files = formReset.html invalid_accesscontrol.resource invalid_accesscontrol.resource^headers^ - mutationobserver_dialog.html orientationcommon.js script-1_bug597345.sjs script-2_bug597345.js @@ -627,9 +626,6 @@ subsuite = clipboard skip-if = toolkit == 'android' #bug 904183 [test_createHTMLDocument.html] [test_declare_stylesheet_obsolete.html] -[test_dialogArguments.html] -tags = openwindow -skip-if = toolkit == 'android' || e10s # showmodaldialog [test_document.all_iteration.html] [test_document.all_unqualified.html] [test_document_constructor.html] diff --git a/dom/base/test/mutationobserver_dialog.html b/dom/base/test/mutationobserver_dialog.html deleted file mode 100644 index 2cc815309..000000000 --- a/dom/base/test/mutationobserver_dialog.html +++ /dev/null @@ -1,62 +0,0 @@ -<html> - <head> - <title></title> - <script> - - var div = document.createElement("div"); - - var M; - if ("MozMutationObserver" in window) { - M = window.MozMutationObserver; - } else if ("WebKitMutationObserver" in window) { - M = window.WebKitMutationObserver; - } else { - M = window.MutationObserver; - } - - var didCall1 = false; - var didCall2 = false; - function testMutationObserverInDialog() { - div.innerHTML = "<span>1</span><span>2</span>"; - m = new M(function(records, observer) { - opener.is(records[0].type, "childList", "Should have got childList"); - opener.is(records[0].removedNodes.length, 2, "Should have got removedNodes"); - opener.is(records[0].addedNodes.length, 1, "Should have got addedNodes"); - observer.disconnect(); - m = null; - didCall1 = true; - }); - m.observe(div, { childList: true }); - div.innerHTML = "<span><span>foo</span></span>"; - } - - function testMutationObserverInDialog2() { - div.innerHTML = "<span>1</span><span>2</span>"; - m = new M(function(records, observer) { - opener.is(records[0].type, "childList", "Should have got childList"); - opener.is(records[0].removedNodes.length, 2, "Should have got removedNodes"); - opener.is(records[0].addedNodes.length, 1, "Should have got addedNodes"); - observer.disconnect(); - m = null; - didCall2 = true; - }); - m.observe(div, { childList: true }); - div.innerHTML = "<span><span>foo</span></span>"; - } - - window.addEventListener("load", testMutationObserverInDialog); - window.addEventListener("load", testMutationObserverInDialog2); - window.addEventListener("load", - function() { - opener.ok(didCall1, "Should have called 1st mutation callback"); - opener.ok(didCall2, "Should have called 2nd mutation callback"); - window.close(); - }); - </script> - <style> - </style> - </head> - <body> - <input type="button" onclick="window.close()" value="close"> - </body> -</html> diff --git a/dom/base/test/test_dialogArguments.html b/dom/base/test/test_dialogArguments.html deleted file mode 100644 index 70a091d00..000000000 --- a/dom/base/test/test_dialogArguments.html +++ /dev/null @@ -1,31 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>Test for Bug 1019761</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - - <meta http-equiv="content-type" content="text/html; charset=utf-8"> -</head> -<body> -<script type="application/javascript"> - -/* - Tests whether Firefox crashes when accessing the dialogArguments property - of a modal window that has been closed. -*/ -SimpleTest.waitForExplicitFinish(); - -function openModal() { - showModalDialog("javascript:opener.winRef = window; \ - window.opener.setTimeout(\'winRef.dialogArguments;\', 0);\ - window.close();"); - - ok(true, "dialogArguments did not cause a crash."); - SimpleTest.finish(); -} - -window.onload = openModal; -</script> -</body> -</html> diff --git a/dom/base/test/test_mutationobservers.html b/dom/base/test/test_mutationobservers.html index bde07c79c..7e4c99423 100644 --- a/dom/base/test/test_mutationobservers.html +++ b/dom/base/test/test_mutationobservers.html @@ -362,7 +362,7 @@ function testChildList5() { is(records[5].previousSibling, c3, ""); is(records[5].nextSibling, c5, ""); observer.disconnect(); - then(testAdoptNode); + then(testNestedMutations); m = null; }); m.observe(div, { childList: true, subtree: true }); @@ -375,6 +375,37 @@ function testChildList5() { div.appendChild(emptyDF); // empty document shouldn't cause mutation records } +function testNestedMutations() { + div.textContent = null; + div.appendChild(document.createTextNode("foo")); + var m2WasCalled = false; + m = new M(function(records, observer) { + is(records[0].type, "characterData", "Should have got characterData"); + observer.disconnect(); + m = null; + m3 = new M(function(records, observer) { + ok(m2WasCalled, "m2 should have been called before m3!"); + is(records[0].type, "characterData", "Should have got characterData"); + observer.disconnect(); + then(testAdoptNode); + m3 = null; + }); + m3.observe(div, { characterData: true, subtree: true}); + div.firstChild.data = "foo"; + }); + m2 = new M(function(records, observer) { + m2WasCalled = true; + is(records[0].type, "characterData", "Should have got characterData"); + observer.disconnect(); + m2 = null; + }); + m2.observe(div, { characterData: true, subtree: true}); + div.appendChild(document.createTextNode("foo")); + m.observe(div, { characterData: true, subtree: true }); + + div.firstChild.data = "bar"; +} + function testAdoptNode() { var d1 = document.implementation.createHTMLDocument(null); var d2 = document.implementation.createHTMLDocument(null); @@ -484,28 +515,6 @@ function testSyncXHR() { function testSyncXHR2() { ok(callbackHandled, "Should have called the mutation callback!"); - then(testModalDialog); -} - -function testModalDialog() { - var didHandleCallback = false; - div.innerHTML = "<span>1</span><span>2</span>"; - m = new M(function(records, observer) { - is(records[0].type, "childList", "Should have got childList"); - is(records[0].removedNodes.length, 2, "Should have got removedNodes"); - is(records[0].addedNodes.length, 1, "Should have got addedNodes"); - observer.disconnect(); - m = null; - didHandleCallback = true; - }); - m.observe(div, { childList: true }); - div.innerHTML = "<span><span>foo</span></span>"; - try { - window.showModalDialog("mutationobserver_dialog.html"); - ok(didHandleCallback, "Should have called the callback while showing modal dialog!"); - } catch(e) { - todo(false, "showModalDialog not implemented on this platform"); - } then(testTakeRecords); } diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index b244d4d2a..f76f14d95 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -16,13 +16,16 @@ #include "mozilla/SizePrintfMacros.h" #include "mozilla/Unused.h" #include "mozilla/UseCounter.h" +#include "mozilla/dom/DocGroup.h" #include "AccessCheck.h" #include "jsfriendapi.h" +#include "nsContentCreatorFunctions.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsIDocShell.h" #include "nsIDOMGlobalPropertyInitializer.h" +#include "nsIParserService.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIXPConnect.h" @@ -37,6 +40,7 @@ #include "nsGlobalWindow.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/dom/DOMError.h" #include "mozilla/dom/DOMErrorBinding.h" #include "mozilla/dom/DOMException.h" @@ -44,6 +48,7 @@ #include "mozilla/dom/HTMLObjectElement.h" #include "mozilla/dom/HTMLObjectElementBinding.h" #include "mozilla/dom/HTMLSharedObjectElement.h" +#include "mozilla/dom/HTMLElementBinding.h" #include "mozilla/dom/HTMLEmbedElementBinding.h" #include "mozilla/dom/HTMLAppletElementBinding.h" #include "mozilla/dom/Promise.h" @@ -62,6 +67,30 @@ namespace dom { using namespace workers; +// Forward declare GetConstructorObject methods. +#define HTML_TAG(_tag, _classname, _interfacename) \ +namespace HTML##_interfacename##ElementBinding { \ + JSObject* GetConstructorObject(JSContext*); \ +} +#define HTML_OTHER(_tag) +#include "nsHTMLTagList.h" +#undef HTML_TAG +#undef HTML_OTHER + +typedef JSObject* (*constructorGetterCallback)(JSContext*); + +// Mapping of html tag and GetConstructorObject methods. +#define HTML_TAG(_tag, _classname, _interfacename) HTML##_interfacename##ElementBinding::GetConstructorObject, +#define HTML_OTHER(_tag) nullptr, +// We use eHTMLTag_foo (where foo is the tag) which is defined in nsHTMLTags.h +// to index into this array. +static const constructorGetterCallback sConstructorGetterCallback[] = { + HTMLUnknownElementBinding::GetConstructorObject, +#include "nsHTMLTagList.h" +#undef HTML_TAG +#undef HTML_OTHER +}; + const JSErrorFormatString ErrorFormatString[] = { #define MSG_DEF(_name, _argc, _exn, _str) \ { #_name, _str, _argc, _exn }, @@ -3377,6 +3406,189 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs, return true; } +CustomElementReactionsStack* +GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj) +{ + // This might not be the right object, if there are wrappers. Unwrap if we can. + JSObject* obj = js::CheckedUnwrap(aObj); + if (!obj) { + return nullptr; + } + + nsGlobalWindow* window = xpc::WindowGlobalOrNull(obj); + if (!window) { + return nullptr; + } + + DocGroup* docGroup = window->AsInner()->GetDocGroup(); + if (!docGroup) { + return nullptr; + } + + return docGroup->CustomElementReactionsStack(); +} + +// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor +already_AddRefed<nsGenericHTMLElement> +CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs, + JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv) +{ + // Step 1. + nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports()); + if (!window) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsIDocument* doc = window->GetExtantDoc(); + if (!doc) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements()); + if (!registry) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + // Step 2 is in the code output by CGClassConstructor. + // Step 3. + JSContext* cx = aGlobal.Context(); + JS::Rooted<JSObject*> newTarget(cx, &aCallArgs.newTarget().toObject()); + CustomElementDefinition* definition = + registry->LookupCustomElementDefinition(cx, newTarget); + if (!definition) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } + + // The callee might be an Xray. Unwrap it to get actual callee. + JS::Rooted<JSObject*> callee(cx, js::CheckedUnwrap(&aCallArgs.callee())); + if (!callee) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + // And the actual callee might be in different compartment, so enter its + // compartment before getting the standard constructor object to compare to, + // so we get it from the same global as callee itself. + JSAutoCompartment ac(cx, callee); + int32_t tag = eHTMLTag_userdefined; + if (!definition->IsCustomBuiltIn()) { + // Step 4. + // If the definition is for an autonomous custom element, the active + // function should be HTMLElement. + JS::Rooted<JSObject*> constructor(cx, HTMLElementBinding::GetConstructorObject(cx)); + if (!constructor) { + aRv.NoteJSContextException(cx); + return nullptr; + } + + if (callee != constructor) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } + } else { + // Step 5. + // If the definition is for a customized built-in element, the localName + // should be defined in the specification. + nsIParserService* parserService = nsContentUtils::GetParserService(); + if (!parserService) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + tag = parserService->HTMLCaseSensitiveAtomTagToId(definition->mLocalName); + if (tag == eHTMLTag_userdefined) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } + + MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds"); + + // If the definition is for a customized built-in element, the active + // function should be the localname's element interface. + constructorGetterCallback cb = sConstructorGetterCallback[tag]; + if (!cb) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } + + JS::Rooted<JSObject*> constructor(cx, cb(cx)); + if (!constructor) { + aRv.NoteJSContextException(cx); + return nullptr; + } + + if (callee != constructor) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } + } + + RefPtr<mozilla::dom::NodeInfo> nodeInfo = + doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName, + nullptr, + kNameSpaceID_XHTML, + nsIDOMNode::ELEMENT_NODE); + if (!nodeInfo) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + // Step 6 and Step 7 are in the code output by CGClassConstructor. + // Step 8. + nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack = + definition->mConstructionStack; + if (constructionStack.IsEmpty()) { + RefPtr<nsGenericHTMLElement> newElement; + if (tag == eHTMLTag_userdefined) { + // Autonomous custom element. + newElement = NS_NewHTMLElement(nodeInfo.forget()); + } else { + // Customized built-in element. + newElement = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER); + } + + newElement->SetCustomElementData( + new CustomElementData(definition->mType, CustomElementData::State::eCustom)); + + newElement->SetCustomElementDefinition(definition); + + return newElement.forget(); + } + + // Step 9. + RefPtr<nsGenericHTMLElement>& element = constructionStack.LastElement(); + + // Step 10. + if (element == ALEADY_CONSTRUCTED_MARKER) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + // Step 11. + // Do prototype swizzling for upgrading a custom element here, for cases when + // we have a reflector already. If we don't have one yet, our caller will + // create it with the right proto (by calling DoGetOrCreateDOMReflector with + // that proto). + JS::Rooted<JSObject*> reflector(cx, element->GetWrapper()); + if (reflector) { + // reflector might be in different compartment. + JSAutoCompartment ac(cx, reflector); + JS::Rooted<JSObject*> givenProto(cx, aGivenProto); + if (!JS_WrapObject(cx, &givenProto) || + !JS_SetPrototype(cx, reflector, givenProto)) { + aRv.NoteJSContextException(cx); + return nullptr; + } + } + + // Step 12 and Step 13. + return element.forget(); +} + #ifdef DEBUG namespace binding_detail { void diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 5cab835b3..e583d0e06 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -42,6 +42,7 @@ #include "nsWrapperCacheInlines.h" +class nsGenericHTMLElement; class nsIJSID; namespace mozilla { @@ -49,6 +50,7 @@ namespace mozilla { enum UseCounter : int16_t; namespace dom { +class CustomElementReactionsStack; template<typename KeyType, typename ValueType> class Record; nsresult @@ -3420,6 +3422,19 @@ bool GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs, JS::MutableHandle<JSObject*> aDesiredProto); +// Get the CustomElementReactionsStack for the docgroup of the global +// of the underlying object of aObj. This can be null if aObj can't +// be CheckUnwrapped, or if the global of the result has no docgroup +// (e.g. because it's not a Window global). +CustomElementReactionsStack* +GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj); +// This function is expected to be called from the constructor function for an +// HTML element interface; the global/callargs need to be whatever was passed to +// that constructor function. +already_AddRefed<nsGenericHTMLElement> +CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs, + JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv); + void SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject, UseCounter aUseCounter); diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index b00af2085..9428529f4 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1638,6 +1638,15 @@ DOMInterfaces = { 'register': False, }, +'TestHTMLConstructorInterface' : { + 'headerFile': 'TestBindingHeader.h', + 'register': False, + }, + +'TestCEReactionsInterface' : { + 'headerFile': 'TestBindingHeader.h', + 'register': False, + }, } # These are temporary, until they've been converted to use new DOM bindings diff --git a/dom/bindings/CallbackObject.cpp b/dom/bindings/CallbackObject.cpp index bb01c804c..398acf9da 100644 --- a/dom/bindings/CallbackObject.cpp +++ b/dom/bindings/CallbackObject.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/CallbackObject.h" +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/dom/BindingUtils.h" #include "jsfriendapi.h" #include "nsIScriptGlobalObject.h" @@ -79,7 +80,10 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback, , mIsMainThread(NS_IsMainThread()) { if (mIsMainThread) { - nsContentUtils::EnterMicroTask(); + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + ccjs->EnterMicroTask(); + } } // Compute the caller's subject principal (if necessary) early, before we @@ -288,7 +292,10 @@ CallbackObject::CallSetup::~CallSetup() // It is important that this is the last thing we do, after leaving the // compartment and undoing all our entry/incumbent script changes if (mIsMainThread) { - nsContentUtils::LeaveMicroTask(); + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + ccjs->LeaveMicroTask(); + } } } diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 6b23e8225..8ee732cca 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1747,6 +1747,71 @@ class CGClassConstructor(CGAbstractStaticMethod): else: ctorName = self.descriptor.interface.identifier.name + # [HTMLConstructor] for custom element + # This needs to live in bindings code because it directly examines + # newtarget and the callee function to do HTMLConstructor specific things. + if self._ctor.isHTMLConstructor(): + htmlConstructorSanityCheck = dedent(""" + // The newTarget might be a cross-compartment wrapper. Get the underlying object + // so we can do the spec's object-identity checks. + JS::Rooted<JSObject*> newTarget(cx, js::CheckedUnwrap(&args.newTarget().toObject())); + if (!newTarget) { + return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); + } + + // Step 2 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor. + // Enter the compartment of our underlying newTarget object, so we end + // up comparing to the constructor object for our interface from that global. + { + JSAutoCompartment ac(cx, newTarget); + JS::Handle<JSObject*> constructor(GetConstructorObjectHandle(cx)); + if (!constructor) { + return false; + } + if (newTarget == constructor) { + return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); + } + } + + """) + + # If we are unable to get desired prototype from newTarget, then we + # fall back to the interface prototype object from newTarget's realm. + htmlConstructorFallback = dedent(""" + if (!desiredProto) { + // Step 7 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor. + // This fallback behavior is designed to match analogous behavior for the + // JavaScript built-ins. So we enter the compartment of our underlying + // newTarget object and fall back to the prototype object from that global. + // XXX The spec says to use GetFunctionRealm(), which is not actually + // the same thing as what we have here (e.g. in the case of scripted callable proxies + // whose target is not same-compartment with the proxy, or bound functions, etc). + // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658 + { + JSAutoCompartment ac(cx, newTarget); + desiredProto = GetProtoObjectHandle(cx); + if (!desiredProto) { + return false; + } + } + + // desiredProto is in the compartment of the underlying newTarget object. + // Wrap it into the context compartment. + if (!JS_WrapObject(cx, &desiredProto)) { + return false; + } + } + """) + else: + htmlConstructorSanityCheck = "" + htmlConstructorFallback = "" + + + # If we're a constructor, "obj" may not be a function, so calling + # XrayAwareCalleeGlobal() on it is not safe. Of course in the + # constructor case either "obj" is an Xray or we're already in the + # content compartment, not the Xray compartment, so just + # constructing the GlobalObject from "obj" is fine. preamble = fill( """ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); @@ -1757,19 +1822,41 @@ class CGClassConstructor(CGAbstractStaticMethod): // Adding more relocations return ThrowConstructorWithoutNew(cx, "${ctorName}"); } + + GlobalObject global(cx, obj); + if (global.Failed()) { + return false; + } + + $*{htmlConstructorSanityCheck} JS::Rooted<JSObject*> desiredProto(cx); if (!GetDesiredProto(cx, args, &desiredProto)) { return false; } + $*{htmlConstructorFallback} """, chromeOnlyCheck=chromeOnlyCheck, - ctorName=ctorName) - - name = self._ctor.identifier.name - nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) - callGenerator = CGMethodCall(nativeName, True, self.descriptor, - self._ctor, isConstructor=True, - constructorName=ctorName) + ctorName=ctorName, + htmlConstructorSanityCheck=htmlConstructorSanityCheck, + htmlConstructorFallback=htmlConstructorFallback) + + if self._ctor.isHTMLConstructor(): + signatures = self._ctor.signatures() + assert len(signatures) == 1 + # Given that HTMLConstructor takes no args, we can just codegen a + # call to CreateHTMLElement() in BindingUtils which reuses the + # factory thing in HTMLContentSink. Then we don't have to implement + # Constructor on all the HTML elements. + callGenerator = CGPerSignatureCall(signatures[0][0], signatures[0][1], + "CreateHTMLElement", True, + self.descriptor, self._ctor, + isConstructor=True) + else: + name = self._ctor.identifier.name + nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) + callGenerator = CGMethodCall(nativeName, True, self.descriptor, + self._ctor, isConstructor=True, + constructorName=ctorName) return preamble + "\n" + callGenerator.define() @@ -7386,7 +7473,7 @@ class CGPerSignatureCall(CGThing): def __init__(self, returnType, arguments, nativeMethodName, static, descriptor, idlNode, argConversionStartsAt=0, getter=False, setter=False, isConstructor=False, useCounterName=None, - resultVar=None): + resultVar=None, objectName="obj"): assert idlNode.isMethod() == (not getter and not setter) assert idlNode.isAttr() == (getter or setter) # Constructors are always static @@ -7440,26 +7527,23 @@ class CGPerSignatureCall(CGThing): argsPre = [] if idlNode.isStatic(): - # If we're a constructor, "obj" may not be a function, so calling - # XrayAwareCalleeGlobal() on it is not safe. Of course in the - # constructor case either "obj" is an Xray or we're already in the - # content compartment, not the Xray compartment, so just - # constructing the GlobalObject from "obj" is fine. - if isConstructor: - objForGlobalObject = "obj" - else: - objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)" - cgThings.append(CGGeneric(fill( - """ - GlobalObject global(cx, ${obj}); - if (global.Failed()) { - return false; - } + # If we're a constructor, the GlobalObject struct will be created in + # CGClassConstructor. + if not isConstructor: + cgThings.append(CGGeneric(dedent( + """ + GlobalObject global(cx, xpc::XrayAwareCalleeGlobal(obj)); + if (global.Failed()) { + return false; + } + + """))) - """, - obj=objForGlobalObject))) argsPre.append("global") + if isConstructor and idlNode.isHTMLConstructor(): + argsPre.extend(["args", "desiredProto"]) + # For JS-implemented interfaces we do not want to base the # needsCx decision on the types involved, just on our extended # attributes. Also, JSContext is not needed for the static case @@ -7588,6 +7672,17 @@ class CGPerSignatureCall(CGThing): CGIfWrapper(CGList(xraySteps), "objIsXray")) + if (idlNode.getExtendedAttribute('CEReactions') is not None and + not getter): + cgThings.append(CGGeneric(fill( + """ + CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj}); + Maybe<AutoCEReaction> ceReaction; + if (reactionsStack) { + ceReaction.emplace(reactionsStack, cx); + } + """, obj=objectName))) + # If this is a method that was generated by a maplike/setlike # interface, use the maplike/setlike generator to fill in the body. # Otherwise, use CGCallGenerator to call the native method. @@ -10985,7 +11080,8 @@ class CGProxySpecialOperation(CGPerSignatureCall): # CGPerSignatureCall won't do any argument conversion of its own. CGPerSignatureCall.__init__(self, returnType, arguments, nativeName, False, descriptor, operation, - len(arguments), resultVar=resultVar) + len(arguments), resultVar=resultVar, + objectName="proxy") if operation.isSetter() or operation.isCreator(): # arguments[0] is the index or name of the item that we're setting. @@ -13755,12 +13851,18 @@ class CGBindingRoot(CGThing): iface = desc.interface return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface]) + def descriptorHasCEReactions(desc): + iface = desc.interface + return any(m.getExtendedAttribute("CEReactions") for m in iface.members + [iface]) + bindingHeaders["nsIDocument.h"] = any( descriptorDeprecated(d) for d in descriptors) bindingHeaders["mozilla/Preferences.h"] = any( descriptorRequiresPreferences(d) for d in descriptors) bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any( d.concrete and d.proxy for d in descriptors) + bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any( + descriptorHasCEReactions(d) for d in descriptors) def descriptorHasChromeOnly(desc): ctor = desc.interface.ctor() diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 4f602365b..81911996d 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -1582,7 +1582,7 @@ class IDLInterface(IDLInterfaceOrNamespace): [self.location]) self._noInterfaceObject = True - elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": + elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": if identifier == "Constructor" and not self.hasInterfaceObject(): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) @@ -1595,11 +1595,20 @@ class IDLInterface(IDLInterfaceOrNamespace): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) + if identifier == "HTMLConstructor": + if not self.hasInterfaceObject(): + raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", + [self.location]) + + if not attr.noArguments(): + raise WebIDLError(str(identifier) + " must take no arguments", + [attr.location]) + args = attr.args() if attr.hasArgs() else [] retType = IDLWrapperType(self.location, self) - if identifier == "Constructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": name = "constructor" allowForbidden = True else: @@ -1610,7 +1619,8 @@ class IDLInterface(IDLInterfaceOrNamespace): allowForbidden=allowForbidden) method = IDLMethod(self.location, methodIdentifier, retType, - args, static=True) + args, static=True, + htmlConstructor=(identifier == "HTMLConstructor")) # Constructors are always NewObject and are always # assumed to be able to throw (since there's no way to # indicate otherwise) and never have any other @@ -1622,7 +1632,7 @@ class IDLInterface(IDLInterfaceOrNamespace): method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) - if identifier == "Constructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor": method.resolve(self) else: # We need to detect conflicts for NamedConstructors across @@ -4073,6 +4083,11 @@ class IDLAttribute(IDLInterfaceMember): raise WebIDLError("Attribute returns a type that is not exposed " "everywhere where the attribute is exposed", [self.location]) + if self.getExtendedAttribute("CEReactions"): + if self.readonly: + raise WebIDLError("[CEReactions] is not allowed on " + "readonly attributes", + [self.location]) def handleExtendedAttribute(self, attr): identifier = attr.identifier() @@ -4243,6 +4258,10 @@ class IDLAttribute(IDLInterfaceMember): raise WebIDLError("[Unscopable] is only allowed on non-static " "attributes and operations", [attr.location, self.location]) + elif identifier == "CEReactions": + if not attr.noArguments(): + raise WebIDLError("[CEReactions] must take no arguments", + [attr.location]) elif (identifier == "Pref" or identifier == "Deprecated" or identifier == "SetterThrows" or @@ -4537,7 +4556,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): static=False, getter=False, setter=False, creator=False, deleter=False, specialType=NamedOrIndexed.Neither, legacycaller=False, stringifier=False, jsonifier=False, - maplikeOrSetlikeOrIterable=None): + maplikeOrSetlikeOrIterable=None, htmlConstructor=False): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.Tags.Method) @@ -4567,6 +4586,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._jsonifier = jsonifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable + assert isinstance(htmlConstructor, bool) + # The identifier of a HTMLConstructor must be 'constructor'. + assert not htmlConstructor or identifier.name == "constructor" + self._htmlConstructor = htmlConstructor self._specialType = specialType self._unforgeable = False self.dependsOn = "Everything" @@ -4667,6 +4690,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self.isStringifier() or self.isJsonifier()) + def isHTMLConstructor(self): + return self._htmlConstructor + def hasOverloads(self): return self._hasOverloads @@ -4722,6 +4748,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isStringifier() assert not self.isJsonifier() assert not method.isJsonifier() + assert not self.isHTMLConstructor() + assert not method.isHTMLConstructor() return self @@ -4964,6 +4992,15 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[Unscopable] is only allowed on non-static " "attributes and operations", [attr.location, self.location]) + elif identifier == "CEReactions": + if not attr.noArguments(): + raise WebIDLError("[CEReactions] must take no arguments", + [attr.location]) + + if self.isSpecial() and not self.isSetter() and not self.isDeleter(): + raise WebIDLError("[CEReactions] is only allowed on operation, " + "attribute, setter, and deleter", + [attr.location, self.location]) elif (identifier == "Throws" or identifier == "NewObject" or identifier == "ChromeOnly" or diff --git a/dom/bindings/parser/tests/test_cereactions.py b/dom/bindings/parser/tests/test_cereactions.py new file mode 100644 index 000000000..2f9397d90 --- /dev/null +++ b/dom/bindings/parser/tests/test_cereactions.py @@ -0,0 +1,162 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions(DOMString a)] void foo(boolean arg2); + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] with an argument") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions(DOMString b)] readonly attribute boolean bar; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] with an argument") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] attribute boolean bar; + }; + """) + + results = parser.finish() + except Exception, e: + harness.ok(False, "Shouldn't have thrown for [CEReactions] used on writable attribute. %s" % e) + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] void foo(boolean arg2); + }; + """) + + results = parser.finish() + except Exception, e: + harness.ok(False, "Shouldn't have thrown for [CEReactions] used on regular operations. %s" % e) + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] readonly attribute boolean A; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] used on a readonly attribute") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [CEReactions] + interface Foo { + } + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] used on a interface") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] getter any(DOMString name); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a named getter") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] creator boolean (DOMString name, boolean value); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a named creator") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] legacycaller double compute(double x); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a legacycaller") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] stringifier DOMString (); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [CEReactions] used on a stringifier") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface Foo { + [CEReactions] jsonifier; + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier") diff --git a/dom/bindings/parser/tests/test_constructor.py b/dom/bindings/parser/tests/test_constructor.py index 348204c7d..fb651c08d 100644 --- a/dom/bindings/parser/tests/test_constructor.py +++ b/dom/bindings/parser/tests/test_constructor.py @@ -13,7 +13,7 @@ def WebIDLTest(parser, harness): def checkMethod(method, QName, name, signatures, static=True, getter=False, setter=False, creator=False, deleter=False, legacycaller=False, stringifier=False, - chromeOnly=False): + chromeOnly=False, htmlConstructor=False): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") harness.ok(method.isMethod(), "Method is a method") @@ -29,6 +29,7 @@ def WebIDLTest(parser, harness): harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly") + harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value") harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") sigpairs = zip(method.signatures(), signatures) @@ -80,6 +81,21 @@ def WebIDLTest(parser, harness): parser = parser.reset() parser.parse(""" + [HTMLConstructor] + interface TestHTMLConstructor { + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestHTMLConstructor::constructor", + "constructor", [("TestHTMLConstructor (Wrapper)", [])], + htmlConstructor=True) + + parser = parser.reset() + parser.parse(""" [ChromeConstructor()] interface TestChromeConstructor { }; @@ -107,3 +123,151 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor") + + # Test HTMLConstructor with argument + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor(DOMString a)] + interface TestHTMLConstructorWithArgs { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "HTMLConstructor should take no argument") + + # Test HTMLConstructor on a callback interface + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor] + callback interface TestHTMLConstructorOnCallbackInterface { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "HTMLConstructor can't be used on a callback interface") + + # Test HTMLConstructor and Constructor + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor, + HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a Constructor and a HTMLConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + Constructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + Constructor(DOMString a)] + interface TestHTMLConstructorAndConstructor { + }; + """) + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor(DOMString a), + HTMLConstructor] + interface TestHTMLConstructorAndConstructor { + }; + """) + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor") + + # Test HTMLConstructor and ChromeConstructor + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ChromeConstructor, + HTMLConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + ChromeConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [ChromeConstructor(DOMString a), + HTMLConstructor] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [HTMLConstructor, + ChromeConstructor(DOMString a)] + interface TestHTMLConstructorAndChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor")
\ No newline at end of file diff --git a/dom/bindings/parser/tests/test_constructor_no_interface_object.py b/dom/bindings/parser/tests/test_constructor_no_interface_object.py index 2b09ae71e..af7b73d67 100644 --- a/dom/bindings/parser/tests/test_constructor_no_interface_object.py +++ b/dom/bindings/parser/tests/test_constructor_no_interface_object.py @@ -34,3 +34,36 @@ def WebIDLTest(parser, harness): interface TestNamedConstructorNoInterfaceObject { }; """) + + # Test HTMLConstructor and NoInterfaceObject + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [NoInterfaceObject, HTMLConstructor] + interface TestHTMLConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + + threw = False + try: + parser.parse(""" + [HTMLConstructor, NoInterfaceObject] + interface TestHTMLConstructorNoInterfaceObject { + }; + """) + + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown.")
\ No newline at end of file diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index ca5aafdc5..7d9963700 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -939,6 +939,11 @@ public: void NeedsCallerTypeMethod(CallerType); bool NeedsCallerTypeAttr(CallerType); void SetNeedsCallerTypeAttr(bool, CallerType); + void CeReactionsMethod(); + void CeReactionsMethodOverload(); + void CeReactionsMethodOverload(const nsAString&); + bool CeReactionsAttr() const; + void SetCeReactionsAttr(bool); int16_t LegacyCall(const JS::Value&, uint32_t, TestInterface&); void PassArgsWithDefaults(JSContext*, const Optional<int32_t>&, TestInterface*, const Dict&, double, @@ -1425,6 +1430,31 @@ public: void SetNeedsCallerTypeAttr(bool, CallerType); }; +class TestHTMLConstructorInterface : public nsGenericHTMLElement +{ +public: + virtual nsISupports* GetParentObject(); +}; + +class TestCEReactionsInterface : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_ISUPPORTS + + // We need a GetParentObject to make binding codegen happy + virtual nsISupports* GetParentObject(); + + int32_t Item(uint32_t); + uint32_t Length() const; + int32_t IndexedGetter(uint32_t, bool &); + void IndexedSetter(uint32_t, int32_t); + void NamedDeleter(const nsAString&, bool &); + void NamedGetter(const nsAString&, bool &, nsString&); + void NamedSetter(const nsAString&, const nsAString&); + void GetSupportedNames(nsTArray<nsString>&); +}; + } // namespace dom } // namespace mozilla diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index 4fb9be270..3fce5e21b 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -947,6 +947,10 @@ interface TestInterface { [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; [NeedsCallerType] void needsCallerTypeMethod(); [NeedsCallerType] attribute boolean needsCallerTypeAttr; + [CEReactions] void ceReactionsMethod(); + [CEReactions] void ceReactionsMethodOverload(); + [CEReactions] void ceReactionsMethodOverload(DOMString bar); + [CEReactions] attribute boolean ceReactionsAttr; legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, @@ -1262,3 +1266,16 @@ interface TestWorkerExposedInterface { [NeedsCallerType] void needsCallerTypeMethod(); [NeedsCallerType] attribute boolean needsCallerTypeAttr; }; + +[HTMLConstructor] +interface TestHTMLConstructorInterface { +}; + +interface TestCEReactionsInterface { + [CEReactions] setter creator void (unsigned long index, long item); + [CEReactions] setter creator void (DOMString name, DOMString item); + [CEReactions] deleter void (DOMString name); + getter long item(unsigned long index); + getter DOMString (DOMString name); + readonly attribute unsigned long length; +}; diff --git a/dom/bindings/test/TestExampleGen.webidl b/dom/bindings/test/TestExampleGen.webidl index ea6387a84..a2183c002 100644 --- a/dom/bindings/test/TestExampleGen.webidl +++ b/dom/bindings/test/TestExampleGen.webidl @@ -777,6 +777,10 @@ interface TestExampleInterface { [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; [NeedsCallerType] void needsCallerTypeMethod(); [NeedsCallerType] attribute boolean needsCallerTypeAttr; + [CEReactions] void ceReactionsMethod(); + [CEReactions] void ceReactionsMethodOverload(); + [CEReactions] void ceReactionsMethodOverload(DOMString bar); + [CEReactions] attribute boolean ceReactionsAttr; legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, diff --git a/dom/bindings/test/TestJSImplGen.webidl b/dom/bindings/test/TestJSImplGen.webidl index a131dcdfe..a133b9981 100644 --- a/dom/bindings/test/TestJSImplGen.webidl +++ b/dom/bindings/test/TestJSImplGen.webidl @@ -794,6 +794,10 @@ interface TestJSImplInterface { [Throws] attribute boolean throwingAttr; [GetterThrows] attribute boolean throwingGetterAttr; [SetterThrows] attribute boolean throwingSetterAttr; + [CEReactions] void ceReactionsMethod(); + [CEReactions] void ceReactionsMethodOverload(); + [CEReactions] void ceReactionsMethodOverload(DOMString bar); + [CEReactions] attribute boolean ceReactionsAttr; // NeedsSubjectPrincipal not supported on JS-implemented things for // now, because we always pass in the caller principal anyway. // [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); diff --git a/dom/bindings/test/test_bug560072.html b/dom/bindings/test/test_bug560072.html index 82bb1c2c6..0eebff116 100644 --- a/dom/bindings/test/test_bug560072.html +++ b/dom/bindings/test/test_bug560072.html @@ -20,11 +20,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=560072 /** Test for Bug 560072 **/ is(document.body, - Object.getOwnPropertyDescriptor(HTMLDocument.prototype, "body").get.call(document), + Object.getOwnPropertyDescriptor(Document.prototype, "body").get.call(document), "Should get body out of property descriptor"); is(document.body, - Object.getOwnPropertyDescriptor(Object.getPrototypeOf(document), "body").get.call(document), + Object.getOwnPropertyDescriptor( + Object.getPrototypeOf(Object.getPrototypeOf(document)), "body").get.call(document), "Should get body out of property descriptor this way too"); </script> diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index ebf0aa8c2..30d4c6522 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -440,6 +440,13 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) { MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized"); + if (!gl->MakeCurrent(true)) { + MOZ_ASSERT(false); + *out_failReason = { "FEATURE_FAILURE_WEBGL_MAKECURRENT", + "Failed to MakeCurrent for init." }; + return false; + } + // Unconditionally create a new format usage authority. This is // important when restoring contexts and extensions need to add // formats back into the authority. diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 0774c3296..2add7d009 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -1087,7 +1087,10 @@ EventListenerManager::HandleEventSubType(Listener* aListener, if (NS_SUCCEEDED(result)) { if (mIsMainThreadELM) { - nsContentUtils::EnterMicroTask(); + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + ccjs->EnterMicroTask(); + } } // nsIDOMEvent::currentTarget is set in EventDispatcher. if (listenerHolder.HasWebIDLCallback()) { @@ -1099,7 +1102,10 @@ EventListenerManager::HandleEventSubType(Listener* aListener, result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent); } if (mIsMainThreadELM) { - nsContentUtils::LeaveMicroTask(); + CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); + if (ccjs) { + ccjs->LeaveMicroTask(); + } } } diff --git a/dom/flyweb/FlyWebDiscoveryManager.cpp b/dom/flyweb/FlyWebDiscoveryManager.cpp index 5a97eb6d8..14ad5aa1f 100644 --- a/dom/flyweb/FlyWebDiscoveryManager.cpp +++ b/dom/flyweb/FlyWebDiscoveryManager.cpp @@ -16,6 +16,7 @@ #include "mozilla/dom/FlyWebDiscoveryManager.h" #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h" +#include "mozilla/dom/Element.h" namespace mozilla { namespace dom { diff --git a/dom/html/HTMLDetailsElement.cpp b/dom/html/HTMLDetailsElement.cpp index ed20b50ca..8619b1450 100644 --- a/dom/html/HTMLDetailsElement.cpp +++ b/dom/html/HTMLDetailsElement.cpp @@ -6,39 +6,11 @@ #include "mozilla/dom/HTMLDetailsElement.h" #include "mozilla/dom/HTMLDetailsElementBinding.h" -#include "mozilla/dom/HTMLUnknownElement.h" -#include "mozilla/Preferences.h" - -// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Details) to add pref check. -nsGenericHTMLElement* -NS_NewHTMLDetailsElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, - mozilla::dom::FromParser aFromParser) -{ - if (!mozilla::dom::HTMLDetailsElement::IsDetailsEnabled()) { - return new mozilla::dom::HTMLUnknownElement(aNodeInfo); - } - - return new mozilla::dom::HTMLDetailsElement(aNodeInfo); -} +NS_IMPL_NS_NEW_HTML_ELEMENT(Details) namespace mozilla { namespace dom { -/* static */ bool -HTMLDetailsElement::IsDetailsEnabled() -{ - static bool isDetailsEnabled = false; - static bool added = false; - - if (!added) { - Preferences::AddBoolVarCache(&isDetailsEnabled, - "dom.details_element.enabled"); - added = true; - } - - return isDetailsEnabled; -} - HTMLDetailsElement::~HTMLDetailsElement() { } diff --git a/dom/html/HTMLDetailsElement.h b/dom/html/HTMLDetailsElement.h index 5a3af27b4..6adf567bf 100644 --- a/dom/html/HTMLDetailsElement.h +++ b/dom/html/HTMLDetailsElement.h @@ -23,8 +23,6 @@ class HTMLDetailsElement final : public nsGenericHTMLElement public: using NodeInfo = mozilla::dom::NodeInfo; - static bool IsDetailsEnabled(); - explicit HTMLDetailsElement(already_AddRefed<NodeInfo>& aNodeInfo) : nsGenericHTMLElement(aNodeInfo) { diff --git a/dom/html/HTMLElement.cpp b/dom/html/HTMLElement.cpp index b2f23b931..d3901bdf3 100644 --- a/dom/html/HTMLElement.cpp +++ b/dom/html/HTMLElement.cpp @@ -52,3 +52,12 @@ NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, { return new mozilla::dom::HTMLElement(aNodeInfo); } + +// Distinct from the above in order to have function pointer that compared unequal +// to a function pointer to the above. +nsGenericHTMLElement* +NS_NewCustomElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + mozilla::dom::FromParser aFromParser) +{ + return new mozilla::dom::HTMLElement(aNodeInfo); +} diff --git a/dom/html/HTMLSummaryElement.cpp b/dom/html/HTMLSummaryElement.cpp index ee3c07b20..42ead6b87 100644 --- a/dom/html/HTMLSummaryElement.cpp +++ b/dom/html/HTMLSummaryElement.cpp @@ -14,17 +14,7 @@ #include "mozilla/TextEvents.h" #include "nsFocusManager.h" -// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Summary) to add pref check. -nsGenericHTMLElement* -NS_NewHTMLSummaryElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, - mozilla::dom::FromParser aFromParser) -{ - if (!mozilla::dom::HTMLDetailsElement::IsDetailsEnabled()) { - return new mozilla::dom::HTMLUnknownElement(aNodeInfo); - } - - return new mozilla::dom::HTMLSummaryElement(aNodeInfo); -} +NS_IMPL_NS_NEW_HTML_ELEMENT(Summary) namespace mozilla { namespace dom { diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index 0c8bcc9c8..78e4d5b95 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -497,7 +497,7 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // We need to consider a labels element is moved to another subtree // with different root, it needs to update labels list and its root // as well. - nsDOMSlots* slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots && slots->mLabelsList) { slots->mLabelsList->MaybeResetRoot(SubtreeRoot()); } @@ -524,7 +524,7 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent) // We need to consider a labels element is removed from tree, // it needs to update labels list and its root as well. - nsDOMSlots* slots = GetExistingDOMSlots(); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots && slots->mLabelsList) { slots->mLabelsList->MaybeResetRoot(SubtreeRoot()); } @@ -1730,7 +1730,7 @@ nsGenericHTMLElement::Labels() { MOZ_ASSERT(IsLabelable(), "Labels() only allow labelable elements to use it."); - nsDOMSlots* slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); if (!slots->mLabelsList) { slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement, diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index acbebe087..2b8b608b9 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -1588,6 +1588,15 @@ protected: NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, \ mNodeInfo->Equals(nsGkAtoms::_tag)) +namespace mozilla { +namespace dom { + +typedef nsGenericHTMLElement* (*HTMLContentCreatorFunction)( + already_AddRefed<mozilla::dom::NodeInfo>&&, + mozilla::dom::FromParser aFromParser); + +} // namespace dom +} // namespace mozilla /** * A macro to declare the NS_NewHTMLXXXElement() functions. @@ -1636,6 +1645,13 @@ nsGenericHTMLElement* NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER); +// Distinct from the above in order to have function pointer that compared unequal +// to a function pointer to the above. +nsGenericHTMLElement* +NS_NewCustomElement( + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER); + NS_DECLARE_NS_NEW_HTML_ELEMENT(Shared) NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList) NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedObject) diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp index 3e8e019b8..1fe5d2a86 100644 --- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -84,10 +84,6 @@ using namespace mozilla::dom; //---------------------------------------------------------------------- -typedef nsGenericHTMLElement* - (*contentCreatorCallback)(already_AddRefed<mozilla::dom::NodeInfo>&&, - FromParser aFromParser); - nsGenericHTMLElement* NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, FromParser aFromParser) @@ -96,14 +92,12 @@ NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, return nullptr; } -#define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element, -#define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement, +#define HTML_TAG(_tag, _classname, _interfacename) NS_NewHTML##_classname##Element, #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement, -static const contentCreatorCallback sContentCreatorCallbacks[] = { +static const HTMLContentCreatorFunction sHTMLContentCreatorFunctions[] = { NS_NewHTMLUnknownElement, #include "nsHTMLTagList.h" #undef HTML_TAG -#undef HTML_HTMLELEMENT_TAG #undef HTML_OTHER NS_NewHTMLUnknownElement }; @@ -234,9 +228,35 @@ public: int32_t mStackPos; }; +static void +DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, nsIAtom* aLocalName, + CustomElementConstructor* aConstructor, ErrorResult& aRv) +{ + RefPtr<Element> element = + aConstructor->Construct("Custom Element Create", aRv); + if (aRv.Failed()) { + return; + } + + if (!element || !element->IsHTMLElement()) { + aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement")); + return; + } + + if (aDoc != element->OwnerDoc() || element->GetParentNode() || + element->HasChildren() || element->GetAttrCount() || + element->NodeInfo()->NameAtom() != aLocalName) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return; + } + + element.forget(aElement); +} + nsresult NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, - FromParser aFromParser, const nsAString* aIs) + FromParser aFromParser, const nsAString* aIs, + mozilla::dom::CustomElementDefinition* aDefinition) { *aResult = nullptr; @@ -247,16 +267,109 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& return NS_ERROR_OUT_OF_MEMORY; nsIAtom *name = nodeInfo->NameAtom(); + RefPtr<nsIAtom> tagAtom = nodeInfo->NameAtom(); + RefPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom; NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML), "Trying to HTML elements that don't have the XHTML namespace"); int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name); - // Per the Custom Element specification, unknown tags that are valid custom - // element names should be HTMLElement instead of HTMLUnknownElement. bool isCustomElementName = (tag == eHTMLTag_userdefined && nsContentUtils::IsCustomElementName(name)); + bool isCustomElement = isCustomElementName || aIs; + MOZ_ASSERT_IF(aDefinition, isCustomElement); + + // https://dom.spec.whatwg.org/#concept-create-element + // We only handle the "synchronous custom elements flag is set" now. + // For the unset case (e.g. cloning a node), see bug 1319342 for that. + // Step 4. + CustomElementDefinition* definition = aDefinition; + if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement && + !definition) { + MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName())); + definition = + nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), + nodeInfo->NameAtom(), + nodeInfo->NamespaceID(), + typeAtom); + } + + // It might be a problem that parser synchronously calls constructor, so filed + // bug 1378079 to figure out what we should do for parser case. + if (definition) { + /* + * Synchronous custom elements flag is determined by 3 places in spec, + * 1) create an element for a token, the flag is determined by + * "will execute script" which is not originally created + * for the HTML fragment parsing algorithm. + * 2) createElement and createElementNS, the flag is the same as + * NOT_FROM_PARSER. + * 3) clone a node, our implementation will not go into this function. + * For the unset case which is non-synchronous only applied for + * inner/outerHTML. + */ + bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT || + aFromParser == dom::NOT_FROM_PARSER; + // Per discussion in https://github.com/w3c/webcomponents/issues/635, + // use entry global in those places that are called from JS APIs and use the + // node document's global object if it is called from parser. + nsIGlobalObject* global; + if (aFromParser == dom::NOT_FROM_PARSER) { + global = GetEntryGlobal(); + } else { + global = nodeInfo->GetDocument()->GetScopeObject(); + } + if (!global) { + // In browser chrome code, one may have access to a document which doesn't + // have scope object anymore. + return NS_ERROR_FAILURE; + } + + AutoEntryScript aes(global, "create custom elements"); + JSContext* cx = aes.cx(); + ErrorResult rv; + + // Step 5. + if (definition->IsCustomBuiltIn()) { + // SetupCustomElement() should be called with an element that don't have + // CustomElementData setup, if not we will hit the assertion in + // SetCustomElementData(). + // Built-in element + *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take(); + (*aResult)->SetCustomElementData(new CustomElementData(typeAtom)); + if (synchronousCustomElements) { + CustomElementRegistry::Upgrade(*aResult, definition, rv); + if (rv.MaybeSetPendingException(cx)) { + aes.ReportException(); + } + } else { + nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); + } + + return NS_OK; + } + + // Step 6.1. + if (synchronousCustomElements) { + DoCustomElementCreate(aResult, nodeInfo->GetDocument(), + nodeInfo->NameAtom(), + definition->mConstructor, rv); + if (rv.MaybeSetPendingException(cx)) { + NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser)); + } + return NS_OK; + } + + // Step 6.2. + NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser)); + (*aResult)->SetCustomElementData(new CustomElementData(definition->mType)); + nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); + return NS_OK; + } + + // Per the Custom Element specification, unknown tags that are valid custom + // element names should be HTMLElement instead of HTMLUnknownElement. if (isCustomElementName) { NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser)); } else { @@ -267,8 +380,8 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& return NS_ERROR_OUT_OF_MEMORY; } - if (isCustomElementName || aIs) { - nsContentUtils::SetupCustomElement(*aResult, aIs); + if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement) { + (*aResult)->SetCustomElementData(new CustomElementData(typeAtom)); } return NS_OK; @@ -283,7 +396,7 @@ CreateHTMLElement(uint32_t aNodeType, aNodeType == eHTMLTag_userdefined, "aNodeType is out of bounds"); - contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType]; + HTMLContentCreatorFunction cb = sHTMLContentCreatorFunctions[aNodeType]; NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement, "Don't know how to construct tag element!"); diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 0f2d90673..f530d75e1 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1013,26 +1013,6 @@ nsHTMLDocument::SetDomain(const nsAString& aDomain, ErrorResult& rv) rv = NodePrincipal()->SetDomain(newURI); } -nsGenericHTMLElement* -nsHTMLDocument::GetBody() -{ - Element* html = GetHtmlElement(); - if (!html) { - return nullptr; - } - - for (nsIContent* child = html->GetFirstChild(); - child; - child = child->GetNextSibling()) { - if (child->IsHTMLElement(nsGkAtoms::body) || - child->IsHTMLElement(nsGkAtoms::frameset)) { - return static_cast<nsGenericHTMLElement*>(child); - } - } - - return nullptr; -} - NS_IMETHODIMP nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody) { @@ -1054,31 +1034,6 @@ nsHTMLDocument::SetBody(nsIDOMHTMLElement* aBody) return rv.StealNSResult(); } -void -nsHTMLDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv) -{ - nsCOMPtr<Element> root = GetRootElement(); - - // The body element must be either a body tag or a frameset tag. And we must - // have a html root tag, otherwise GetBody will not return the newly set - // body. - if (!newBody || - !newBody->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset) || - !root || !root->IsHTMLElement() || - !root->IsHTMLElement(nsGkAtoms::html)) { - rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); - return; - } - - // Use DOM methods so that we pass through the appropriate security checks. - nsCOMPtr<Element> currentBody = GetBodyElement(); - if (currentBody) { - root->ReplaceChild(*newBody, *currentBody, rv); - } else { - root->AppendChild(*newBody, rv); - } -} - NS_IMETHODIMP nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead) { @@ -1446,6 +1401,11 @@ nsHTMLDocument::Open(JSContext* cx, return nullptr; } + if (ShouldThrowOnDynamicMarkupInsertion()) { + aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + // Set up the content type for insertion nsAutoCString contentType; contentType.AssignLiteral("text/html"); @@ -1653,6 +1613,11 @@ nsHTMLDocument::Close(ErrorResult& rv) return; } + if (ShouldThrowOnDynamicMarkupInsertion()) { + rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + if (!mParser || !mParser->IsScriptCreated()) { return; } @@ -1728,6 +1693,10 @@ nsHTMLDocument::WriteCommon(JSContext *cx, return NS_ERROR_DOM_INVALID_STATE_ERR; } + if (ShouldThrowOnDynamicMarkupInsertion()) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + if (mParserAborted) { // Hixie says aborting the parser doesn't undefine the insertion point. // However, since we null out mParser in that case, we track the diff --git a/dom/html/nsHTMLDocument.h b/dom/html/nsHTMLDocument.h index 1fa81f6cd..c9e46b3fa 100644 --- a/dom/html/nsHTMLDocument.h +++ b/dom/html/nsHTMLDocument.h @@ -175,8 +175,8 @@ public: JS::MutableHandle<JSObject*> aRetval, mozilla::ErrorResult& rv); void GetSupportedNames(nsTArray<nsString>& aNames); - nsGenericHTMLElement *GetBody(); - void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv); + using nsIDocument::GetBody; + using nsIDocument::SetBody; mozilla::dom::HTMLSharedElement *GetHead() { return static_cast<mozilla::dom::HTMLSharedElement*>(GetHeadElement()); } diff --git a/dom/html/test/file_iframe_sandbox_c_if4.html b/dom/html/test/file_iframe_sandbox_c_if4.html index 53bf49559..828592d63 100644 --- a/dom/html/test/file_iframe_sandbox_c_if4.html +++ b/dom/html/test/file_iframe_sandbox_c_if4.html @@ -12,7 +12,7 @@ } function doStuff() { - // try to open a new window via target="_blank", target="BC341604", window.open(), and showModalDialog() + // try to open a new window via target="_blank", target="BC341604", and window.open() // the window we try to open closes itself once it opens sendMouseEvent({type:'click'}, 'target_blank'); sendMouseEvent({type:'click'}, 'target_BC341604'); @@ -25,15 +25,6 @@ } ok(threw, "window.open threw a JS exception and was not allowed"); - - threw = false; - try { - window.showModalDialog("about:blank"); - } catch(error) { - threw = true; - } - - ok(threw, "window.showModalDialog threw a JS exception and was not allowed"); } </script> <body onLoad="doStuff()"> diff --git a/dom/html/test/file_iframe_sandbox_j_if1.html b/dom/html/test/file_iframe_sandbox_j_if1.html deleted file mode 100644 index 6d4347dfc..000000000 --- a/dom/html/test/file_iframe_sandbox_j_if1.html +++ /dev/null @@ -1,30 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <meta charset="utf-8"> - <title>Test for Bug 766282</title> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> - -<script type="text/javascript"> - function doStuff() { - // Open a new window via showModalDialog(). - try { - window.showModalDialog("file_iframe_sandbox_k_if5.html"); - } catch(e) { - window.parent.ok_wrapper(false, "iframes sandboxed with allow-popups and allow-modals should be able to open a modal dialog"); - } - - // Open a new window via showModalDialog(). - try { - window.showModalDialog("file_iframe_sandbox_k_if7.html"); - } catch(e) { - window.parent.ok_wrapper(false, "iframes sandboxed with allow-popups and allow-modals should be able to open a modal dialog"); - } - } -</script> - -<body onLoad="doStuff()"> - I am sandboxed with "allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation". -</body> -</html> diff --git a/dom/html/test/file_iframe_sandbox_j_if2.html b/dom/html/test/file_iframe_sandbox_j_if2.html deleted file mode 100644 index 9552307ee..000000000 --- a/dom/html/test/file_iframe_sandbox_j_if2.html +++ /dev/null @@ -1,28 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <meta charset="utf-8"> - <title>Test for Bug 766282</title> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> - -<script type="text/javascript"> - function doSubOpens() { - // Open a new window showModalDialog(). - try { - window.showModalDialog("file_iframe_sandbox_k_if9.html"); - } catch(e) { - window.parent.ok_wrapper(false, "iframes sandboxed with allow-popups and allow-modals should be able to open a modal dialog"); - } - } - - window.doSubOpens = doSubOpens; -</script> - -<body> - I am sandboxed but with "allow-scripts allow-popups allow-same-origin". - After my initial load, "allow-same-origin" is removed and then I open file_iframe_sandbox_k_if9.html, - which attemps to call a function in my parent. - This should succeed since the new sandbox flags shouldn't have taken affect on me until I'm reloaded. -</body> -</html> diff --git a/dom/html/test/file_iframe_sandbox_j_if3.html b/dom/html/test/file_iframe_sandbox_j_if3.html deleted file mode 100644 index 07c5b66c1..000000000 --- a/dom/html/test/file_iframe_sandbox_j_if3.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <meta charset="utf-8"> - <title>Tests for Bug 766282</title> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - -</head> -<script type="text/javascript"> - function ok(result, desc) { - window.parent.ok_wrapper(result, desc); - } - - function doStuff() { - // Try to open a new window via showModalDialog(). - // The window we try to open closes itself once it opens. - try { - window.showModalDialog("file_iframe_sandbox_open_window_pass.html"); - } catch(e) { - ok(false, "iframes sandboxed with allow-popups and allow-modals should be able to open a modal dialog"); - } - } -</script> -<body onLoad="doStuff()"> - I am sandboxed but with "allow-popups allow-scripts allow-same-origin" -</body> -</html> diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 024de1cd9..4a50a9c3f 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -154,9 +154,6 @@ support-files = file_iframe_sandbox_form_pass.html file_iframe_sandbox_g_if1.html file_iframe_sandbox_h_if1.html - file_iframe_sandbox_j_if1.html - file_iframe_sandbox_j_if2.html - file_iframe_sandbox_j_if3.html file_iframe_sandbox_k_if1.html file_iframe_sandbox_k_if2.html file_iframe_sandbox_k_if3.html @@ -471,9 +468,6 @@ skip-if = toolkit == 'android' # just copy the conditions from the test above tags = openwindow [test_iframe_sandbox_inheritance.html] tags = openwindow -[test_iframe_sandbox_modal.html] -tags = openwindow -skip-if = toolkit == 'android' || e10s #modal tests fail on android [test_iframe_sandbox_navigation.html] tags = openwindow [test_iframe_sandbox_navigation2.html] @@ -540,8 +534,6 @@ skip-if = toolkit == 'android' #bug 811644 [test_bug369370.html] skip-if = toolkit == "android" || toolkit == "windows" # disabled on Windows because of bug 1234520 [test_bug380383.html] -[test_bug391777.html] -skip-if = toolkit == 'android' || e10s [test_bug402680.html] [test_bug403868.html] [test_bug403868.xhtml] @@ -607,4 +599,4 @@ skip-if = os == "android" # up/down arrow keys not supported on android [test_script_module.html] support-files = file_script_module.html - file_script_nomodule.html
\ No newline at end of file + file_script_nomodule.html diff --git a/dom/html/test/test_bug391777.html b/dom/html/test/test_bug391777.html deleted file mode 100644 index aa01a45de..000000000 --- a/dom/html/test/test_bug391777.html +++ /dev/null @@ -1,25 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=391777 ---> -<head> - <title>Test for Bug 391777</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=391777">Mozilla Bug 391777</a> -<p id="display"></p> -<script class="testbody" type="text/javascript"> - -/** Test for Bug 391777 **/ -var arg = {}; -arg.testVal = "foo"; -var result = window.showModalDialog("javascript:window.returnValue = window.dialogArguments.testVal; window.close(); 'This window should close on its own.';", arg); -ok(true, "We should get here without user interaction"); -is(result, "foo", "Unexpected result from showModalDialog"); - -</script> -</body> -</html> diff --git a/dom/html/test/test_iframe_sandbox_general.html b/dom/html/test/test_iframe_sandbox_general.html index 6d3a190ee..83f0e9045 100644 --- a/dom/html/test/test_iframe_sandbox_general.html +++ b/dom/html/test/test_iframe_sandbox_general.html @@ -41,7 +41,7 @@ function ok_wrapper(result, desc) { passedTests++; } - if (completedTests == 33) { + if (completedTests == 32) { is(passedTests, completedTests, "There are " + completedTests + " general tests that should pass"); SimpleTest.finish(); } diff --git a/dom/html/test/test_iframe_sandbox_modal.html b/dom/html/test/test_iframe_sandbox_modal.html deleted file mode 100644 index 1307ea9a5..000000000 --- a/dom/html/test/test_iframe_sandbox_modal.html +++ /dev/null @@ -1,122 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=766282 -implement allow-popups directive for iframe sandbox ---> -<head> - <meta charset="utf-8"> - <title>Tests for Bug 766282</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> - -<script> - -SimpleTest.waitForExplicitFinish(); -SimpleTest.requestFlakyTimeout("untriaged"); - -// A postMessage handler that is used by sandboxed iframes without -// 'allow-same-origin' to communicate pass/fail back to this main page. -window.addEventListener("message", receiveMessage, false); - -function receiveMessage(event) { - switch (event.data.type) { - case "attempted": - testAttempted(); - break; - case "ok": - ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); - break; - default: - // allow for old style message - if (event.data.ok != undefined) { - ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); - } - } -} - -var attemptedTests = 0; -var passedTests = 0; -var totalTestsToPass = 5; -var totalTestsToAttempt = 5; - -function ok_wrapper(result, desc, addToAttempted = true) { - ok(result, desc); - - if (result) { - passedTests++; - } - - if (addToAttempted) { - testAttempted(); - } -} - -// Added so that tests that don't register unless they fail, -// can at least notify that they've attempted to run. -function testAttempted() { - attemptedTests++; - if (attemptedTests == totalTestsToAttempt) { - // Make sure all tests have had a chance to complete. - setTimeout(function() {finish();}, 1000); - } -} - -var finishCalled = false; - -function finish() { - if (!finishCalled) { - finishCalled = true; - is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " modal tests that should pass"); - - SimpleTest.finish(); - } -} - -function doTest() { - // passes if good and fails if bad - // 1) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups - // allow-same-origin" should not have its origin sandbox flag set and be able to access - // document.cookie. (Done by file_iframe_sandbox_k_if5.html opened from - // file_iframe_sandbox_j_if1.html) using showModalDialog.) - - // passes if good - // 2) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups - // allow-top-navigation" should not have its top-level navigation sandbox flag set and be able to - // navigate top. (Done by file_iframe_sandbox_k_if5.html (and if6) opened from - // file_iframe_sandbox_j_if1.html) using showModalDialog.) - - // passes if good - // 3) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups - // all-forms" should not have its forms sandbox flag set and be able to submit forms. - // (Done by file_iframe_sandbox_k_if7.html opened from - // file_iframe_sandbox_j_if1.html) using showModalDialog.) - - // passes if good - // 4) Make sure that the sandbox flags copied to a new browsing context are taken from the - // current active document not the browsing context (iframe / docShell). - // This is done by removing allow-same-origin and calling doSubOpens from file_iframe_sandbox_j_if2.html, - // which opens file_iframe_sandbox_k_if9.html using showModalDialog. - var if_2 = document.getElementById('if_2'); - if_2.sandbox = 'allow-scripts allow-popups'; - if_2.contentWindow.doSubOpens(); - - // passes if good - // 5) Test that a sandboxed iframe with "allow-popups" can open a new window using window.ShowModalDialog. - // This is done via file_iframe_sandbox_j_if3.html which is sandboxed with "allow-popups allow-scripts - // allow-same-origin". The window it attempts to open calls window.opener.ok(true, ...) and - // file_iframe_j_if3.html has an ok() function that calls window.parent.ok_wrapper. -} - -addLoadEvent(doTest); -</script> - -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=766282">Mozilla Bug 766282</a> - implement allow-popups directive for iframe sandbox -<p id="display"></p> -<div id="content"> -<iframe sandbox="allow-scripts allow-popups allow-modals allow-same-origin allow-forms allow-top-navigation" id="if_1" src="file_iframe_sandbox_j_if1.html" height="10" width="10"></iframe> -<iframe sandbox="allow-scripts allow-popups allow-modals allow-same-origin" id="if_2" src="file_iframe_sandbox_j_if2.html" height="10" width="10"></iframe> -<iframe sandbox="allow-popups allow-modals allow-same-origin allow-scripts" id="if_3" src="file_iframe_sandbox_j_if3.html" height="10" width="10"></iframe> -</div> diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index 90171db10..df1e6cbf5 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -46,6 +46,7 @@ #include "nsIWritablePropertyBag2.h" #include "nsIContentSecurityPolicy.h" #include "nsSandboxFlags.h" +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/dom/ScriptSettings.h" #include "nsILoadInfo.h" #include "nsContentSecurityManager.h" @@ -241,7 +242,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, // New script entry point required, due to the "Create a script" step of // http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol - nsAutoMicroTask mt; + mozilla::nsAutoMicroTask mt; AutoEntryScript aes(innerGlobal, "javascript: URI", true); JSContext* cx = aes.cx(); JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject()); diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 0472979d7..6bd3aac94 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -174,8 +174,6 @@ UseOfCaptureEventsWarning=Use of captureEvents() is deprecated. To upgrade your UseOfReleaseEventsWarning=Use of releaseEvents() is deprecated. To upgrade your code, use the DOM 2 removeEventListener() method. For more help http://developer.mozilla.org/en/docs/DOM:element.removeEventListener # LOCALIZATION NOTE: Do not translate "document.load()" or "XMLHttpRequest" UseOfDOM3LoadMethodWarning=Use of document.load() is deprecated. To upgrade your code, use the DOM XMLHttpRequest object. For more help https://developer.mozilla.org/en/XMLHttpRequest -# LOCALIZATION NOTE: Do not translate "window.showModalDialog()" or "window.open()" -ShowModalDialogWarning=Use of window.showModalDialog() is deprecated. Use window.open() instead. For more help https://developer.mozilla.org/en-US/docs/Web/API/Window.open # LOCALIZATION NOTE: Do not translate "window._content" or "window.content" Window_ContentWarning=window._content is deprecated. Please use window.content instead. # LOCALIZATION NOTE: Do not translate "XMLHttpRequest" diff --git a/dom/media/webspeech/recognition/test/test_nested_eventloop.html b/dom/media/webspeech/recognition/test/test_nested_eventloop.html index bdbed6524..8b4cea6d7 100644 --- a/dom/media/webspeech/recognition/test/test_nested_eventloop.html +++ b/dom/media/webspeech/recognition/test/test_nested_eventloop.html @@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295 SimpleTest.waitForExplicitFinish(); /* - * window.showModalDialog() can be used to spin the event loop, causing + * SpecialPowers.spinEventLoop can be used to spin the event loop, causing * queued SpeechEvents (such as those created by calls to start(), stop() * or abort()) to be processed immediately. * When this is done from inside DOM event handlers, it is possible to @@ -33,7 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295 } function doneFunc() { // Trigger gc now and wait some time to make sure this test gets the blame - // for any assertions caused by showModalDialog + // for any assertions caused by spinning the event loop. // // NB - The assertions should be gone, but this looks too scary to touch // during batch cleanup. diff --git a/dom/svg/SVGElementFactory.cpp b/dom/svg/SVGElementFactory.cpp index abbb0a865..d3e922ee5 100644 --- a/dom/svg/SVGElementFactory.cpp +++ b/dom/svg/SVGElementFactory.cpp @@ -15,31 +15,28 @@ using namespace mozilla; using namespace mozilla::dom; // Hash table that maps nsIAtom* SVG tags to an offset index -// within the array sContentCreatorCallbacks (offset by TABLE_VALUE_OFFSET) +// within the array sSVGContentCreatorFunctions (offset by TABLE_VALUE_OFFSET) static PLHashTable* sTagAtomTable = nullptr; // We don't want to store 0 in the hash table as a return value of 0 from // PL_HashTableLookupConst indicates that the value is not found #define TABLE_VALUE_OFFSET 1 -#define SVG_TAG(_tag, _classname) \ -nsresult \ -NS_NewSVG##_classname##Element(nsIContent** aResult, \ - already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); \ -\ -static inline nsresult \ -Create##_classname##Element(nsIContent** aResult, \ - already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \ - FromParser aFromParser) \ -{ \ - return NS_NewSVG##_classname##Element(aResult, mozilla::Move(aNodeInfo)); \ -} +#define SVG_TAG(_tag, _classname) \ + nsresult NS_NewSVG##_classname##Element( \ + nsIContent** aResult, \ + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); \ + \ + nsresult NS_NewSVG##_classname##Element( \ + nsIContent** aResult, \ + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \ + FromParser aFromParser) \ + { \ + return NS_NewSVG##_classname##Element(aResult, mozilla::Move(aNodeInfo)); \ + } + +#define SVG_FROM_PARSER_TAG(_tag, _classname) -#define SVG_FROM_PARSER_TAG(_tag, _classname) \ -nsresult \ -NS_NewSVG##_classname##Element(nsIContent** aResult, \ - already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \ - FromParser aFromParser); #include "SVGTagList.h" #undef SVG_TAG #undef SVG_FROM_PARSER_TAG @@ -48,13 +45,8 @@ nsresult NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); -typedef nsresult - (*contentCreatorCallback)(nsIContent** aResult, - already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, - FromParser aFromParser); - -static const contentCreatorCallback sContentCreatorCallbacks[] = { -#define SVG_TAG(_tag, _classname) Create##_classname##Element, +static const SVGContentCreatorFunction sSVGContentCreatorFunctions[] = { +#define SVG_TAG(_tag, _classname) NS_NewSVG##_classname##Element, #define SVG_FROM_PARSER_TAG(_tag, _classname) NS_NewSVG##_classname##Element, #include "SVGTagList.h" #undef SVG_TAG @@ -124,7 +116,7 @@ NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& a MOZ_CRASH(); } - contentCreatorCallback cb = sContentCreatorCallbacks[index]; + SVGContentCreatorFunction cb = sSVGContentCreatorFunctions[index]; nsCOMPtr<nsIContent> content; nsresult rv = cb(getter_AddRefs(content), ni.forget(), aFromParser); @@ -135,3 +127,15 @@ NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& a // if we don't know what to create, just create a standard svg element: return NS_NewSVGElement(aResult, ni.forget()); } + +nsresult +NS_NewSVGUnknownElement(nsIContent** aResult, + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + FromParser aFromParser) +{ + RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo; + nsCOMPtr<Element> element; + nsresult rv = NS_NewSVGElement(getter_AddRefs(element), ni.forget()); + element.forget(aResult); + return rv; +} diff --git a/dom/svg/SVGElementFactory.h b/dom/svg/SVGElementFactory.h index 3a75ef750..6d6fa1ca9 100644 --- a/dom/svg/SVGElementFactory.h +++ b/dom/svg/SVGElementFactory.h @@ -18,7 +18,32 @@ public: static void Shutdown(); }; +typedef nsresult (*SVGContentCreatorFunction)( + nsIContent** aResult, + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + mozilla::dom::FromParser aFromParser); + } // namespace dom } // namespace mozilla +#define SVG_TAG(_tag, _classname) \ + nsresult NS_NewSVG##_classname##Element( \ + nsIContent** aResult, \ + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \ + mozilla::dom::FromParser aFromParser); + +#define SVG_FROM_PARSER_TAG(_tag, _classname) \ + nsresult NS_NewSVG##_classname##Element( \ + nsIContent** aResult, \ + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \ + mozilla::dom::FromParser aFromParser); +#include "SVGTagList.h" +#undef SVG_TAG +#undef SVG_FROM_PARSER_TAG + +nsresult +NS_NewSVGUnknownElement(nsIContent** aResult, + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + mozilla::dom::FromParser aFromParser); + #endif /* mozilla_dom_SVGElementFactory_h */ diff --git a/dom/svg/SVGTagList.h b/dom/svg/SVGTagList.h index 219cafc43..6fb5c0bef 100644 --- a/dom/svg/SVGTagList.h +++ b/dom/svg/SVGTagList.h @@ -9,7 +9,14 @@ This file contains the list of all SVG tags. It is designed to be used as inline input to SVGElementFactory.cpp - *only* through the magic of C preprocessing. + through the magic of C preprocessing. + + Additionally, it is consumed by the self-regeneration code in + ElementName.java from which nsHtml5ElementName.cpp/h is translated. + See parser/html/java/README.txt. + + If you edit this list, you need to re-run ElementName.java + self-regeneration and the HTML parser Java to C++ translation. All entries must be enclosed in the macro SVG_TAG or SVG_FROM_PARSER_TAG which will have cruel and unusual things done to them. diff --git a/dom/svg/moz.build b/dom/svg/moz.build index 298a7293d..08cf1d78d 100644 --- a/dom/svg/moz.build +++ b/dom/svg/moz.build @@ -14,6 +14,7 @@ EXPORTS += [ 'SVGContentUtils.h', 'SVGPreserveAspectRatio.h', 'SVGStringList.h', + 'SVGTagList.h', ] EXPORTS.mozilla.dom += [ @@ -39,6 +40,7 @@ EXPORTS.mozilla.dom += [ 'SVGDefsElement.h', 'SVGDescElement.h', 'SVGDocument.h', + 'SVGElementFactory.h', 'SVGEllipseElement.h', 'SVGFEBlendElement.h', 'SVGFEColorMatrixElement.h', diff --git a/dom/tests/mochitest/bugs/file_bug291653.html b/dom/tests/mochitest/bugs/file_bug291653.html deleted file mode 100644 index 4bfc8337e..000000000 --- a/dom/tests/mochitest/bugs/file_bug291653.html +++ /dev/null @@ -1,28 +0,0 @@ -<html> - <head> - <script> - <!-- - function listener1() { - window.showModalDialog("data:text/html,<script>var maintest = opener.opener; opener.location = 'data:text/html,test'; maintest.end(); window.close();</script>"); - } - - function listener2() { - opener.secondListenerDidRun = true; - } - - window.addEventListener("foo", listener1); - window.addEventListener("foo", listener2); - - - function fireFoo() { - var e = document.createEvent("Events"); - e.initEvent("foo", true, true); - window.dispatchEvent(e); - } - //--> - </script> - </head> - <body onload="setTimeout(fireFoo, 0)"> - Test for bug 291653 - </body> -</html> diff --git a/dom/tests/mochitest/bugs/file_bug504862.html b/dom/tests/mochitest/bugs/file_bug504862.html deleted file mode 100644 index dc11ced6f..000000000 --- a/dom/tests/mochitest/bugs/file_bug504862.html +++ /dev/null @@ -1,22 +0,0 @@ -<html> -<body> -<script> -window.returnValue = 3; - -if (location.toString().match(/^http:\/\/mochi.test:8888/)) { - // Test that we got the right arguments. - opener.is(window.dialogArguments, "my args", - "dialog did not get the right arguments."); - - // Load a different url, and test that it sees the arguments (since it's same origin). - window.location="data:text/html,<html><body onload=\"opener.is(window.dialogArguments, 'my args', 'subsequent dialog document did not get the right arguments.'); close();\">';"; -} else { - // Post a message containing our arguments to the opener to test - // that this cross origing dialog does *not* see the passed in - // arguments. - opener.postMessage("args: " + window.dialogArguments, - "http://mochi.test:8888"); - - close(); -} -</script> diff --git a/dom/tests/mochitest/bugs/mochitest.ini b/dom/tests/mochitest/bugs/mochitest.ini index 309aab6e0..3743c6782 100644 --- a/dom/tests/mochitest/bugs/mochitest.ini +++ b/dom/tests/mochitest/bugs/mochitest.ini @@ -10,9 +10,6 @@ support-files = child_bug260264.html devicemotion_inner.html devicemotion_outer.html - file_bug291653.html - file_bug406375.html - file_bug504862.html file_bug593174_1.html file_bug593174_2.html file_bug809290_b1.html @@ -45,7 +42,6 @@ skip-if = toolkit == 'android' [test_bug260264_nested.html] [test_bug265203.html] [test_bug291377.html] -[test_bug291653.html] skip-if = toolkit == 'android' #TIMED_OUT [test_bug304459.html] [test_bug308856.html] @@ -67,28 +63,21 @@ skip-if = toolkit == 'android' #TIMED_OUT [test_bug396843.html] [test_bug400204.html] [test_bug404748.html] -[test_bug406375.html] -skip-if = toolkit == 'android' -[test_bug414291.html] -tags = openwindow [test_bug427744.html] skip-if = toolkit == 'android' [test_bug42976.html] [test_bug430276.html] -[test_bug437361.html] skip-if = toolkit == 'android' [test_bug440572.html] [test_bug456151.html] [test_bug458091.html] [test_bug459848.html] [test_bug465263.html] -[test_bug479143.html] skip-if = toolkit == 'android' [test_bug484775.html] [test_bug492925.html] [test_bug49312.html] [test_bug495219.html] -[test_bug504862.html] skip-if = toolkit == 'android' #RANDOM [test_bug529328.html] [test_bug531176.html] @@ -126,7 +115,6 @@ skip-if = toolkit == 'android' [test_bug698061.html] [test_bug698551.html] [test_bug707749.html] -[test_bug735237.html] [test_bug739038.html] [test_bug740811.html] [test_bug743615.html] diff --git a/dom/tests/mochitest/bugs/test_bug291653.html b/dom/tests/mochitest/bugs/test_bug291653.html deleted file mode 100644 index 1543cdd96..000000000 --- a/dom/tests/mochitest/bugs/test_bug291653.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=291653 ---> -<head> - <title>Test for Bug 291653</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=291653">Mozilla Bug 291653</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -<script type="application/javascript"> - -/** Test for Bug 291653 **/ -SimpleTest.waitForExplicitFinish(); -SimpleTest.requestFlakyTimeout("untriaged"); - -var secondListenerDidRun = false; - -var w; -function start() { - if ("showModalDialog" in window) { - w = window.open("file_bug291653.html", "foo", "width=300,height=300"); - } else { - // window.showModalDialog doesn't exist in e10s mode, nothing to do in this test. - ok(true, "nothing to do in e10s mode"); - SimpleTest.finish(); - } -} - -function closeTest() { - w.setTimeout("close()", 0); - setTimeout("finish()", 500); -} - -function finish() { - ok(!secondListenerDidRun, "Shouldn't have run second listener!"); - SimpleTest.finish(); -} - -function end() { - setTimeout("closeTest()", 500); -} - -start(); - -</script> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/bugs/test_bug406375.html b/dom/tests/mochitest/bugs/test_bug406375.html deleted file mode 100644 index 2cd459ffa..000000000 --- a/dom/tests/mochitest/bugs/test_bug406375.html +++ /dev/null @@ -1,37 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=406375 ---> -<head> - <title>Test for Bug 406375</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> -<body onload="runTest()"> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=406375">Mozilla Bug 406375</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -<script type="application/javascript"> - -/** Test for Bug 406375 **/ - - -SimpleTest.waitForExplicitFinish(); - -function runTest() { - if ("showModalDialog" in window) { - window.showModalDialog("file_bug406375.html"); - } - ok(true, "This test should not hang"); - - SimpleTest.finish(); -} - -</script> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/bugs/test_bug414291.html b/dom/tests/mochitest/bugs/test_bug414291.html index 883e52bb4..0ee5cb393 100644 --- a/dom/tests/mochitest/bugs/test_bug414291.html +++ b/dom/tests/mochitest/bugs/test_bug414291.html @@ -16,7 +16,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=414291 var result1 = 0; var result2 = 0; -var result3 = 0; window.open("data:text/html,<html><body onload='close(); opener.result1 = 1;'>", "w1"); is(result1, 0, "window should not be opened either as modal or loaded synchronously."); @@ -24,11 +23,6 @@ is(result1, 0, "window should not be opened either as modal or loaded synchronou window.open("data:text/html,<html><body onload='close(); opener.result2 = 2;'>", "w2", "modal=yes"); is(result2, 0, "window should not be opened either as modal or data loaded synchronously."); -if (window.showModalDialog) { - result3 = window.showModalDialog("data:text/html,<html><body onload='close(); returnValue = 3;'>"); - is(result3, 3, "window should be opened as modal."); -} - </script> </pre> </body> diff --git a/dom/tests/mochitest/bugs/test_bug437361.html b/dom/tests/mochitest/bugs/test_bug437361.html deleted file mode 100644 index ecc2cb08d..000000000 --- a/dom/tests/mochitest/bugs/test_bug437361.html +++ /dev/null @@ -1,72 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=437361 ---> -<head> - <title>Test for Bug 437361</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - - <script class="testbody" type="text/javascript"> - - /** Test for Bug 437361 **/ - - function testModalDialogBlockedCleanly() { - is(true, SpecialPowers.getBoolPref("dom.disable_open_during_load"), "mozprefs sanity check"); - var rv = window.showModalDialog( // should be blocked without exception - "data:text/html,<html><body onload='close(); returnValue = 1;' /></html>"); - is(rv, null, "Modal dialog opened unexpectedly."); - } - - function testModalDialogAllowed() { - is(false, SpecialPowers.getBoolPref("dom.disable_open_during_load"), "mozprefs sanity check"); - var rv = window.showModalDialog( // should not be blocked this time - "data:text/html,<html><body onload='close(); returnValue = 1;' /></html>"); - is(rv, 1, "Problem with modal dialog returnValue."); - } - - function testOtherExceptionsNotTrapped() { - is(false, SpecialPowers.getBoolPref("dom.disable_open_during_load"), "mozprefs sanity check"); - window.showModalDialog('about:config'); // forbidden by SecurityCheckURL - } - - function test(disableOpen, exceptionExpected, testFn, errorMsg) { - if ("showModalDialog" in window) { - var oldPrefVal = SpecialPowers.getBoolPref("dom.disable_open_during_load"); - try { - SpecialPowers.setBoolPref("dom.disable_open_during_load", disableOpen); - testFn(); - ok(!exceptionExpected, errorMsg); - } catch (_) { - ok(exceptionExpected, errorMsg); - } - finally { - SpecialPowers.setBoolPref("dom.disable_open_during_load", oldPrefVal); - } - } else { - ok(true, "nothing to do in e10s mode"); - } - } - - test(true, false, testModalDialogBlockedCleanly, - "Blocked showModalDialog caused an exception."); - - test(false, false, testModalDialogAllowed, - "showModalDialog was blocked even though dom.disable_open_during_load was false."); - - test(false, true, testOtherExceptionsNotTrapped, - "Incorrectly suppressed insecure showModalDialog exception."); - - </script> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=437361">Mozilla Bug 437361</a> -<p id="display"></p> -<div id="content" style="display: none"> -</div> -<pre id="test"> -</pre> -</body> -</html> - diff --git a/dom/tests/mochitest/bugs/test_bug479143.html b/dom/tests/mochitest/bugs/test_bug479143.html deleted file mode 100644 index 03db4ddea..000000000 --- a/dom/tests/mochitest/bugs/test_bug479143.html +++ /dev/null @@ -1,44 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=479143 ---> -<head> - <title>Test for Bug 411103</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479143">Mozilla Bug 479143</a> -<p id="display"></p> -<div id="content" style="display: none"></div> - -<pre id="test"> -<script class="testbody" type="text/javascript"> - - SimpleTest.waitForExplicitFinish(); - - setTimeout(function() { - if ("showModalDialog" in window) { - var interval = setInterval(function() { var i = 0; i++; }, 10); - - var xhr = new XMLHttpRequest(); - xhr.open("GET", "test_bug479143.html", false); - xhr.send(null); - - window.showModalDialog("javascript:" + - "setTimeout(function() { window.close(); }, 1000);", - null); - - clearInterval(interval); - } - - ok(true, "did not crash"); - - SimpleTest.finish(); - }, 0); - -</script> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/bugs/test_bug504862.html b/dom/tests/mochitest/bugs/test_bug504862.html deleted file mode 100644 index 713165bc3..000000000 --- a/dom/tests/mochitest/bugs/test_bug504862.html +++ /dev/null @@ -1,45 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=504862 ---> -<head> - <title>Test for Bug 504862</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body onload="runTest()"> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=504862">Mozilla Bug 504862</a> -<script class="testbody" type="text/javascript"> - -/** Test for Bug 504862 **/ -SimpleTest.waitForExplicitFinish(); -function onMsgRcv(event) -{ - is(event.data, "args: undefined", "Unexpected cross origin dialog arguments."); -} - -function runTest() { - if ("showModalDialog" in window) { - window.addEventListener("message", onMsgRcv, false); - - var result = window.showModalDialog("file_bug504862.html", "my args"); - // NB: We used to clear returnValue on each navigation, but now we do a - // security check on access, so we can safely make returnValue live on - // the browsing context, per spec. - is(result, 3, "window sees previous dialog documents return value."); - - result = window.showModalDialog("http://test1.example.com/tests/dom/tests/mochitest/bugs/file_bug504862.html", "my args"); - - is(result, undefined, "Able to see return value from cross origin dialog."); - } else { - ok(true, "nothing to do in e10s mode"); - } - - SimpleTest.finish(); -} - -</script> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/bugs/test_bug61098.html b/dom/tests/mochitest/bugs/test_bug61098.html index 4c6ce967d..ed16e099b 100644 --- a/dom/tests/mochitest/bugs/test_bug61098.html +++ b/dom/tests/mochitest/bugs/test_bug61098.html @@ -306,28 +306,6 @@ function runtestsInner() w.close(); - // Test that showModalDialog() works normally and then gets blocked - // on the second call. - if (window.showModalDialog) { - w = window.open(); - w.showModalDialog("data:text/html,%3Cscript>window.close();%3C/script>") - is (promptState, void(0), "Wrong prompt state"); - - try { - w.showModalDialog("data:text/html,%3Cscript>window.close();%3C/script>") - ok(false, "showModalDialog call should throw an exception"); - } catch(e) { - is(e.name, "NS_ERROR_NOT_AVAILABLE", "Wrong exception"); - } - is (promptState.method, "confirm", "Wrong prompt method called"); - is (promptState.parent, w, "Wrong confirm parent"); - is (promptState.msg, "Prevent this page from creating additional dialogs", - "Wrong confirm message"); - promptState = void(0); - - w.close(); - } - mockPromptFactoryRegisterer.unregister(); mockPromptServiceRegisterer.unregister(); diff --git a/dom/tests/mochitest/bugs/test_bug735237.html b/dom/tests/mochitest/bugs/test_bug735237.html deleted file mode 100644 index e1a25a425..000000000 --- a/dom/tests/mochitest/bugs/test_bug735237.html +++ /dev/null @@ -1,38 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=735237 ---> -<head> - <title>Test for Bug 735237</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=735237">Mozilla Bug 735237</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -/** Test for Bug 735237 **/ - -SimpleTest.waitForExplicitFinish(); - -SpecialPowers.pushPrefEnv({"set": [["dom.disable_window_showModalDialog", true]]}, function() { - var caughtException = false; - try { - window.showModalDialog("http://example.com/"); - } catch (e) { - caughtException = true; - } - ok(caughtException, "showModalDialog should throw an exception"); - SimpleTest.finish(); -}); - -</script> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/general/file_showModalDialog.html b/dom/tests/mochitest/general/file_showModalDialog.html deleted file mode 100644 index 1cae0b1c0..000000000 --- a/dom/tests/mochitest/general/file_showModalDialog.html +++ /dev/null @@ -1,35 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script> - function go() { - is(SpecialPowers.wrap(window).location.toString(), location.toString(), "sanity"); - ok("returnValue" in window && "dialogArguments" in window, "We are modal"); - var iwin = document.getElementById('ifr').contentWindow; - is(SpecialPowers.Cu.getClassName(iwin, /* aUnwrap = */ true), "Window", "Descendant frames should not be modal"); - - if (location.origin != "http://mochi.test:8888") { - is(window.dialogArguments, undefined, - "dialogArguments should be undefined cross-origin: " + location.origin); - } - - window.returnValue = "rv: " + window.dialogArguments; - - // Allow for testing navigations in series. - if (location.search == "") { - window.close(); - } else { - var origins = location.search.split('?')[1].split(','); - var newsearch = '?' + origins.splice(1).join(','); - var newurl = location.toString().replace(location.origin, origins[0]) - .replace(location.search, newsearch); - location = newurl; - } - - } -</script> -</head> -<body onload="opener.postMessage('dosetup', '*');"> -<iframe id="ifr"></iframe> -</body> -</html> diff --git a/dom/tests/mochitest/general/mochitest.ini b/dom/tests/mochitest/general/mochitest.ini index d00ea1d4b..9f2fad785 100755 --- a/dom/tests/mochitest/general/mochitest.ini +++ b/dom/tests/mochitest/general/mochitest.ini @@ -9,7 +9,6 @@ support-files = file_interfaces.xml file_moving_nodeList.html file_moving_xhr.html - file_showModalDialog.html historyframes.html image_50.png image_100.png @@ -116,8 +115,6 @@ support-files = test_offsets.js [test_resource_timing_frameset.html] [test_selectevents.html] skip-if = toolkit == 'android' # bug 1230232 - Mouse doesn't select in the same way -[test_showModalDialog.html] -skip-if = e10s || toolkit == 'android' #Don't run modal tests on Android [test_showModalDialog_e10s.html] run-if = e10s [test_storagePermissionsAccept.html] diff --git a/dom/tests/mochitest/general/test_showModalDialog.html b/dom/tests/mochitest/general/test_showModalDialog.html deleted file mode 100644 index 511c79e63..000000000 --- a/dom/tests/mochitest/general/test_showModalDialog.html +++ /dev/null @@ -1,60 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=862918 ---> -<head> - <meta charset="utf-8"> - <title>Test for Bug 862918</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - <script type="application/javascript"> - - /** Test for window.showModalDialog. **/ - - // The modal window needs to touch Cu, which means that it needs - // SpecialPowers. But given the semantics of modal windows, we have to - // do some funny stuff with postMessage to set this up. - window.onmessage = function(evt) { - is(evt.data, 'dosetup', "message from modal window is correct"); - var win = SpecialPowers.wrap(evt.source); - win.wrappedJSObject.SpecialPowers = SpecialPowers; - SpecialPowers.setWrapped(win.wrappedJSObject, 'is', SpecialPowers.wrap(is)); - SpecialPowers.setWrapped(win.wrappedJSObject, 'ok', SpecialPowers.wrap(ok)); - win.wrappedJSObject.go(); - }; - - var someObj = { foo: 42, bar: "hi"}; - var xurl = location.toString() - .replace('mochi.test:8888', 'example.org') - .replace('test_showModal', 'file_showModal'); - if (xurl.indexOf('?') != -1) - xurl = xurl.substring(0, xurl.indexOf('?')); - is(showModalDialog('file_showModalDialog.html'), "rv: undefined"); - is(showModalDialog(xurl), undefined); - is(showModalDialog('file_showModalDialog.html', 3), "rv: 3"); - is(showModalDialog(xurl, 3), undefined); - is(showModalDialog('file_showModalDialog.html', someObj), "rv: " + someObj); - is(showModalDialog(xurl, someObj), undefined); - - // Test sequential navigations. - is(showModalDialog('file_showModalDialog.html?http://mochi.test:8888', 4), - 'rv: 4'); - is(showModalDialog('file_showModalDialog.html?http://example.com', 4), undefined); - is(showModalDialog('file_showModalDialog.html?http://example.com,http://mochi.test:8888', 4), 'rv: 4'); - - // This test used to assert after gc. Make sure it doesn't. - SpecialPowers.gc(); - - </script> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=862918">Mozilla Bug 862918</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/webcomponents/chrome.ini b/dom/tests/mochitest/webcomponents/chrome.ini new file mode 100644 index 000000000..5e25c2123 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/chrome.ini @@ -0,0 +1,9 @@ +[DEFAULT] +support-files = + dummy_page.html + +[test_custom_element_htmlconstructor_chrome.html] +skip-if = os == 'android' # bug 1323645 +support-files = + htmlconstructor_autonomous_tests.js + htmlconstructor_builtin_tests.js diff --git a/dom/tests/mochitest/webcomponents/dummy_page.html b/dom/tests/mochitest/webcomponents/dummy_page.html new file mode 100644 index 000000000..fd238954c --- /dev/null +++ b/dom/tests/mochitest/webcomponents/dummy_page.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<title>Dummy test page</title> +<meta charset="utf-8"/> +</head> +<body> +<p>Dummy test page</p> +</body> +</html> diff --git a/dom/tests/mochitest/webcomponents/htmlconstructor_autonomous_tests.js b/dom/tests/mochitest/webcomponents/htmlconstructor_autonomous_tests.js new file mode 100644 index 000000000..636d9aff6 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/htmlconstructor_autonomous_tests.js @@ -0,0 +1,81 @@ +promises.push(test_with_new_window((testWindow) => { + // Test calling the HTMLElement constructor. + (() => { + SimpleTest.doesThrow(() => { + testWindow.HTMLElement(); + }, 'calling the HTMLElement constructor should throw a TypeError'); + })(); + + // Test constructing a HTMLELement. + (() => { + SimpleTest.doesThrow(() => { + new testWindow.HTMLElement(); + }, 'constructing a HTMLElement should throw a TypeError'); + })(); + + // Test constructing a custom element with defining HTMLElement as entry. + (() => { + testWindow.customElements.define('x-defining-html-element', + testWindow.HTMLElement); + SimpleTest.doesThrow(() => { + new testWindow.HTMLElement(); + }, 'constructing a custom element with defining HTMLElement as registry ' + + 'entry should throw a TypeError'); + })(); + + // Test calling a custom element constructor and constructing an autonomous + // custom element. + (() => { + let num_constructor_invocations = 0; + class X extends testWindow.HTMLElement { + constructor() { + super(); + num_constructor_invocations++; + } + } + testWindow.customElements.define('x-element', X); + SimpleTest.doesThrow(() => { + X(); + }, 'calling an autonomous custom element constructor should throw a TypeError'); + + let element = new X(); + SimpleTest.is(Object.getPrototypeOf(Cu.waiveXrays(element)), X.prototype, + 'constructing an autonomous custom element; ' + + 'the element should be a registered constructor'); + SimpleTest.is(element.localName, 'x-element', + 'constructing an autonomous custom element; ' + + 'the element tag name should be "x-element"'); + SimpleTest.is(element.namespaceURI, 'http://www.w3.org/1999/xhtml', + 'constructing an autonomous custom element; ' + + 'the element should be in the HTML namespace'); + SimpleTest.is(element.prefix, null, + 'constructing an autonomous custom element; ' + + 'the element name should not have a prefix'); + SimpleTest.is(element.ownerDocument, testWindow.document, + 'constructing an autonomous custom element; ' + + 'the element should be owned by the registry\'s associated ' + + 'document'); + SimpleTest.is(num_constructor_invocations, 1, + 'constructing an autonomous custom element; ' + + 'the constructor should have been invoked once'); + })(); + + // Test if prototype is no an object. + (() => { + function ElementWithNonObjectPrototype() { + let o = Reflect.construct(testWindow.HTMLElement, [], new.target); + SimpleTest.is(Object.getPrototypeOf(Cu.waiveXrays(o)), window.HTMLElement.prototype, + 'constructing an autonomous custom element; ' + + 'if prototype is not object, fallback from NewTarget\'s realm'); + } + + // Prototype have to be an object during define(), otherwise define will + // throw an TypeError exception. + ElementWithNonObjectPrototype.prototype = {}; + testWindow.customElements.define('x-non-object-prototype', + ElementWithNonObjectPrototype); + + ElementWithNonObjectPrototype.prototype = "string"; + new ElementWithNonObjectPrototype(); + })(); +})); diff --git a/dom/tests/mochitest/webcomponents/htmlconstructor_builtin_tests.js b/dom/tests/mochitest/webcomponents/htmlconstructor_builtin_tests.js new file mode 100644 index 000000000..dd6515148 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/htmlconstructor_builtin_tests.js @@ -0,0 +1,247 @@ +[ + // [TagName, InterfaceName] + ['a', 'Anchor'], + ['abbr', ''], + ['acronym', ''], + ['address', ''], + ['area', 'Area'], + ['article', ''], + ['aside', ''], + ['audio', 'Audio'], + ['b', ''], + ['base', 'Base'], + ['basefont', ''], + ['bdo', ''], + ['big', ''], + ['blockquote', 'Quote'], + ['body', 'Body'], + ['br', 'BR'], + ['button', 'Button'], + ['canvas', 'Canvas'], + ['caption', 'TableCaption'], + ['center', ''], + ['cite', ''], + ['code', ''], + ['col', 'TableCol'], + ['colgroup', 'TableCol'], + ['data', 'Data'], + ['datalist', 'DataList'], + ['dd', ''], + ['del', 'Mod'], + ['details', 'Details'], + ['dfn', ''], + ['dir', 'Directory'], + ['div', 'Div'], + ['dl', 'DList'], + ['dt', ''], + ['em', ''], + ['embed', 'Embed'], + ['fieldset', 'FieldSet'], + ['figcaption', ''], + ['figure', ''], + ['font', 'Font'], + ['footer', ''], + ['form', 'Form'], + ['frame', 'Frame'], + ['frameset', 'FrameSet'], + ['h1', 'Heading'], + ['h2', 'Heading'], + ['h3', 'Heading'], + ['h4', 'Heading'], + ['h5', 'Heading'], + ['h6', 'Heading'], + ['head', 'Head'], + ['header', ''], + ['hgroup', ''], + ['hr', 'HR'], + ['html', 'Html'], + ['i', ''], + ['iframe', 'IFrame'], + ['image', ''], + ['img', 'Image'], + ['input', 'Input'], + ['ins', 'Mod'], + ['kbd', ''], + ['label', 'Label'], + ['legend', 'Legend'], + ['li', 'LI'], + ['link', 'Link'], + ['listing', 'Pre'], + ['main', ''], + ['map', 'Map'], + ['mark', ''], + ['marquee', 'Div'], + ['menu', 'Menu'], + ['menuitem', 'MenuItem'], + ['meta', 'Meta'], + ['meter', 'Meter'], + ['nav', ''], + ['nobr', ''], + ['noembed', ''], + ['noframes', ''], + ['noscript', ''], + ['object', 'Object'], + ['ol', 'OList'], + ['optgroup', 'OptGroup'], + ['option', 'Option'], + ['output', 'Output'], + ['p', 'Paragraph'], + ['param', 'Param'], + ['picture', 'Picture'], + ['plaintext', ''], + ['pre', 'Pre'], + ['progress', 'Progress'], + ['q', 'Quote'], + ['rb', ''], + ['rp', ''], + ['rt', ''], + ['rtc', ''], + ['ruby', ''], + ['s', ''], + ['samp', ''], + ['script', 'Script'], + ['section', ''], + ['select', 'Select'], + ['small', ''], + ['source', 'Source'], + ['span', 'Span'], + ['strike', ''], + ['strong', ''], + ['style', 'Style'], + ['sub', ''], + ['summary', ''], + ['sup', ''], + ['table', 'Table'], + ['tbody', 'TableSection'], + ['td', 'TableCell'], + ['textarea', 'TextArea'], + ['tfoot', 'TableSection'], + ['th', 'TableCell'], + ['thead', 'TableSection'], + ['template', 'Template'], + ['time', 'Time'], + ['title', 'Title'], + ['tr', 'TableRow'], + ['track', 'Track'], + ['tt', ''], + ['u', ''], + ['ul', 'UList'], + ['var', ''], + ['video', 'Video'], + ['wbr', ''], + ['xmp', 'Pre'], +].forEach((e) => { + let tagName = e[0]; + let interfaceName = 'HTML' + e[1] + 'Element'; + promises.push(test_with_new_window((testWindow) => { + // Use window from iframe to isolate the test. + // Test calling the HTML*Element constructor. + (() => { + SimpleTest.doesThrow(() => { + testWindow[interfaceName](); + }, 'calling the ' + interfaceName + ' constructor should throw a TypeError'); + })(); + + // Test constructing a HTML*ELement. + (() => { + SimpleTest.doesThrow(() => { + new testWindow[interfaceName](); + }, 'constructing a ' + interfaceName + ' should throw a TypeError'); + })(); + + // Test constructing a custom element with defining HTML*Element as entry. + (() => { + testWindow.customElements.define('x-defining-' + tagName, + testWindow[interfaceName]); + SimpleTest.doesThrow(() => { + new testWindow[interfaceName](); + }, 'constructing a custom element with defining ' + interfaceName + + ' as registry entry should throw a TypeError'); + })(); + + // Since HTMLElement can be registered without specifying "extends", skip + // testing HTMLElement tags. + if (interfaceName !== "HTMLElement") { + // Test constructing a customized HTML*Element with defining a registry entry + // without specifying "extends". + (() => { + class X extends testWindow[interfaceName] {} + testWindow.customElements.define('x-defining-invalid-' + tagName, X); + SimpleTest.doesThrow(() => { + new X(); + }, 'constructing a customized ' + interfaceName + ' with defining a ' + + 'registry entry without specifying "extends" should throw a TypeError'); + })(); + } + + // Test constructing a built-in custom element with defining a registry entry + // with incorrect "extends" information. + (() => { + class X extends testWindow[interfaceName] {} + testWindow.customElements.define('x-defining-incorrect-' + tagName, X, + { extends: tagName === 'img' ? 'p' : 'img' }); + SimpleTest.doesThrow(() => { + new X(); + }, 'constructing a customized ' + interfaceName + ' with defining a ' + + 'registry entry with incorrect "extends" should throw a TypeError'); + })(); + + // Test calling a custom element constructor and constructing a built-in + // custom element. + (() => { + let num_constructor_invocations = 0; + class X extends testWindow[interfaceName] { + constructor() { + super(); + num_constructor_invocations++; + } + } + testWindow.customElements.define('x-' + tagName, X, { extends: tagName }); + SimpleTest.doesThrow(() => { + X(); + }, 'calling a customized ' + interfaceName + ' constructor should throw a TypeError'); + + let element = new X(); + + SimpleTest.is(Object.getPrototypeOf(Cu.waiveXrays(element)), X.prototype, + 'constructing a customized ' + interfaceName + + '; the element should be a registered constructor'); + SimpleTest.is(element.localName, tagName, + 'constructing a customized ' + interfaceName + + '; the element tag name should be "' + tagName + '"'); + SimpleTest.is(element.namespaceURI, 'http://www.w3.org/1999/xhtml', + 'constructing a customized ' + interfaceName + + '; the element should be in the HTML namespace'); + SimpleTest.is(element.prefix, null, + 'constructing a customized ' + interfaceName + + '; the element name should not have a prefix'); + SimpleTest.is(element.ownerDocument, testWindow.document, + 'constructing a customized ' + interfaceName + + '; the element should be owned by the registry\'s associated ' + + 'document'); + SimpleTest.is(num_constructor_invocations, 1, + 'constructing a customized ' + interfaceName + + '; the constructor should have been invoked once'); + })(); + + // Test if prototype is no an object. + (() => { + function ElementWithNonObjectPrototype() { + let o = Reflect.construct(testWindow[interfaceName], [], new.target); + SimpleTest.is(Object.getPrototypeOf(Cu.waiveXrays(o)), window[interfaceName].prototype, + 'constructing a customized ' + interfaceName + + '; if prototype is not object, fallback from NewTarget\'s realm'); + } + + // Prototype have to be an object during define(), otherwise define will + // throw an TypeError exception. + ElementWithNonObjectPrototype.prototype = {}; + testWindow.customElements.define('x-non-object-prototype-' + tagName, + ElementWithNonObjectPrototype, + { extends: tagName }); + + ElementWithNonObjectPrototype.prototype = "string"; + new ElementWithNonObjectPrototype(); + })(); + })); +}); diff --git a/dom/tests/mochitest/webcomponents/mochitest.ini b/dom/tests/mochitest/webcomponents/mochitest.ini index 496f7ea4d..f5d0f84ea 100644 --- a/dom/tests/mochitest/webcomponents/mochitest.ini +++ b/dom/tests/mochitest/webcomponents/mochitest.ini @@ -1,21 +1,28 @@ [DEFAULT] support-files = inert_style.css + dummy_page.html [test_bug900724.html] [test_bug1017896.html] [test_bug1176757.html] [test_bug1276240.html] [test_content_element.html] -[test_custom_element_adopt_callbacks.html] [test_custom_element_callback_innerhtml.html] -[test_custom_element_clone_callbacks.html] -[test_custom_element_clone_callbacks_extended.html] -[test_custom_element_import_node_created_callback.html] +skip-if = true # disabled - See bug 1390396 +[test_custom_element_htmlconstructor.html] +skip-if = os == 'android' # bug 1323645 +support-files = + htmlconstructor_autonomous_tests.js + htmlconstructor_builtin_tests.js [test_custom_element_in_shadow.html] +skip-if = true || stylo # disabled - See bug 1390396 and 1293844 [test_custom_element_register_invalid_callbacks.html] +[test_custom_element_throw_on_dynamic_markup_insertion.html] [test_custom_element_get.html] [test_custom_element_when_defined.html] +[test_custom_element_uncatchable_exception.html] +skip-if = !debug # TestFunctions only applied in debug builds [test_nested_content_element.html] [test_dest_insertion_points.html] [test_dest_insertion_points_shadow.html] @@ -25,10 +32,11 @@ support-files = [test_document_adoptnode.html] [test_document_importnode.html] [test_document_register.html] -[test_document_register_base_queue.html] [test_document_register_lifecycle.html] +skip-if = true # disabled - See bug 1390396 [test_document_register_parser.html] [test_document_register_stack.html] +skip-if = true # disabled - See bug 1390396 [test_document_shared_registry.html] [test_event_dispatch.html] [test_event_retarget.html] diff --git a/dom/tests/mochitest/webcomponents/test_bug1276240.html b/dom/tests/mochitest/webcomponents/test_bug1276240.html index 33e532a6a..ded8d8276 100644 --- a/dom/tests/mochitest/webcomponents/test_bug1276240.html +++ b/dom/tests/mochitest/webcomponents/test_bug1276240.html @@ -47,7 +47,7 @@ test(); // test with webcomponents disabled SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv( - { 'set': [["dom.webcomponents.enabled", false]]}, runTest); + { 'set': [["dom.webcomponents.customelements.enabled", false]]}, runTest); </script> </pre> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_adopt_callbacks.html b/dom/tests/mochitest/webcomponents/test_custom_element_adopt_callbacks.html deleted file mode 100644 index 28597b7c6..000000000 --- a/dom/tests/mochitest/webcomponents/test_custom_element_adopt_callbacks.html +++ /dev/null @@ -1,29 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1081039 ---> -<head> - <title>Test callbacks for adopted custom elements.</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<template id="template"><x-foo></x-foo></template> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a> -<script> - -var p = Object.create(HTMLElement.prototype); -p.createdCallback = function() { - ok(false, "Created callback should not be called for adopted node."); -}; - -document.registerElement("x-foo", { prototype: p }); - -var template = document.getElementById("template"); -var adoptedFoo = document.adoptNode(template.content.firstChild); -is(adoptedFoo.nodeName, "X-FOO"); - -</script> -</body> -</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html b/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html index 94b02032f..bb5008538 100644 --- a/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html +++ b/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html @@ -16,7 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1102502 SimpleTest.waitForExplicitFinish(); -var attachedCallbackCount = 0; +var connectedCallbackCount = 0; var p = Object.create(HTMLElement.prototype); @@ -24,12 +24,12 @@ p.createdCallback = function() { ok(true, "createdCallback called."); }; -p.attachedCallback = function() { - ok(true, "attachedCallback should be called when the parser creates an element in the document."); - attachedCallbackCount++; - // attachedCallback should be called twice, once for the element created for innerHTML and +p.connectedCallback = function() { + ok(true, "connectedCallback should be called when the parser creates an element in the document."); + connectedCallbackCount++; + // connectedCallback should be called twice, once for the element created for innerHTML and // once for the element created in this document. - if (attachedCallbackCount == 2) { + if (connectedCallbackCount == 2) { SimpleTest.finish(); } } diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks.html b/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks.html deleted file mode 100644 index eea9bafe0..000000000 --- a/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks.html +++ /dev/null @@ -1,54 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1081039 ---> -<head> - <title>Test callbacks for cloned custom elements.</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a> -<script> - -SimpleTest.waitForExplicitFinish(); - -// Test to make sure created callback is called on clones that are upgraded and clones -// created after registering the custom element. - -var callbackCalledOnUpgrade = false; -var callbackCalledOnClone = false; - -var foo = document.createElement("x-foo"); -var fooClone = foo.cloneNode(true); - -var p = Object.create(HTMLElement.prototype); -p.createdCallback = function() { - is(this.__proto__, p, "Correct prototype should be set on custom elements."); - - if (this == fooClone) { - // Callback called for the element created before registering the custom element. - // Should be called on element upgrade. - is(callbackCalledOnUpgrade, false, "Upgrade should only be called once per clone."); - callbackCalledOnUpgrade = true; - } else if (this != foo) { - // Callback called for the element created after registering the custom element. - is(callbackCalledOnClone, false, "Upgrade should only be called once per clone."); - callbackCalledOnClone = true; - } - - if (callbackCalledOnUpgrade && callbackCalledOnClone) { - SimpleTest.finish(); - } -}; - -document.registerElement("x-foo", { prototype: p }); - -var anotherFooClone = foo.cloneNode(true); - -SimpleTest.waitForExplicitFinish(); - -</script> -</body> -</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks_extended.html b/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks_extended.html deleted file mode 100644 index b3531b0ea..000000000 --- a/dom/tests/mochitest/webcomponents/test_custom_element_clone_callbacks_extended.html +++ /dev/null @@ -1,40 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1081039 ---> -<head> - <title>Test callbacks for cloned extended custom elements.</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a> -<script> - -SimpleTest.waitForExplicitFinish(); - -// Test to make sure created callback is called on clones created after -// registering the custom element. - -var count = 0; -var p = Object.create(HTMLButtonElement.prototype); -p.createdCallback = function() { // should be called by createElement and cloneNode - is(this.__proto__, p, "Correct prototype should be set on custom elements."); - - if (++count == 2) { - SimpleTest.finish(); - } -}; - -document.registerElement("x-foo", { prototype: p, extends: "button" }); -var foo = document.createElement("button", {is: "x-foo"}); -is(foo.getAttribute("is"), "x-foo"); - -var fooClone = foo.cloneNode(true); - -SimpleTest.waitForExplicitFinish(); - -</script> -</body> -</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor.html b/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor.html new file mode 100644 index 000000000..b022a7887 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1274159 +--> +<head> + <title>Test HTMLConstructor for custom elements.</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1274159">Bug 1274159</a> +<script type="text/javascript"> +function test_with_new_window(f) { + return new Promise((aResolve) => { + let iframe = document.createElement('iframe'); + iframe.setAttribute('type', 'content'); + iframe.setAttribute('src', 'dummy_page.html'); + iframe.onload = function() { + f(iframe.contentWindow); + aResolve(); + }; + document.body.appendChild(iframe); + }); +} + +// Fake the Cu.waiveXrays, so that we can share the tests with mochitest chrome. +var Cu = { waiveXrays: (obj) => obj }; +var promises = []; +SimpleTest.waitForExplicitFinish(); +</script> +<!-- Test cases for autonomous element --> +<script type="text/javascript" src="htmlconstructor_autonomous_tests.js"></script> +<!-- Test cases for customized built-in element --> +<script type="text/javascript" src="htmlconstructor_builtin_tests.js"></script> +<script type="text/javascript"> +Promise.all(promises).then(() => { + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html b/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html new file mode 100644 index 000000000..8c7ec0ac6 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/test_custom_element_htmlconstructor_chrome.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1274159 +--> +<head> + <title>Test HTMLConstructor for custom elements.</title> + <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1274159">Bug 1274159</a> +<script type="text/javascript"> +function test_with_new_window(f) { + return new Promise((aResolve) => { + let iframe = document.createElement('iframe'); + iframe.setAttribute('type', 'content'); + iframe.setAttribute('src', 'http://example.org/tests/dom/tests/mochitest/webcomponents/dummy_page.html'); + iframe.onload = function() { + f(iframe.contentWindow); + aResolve(); + }; + document.body.appendChild(iframe); + }); +} + +var Cu = Components.utils; +var promises = []; +SimpleTest.waitForExplicitFinish(); +</script> +<!-- Test cases for autonomous element --> +<script type="text/javascript" src="htmlconstructor_autonomous_tests.js"></script> +<!-- Test cases for customized built-in element --> +<script type="text/javascript" src="htmlconstructor_builtin_tests.js"></script> +<script type="text/javascript"> +Promise.all(promises).then(() => { + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_import_node_created_callback.html b/dom/tests/mochitest/webcomponents/test_custom_element_import_node_created_callback.html deleted file mode 100644 index f533b507c..000000000 --- a/dom/tests/mochitest/webcomponents/test_custom_element_import_node_created_callback.html +++ /dev/null @@ -1,34 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1093680 ---> -<head> - <title>Test created callback order for imported custom element.</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<template id="template"><x-foo><span></span></x-foo></template> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1093680">Bug 1093680</a> -<script> - -var fooProtoCreatedCallbackCalled = false; -var fooProto = Object.create(HTMLElement.prototype); -fooProto.createdCallback = function() { - ok(this.firstElementChild, "When the created callback is called, the element should already have a child because the callback should only be called after cloning all the contents."); - fooProtoCreatedCallbackCalled = true; -}; - -document.registerElement("x-foo", { prototype: fooProto }); - -var template = document.getElementById("template"); - -// Importing node will implicityly clone the conent in the main document. -var adoptedFoo = document.importNode(template.content, true); - -ok(fooProtoCreatedCallbackCalled, "Created callback should be called after importing custom element into document"); - -</script> -</body> -</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html b/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html index a349f4aa5..572579ba8 100644 --- a/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html +++ b/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html @@ -19,9 +19,6 @@ const testWindow = iframe.contentDocument.defaultView; // This is for backward compatibility. // We should do the same checks for the callbacks from v0 spec. [ - 'createdCallback', - 'attachedCallback', - 'detachedCallback', 'attributeChangedCallback', ].forEach(callback => { var c = class {}; diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_throw_on_dynamic_markup_insertion.html b/dom/tests/mochitest/webcomponents/test_custom_element_throw_on_dynamic_markup_insertion.html new file mode 100644 index 000000000..b5ef66860 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/test_custom_element_throw_on_dynamic_markup_insertion.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1378079 +--> +<head> + <title>Test throw on dynamic markup insertion when creating element synchronously from parser</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1378079">Bug 1378079</a> +<div id="container"></div> + +<script> + +class DoDocumentOpenInCtor extends HTMLElement { + constructor() { + super(); + document.open(); + } +}; +customElements.define('x-document-open-in-ctor', DoDocumentOpenInCtor); + +class DoDocumentWriteInCtor extends HTMLElement { + constructor() { + super(); + document.write('<div>This should not be shown</div>'); + } +}; +customElements.define('x-document-write-in-ctor', DoDocumentWriteInCtor); + +class DoDocumentCloseInCtor extends HTMLElement { + constructor() { + super(); + document.close(); + } +}; +customElements.define('x-document-close-in-ctor', DoDocumentCloseInCtor); + +window.errors = []; +window.onerror = function(message, url, lineNumber, columnNumber, error) { + errors.push(error.name); + return true; +} +var expectedErrorCount = 0; + +document.write("<x-document-open-in-ctor></x-document-open-in-ctor>"); +expectedErrorCount++; +is(window.errors.length, expectedErrorCount, "expectedErrorCount should be " + expectedErrorCount); +is(window.errors[expectedErrorCount - 1], 'InvalidStateError', "Error name should be 'InvalidStateError'"); + +document.write("<x-document-write-in-ctor></x-document-write-in-ctor>"); +expectedErrorCount++; +is(window.errors.length, expectedErrorCount, "expectedErrorCount should be " + expectedErrorCount); +is(window.errors[expectedErrorCount - 1], 'InvalidStateError', "Error name should be 'InvalidStateError'"); + +document.write("<x-document-close-in-ctor></x-document-close-in-ctor>"); +expectedErrorCount++; +is(window.errors.length, expectedErrorCount, "expectedErrorCount should be " + expectedErrorCount); +is(window.errors[expectedErrorCount - 1], 'InvalidStateError', "Error name should be 'InvalidStateError'"); + +</script> + +</body> +</html> diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_uncatchable_exception.html b/dom/tests/mochitest/webcomponents/test_custom_element_uncatchable_exception.html new file mode 100644 index 000000000..f60bf1674 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/test_custom_element_uncatchable_exception.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1407669 +--> +<head> + <title>Test custom elements runtime exception</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1407669">Bug 1407669</a> +<script type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() { + window.onerror = function (e) { + ok(false, "How did we get here!?"); + } + + class Foo extends HTMLElement { + constructor() { + super() + TestFunctions.throwUncatchableException(); + } + } + + customElements.define("test-custom-element", Foo); + let element = document.createElement("test-custom-element"); + is(element instanceof HTMLUnknownElement, true, "It should be a HTMLUnknownElement when uncatchable exception throws in constructor"); + ok(true, "Uncatchable exception should not report"); + SimpleTest.finish(); +}); + +</script> +</body> +</html> diff --git a/dom/tests/mochitest/webcomponents/test_document_register.html b/dom/tests/mochitest/webcomponents/test_document_register.html index a9c194b60..aa80fef5f 100644 --- a/dom/tests/mochitest/webcomponents/test_document_register.html +++ b/dom/tests/mochitest/webcomponents/test_document_register.html @@ -103,52 +103,12 @@ function startTest() { is(extendedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type."); is(extendedButton.type, "submit", "Created element should be a button with type of \"submit\""); - // document.createElementNS with different namespace than definition. - try { - var svgButton = document.createElementNS("http://www.w3.org/2000/svg", "button", {is: "x-extended-button"}); - ok(false, "An exception should've been thrown"); - } catch(err) { - is(err.name, "NotFoundError", "A NotFoundError exception should've been thrown"); - } - - // document.createElementNS with no namespace. - try { - var noNamespaceButton = document.createElementNS("", "button", {is: "x-extended-button"}); - ok(false, "An exception should've been thrown"); - } catch(err) { - is(err.name, "NotFoundError", "A NotFoundError exception should've been thrown"); - } - - // document.createElement with non-existant extended type. - try { - var normalButton = document.createElement("button", {is: "x-non-existant"}); - ok(false, "An exception should've been thrown"); - } catch(err) { - is(err.name, "NotFoundError", "A NotFoundError exception should've been thrown"); - } - - // document.createElement with exteneded type that does not match with local name of element. - try { - var normalDiv = document.createElement("div", {is: "x-extended-button"}); - ok(false, "An exception should've been thrown"); - } catch(err) { - is(err.name, "NotFoundError", "A NotFoundError exception should've been thrown"); - } - // Custom element constructor. var constructedButton = new buttonConstructor(); is(constructedButton.tagName, "BUTTON", "Created element should have local name of BUTTON"); is(constructedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type."); is(constructedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type."); - // document.createElement with different namespace than definition for extended element. - try { - var htmlText = document.createElement("text", {is: "x-extended-text"}); - ok(false, "An exception should've been thrown"); - } catch(err) { - is(err.name, "NotFoundError", "A NotFoundError exception should've been thrown"); - } - // Try creating an element with a custom element name, but not in the html namespace. var htmlNamespaceProto = Object.create(HTMLElement.prototype); document.registerElement("x-in-html-namespace", { prototype: htmlNamespaceProto }); diff --git a/dom/tests/mochitest/webcomponents/test_document_register_base_queue.html b/dom/tests/mochitest/webcomponents/test_document_register_base_queue.html deleted file mode 100644 index c839857b4..000000000 --- a/dom/tests/mochitest/webcomponents/test_document_register_base_queue.html +++ /dev/null @@ -1,48 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=783129 ---> -<head> - <title>Test for document.registerElement lifecycle callback</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> -<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -<script> -var p = Object.create(HTMLElement.prototype); - -var createdCallbackCallCount = 0; - -// By the time the base element queue is processed via the microtask, -// both x-hello elements should be in the document. -p.createdCallback = function() { - var one = document.getElementById("one"); - var two = document.getElementById("two"); - isnot(one, null, "First x-hello element should be in the tree."); - isnot(two, null, "Second x-hello element should be in the tree."); - createdCallbackCallCount++; - if (createdCallbackCallCount == 2) { - SimpleTest.finish(); - } - - if (createdCallbackCallCount > 2) { - ok(false, "Created callback called too much."); - } -}; - -p.attributeChangedCallback = function(name, oldValue, newValue) { - ok(false, "Attribute changed callback should not be called because callbacks should not be queued until created callback invoked."); -}; - -document.registerElement("x-hello", { prototype: p }); - -SimpleTest.waitForExplicitFinish(); -</script> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a> -<x-hello id="one"></x-hello> -<x-hello id="two"></x-hello> -<script> -</script> -</body> -</html> diff --git a/dom/tests/mochitest/webcomponents/test_document_register_parser.html b/dom/tests/mochitest/webcomponents/test_document_register_parser.html index bc4cdcbac..a4fb63139 100644 --- a/dom/tests/mochitest/webcomponents/test_document_register_parser.html +++ b/dom/tests/mochitest/webcomponents/test_document_register_parser.html @@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783129 var extendedButtonProto = Object.create(HTMLButtonElement.prototype); var buttonCallbackCalled = false; -extendedButtonProto.createdCallback = function() { +extendedButtonProto.connectedCallback = function() { is(buttonCallbackCalled, false, "created callback for x-button should only be called once."); is(this.tagName, "BUTTON", "Only the <button> element should be upgraded."); buttonCallbackCalled = true; @@ -21,7 +21,7 @@ document.registerElement("x-button", { prototype: extendedButtonProto, extends: var divProto = Object.create(HTMLDivElement.prototype); var divCallbackCalled = false; -divProto.createdCallback = function() { +divProto.connectedCallback = function() { is(divCallbackCalled, false, "created callback for x-div should only be called once."); is(buttonCallbackCalled, true, "crated callback should be called for x-button before x-div."); is(this.tagName, "X-DIV", "Only the <x-div> element should be upgraded."); diff --git a/dom/tests/mochitest/webcomponents/test_document_register_stack.html b/dom/tests/mochitest/webcomponents/test_document_register_stack.html index 34f108654..b1c61af11 100644 --- a/dom/tests/mochitest/webcomponents/test_document_register_stack.html +++ b/dom/tests/mochitest/webcomponents/test_document_register_stack.html @@ -28,7 +28,8 @@ function testChangeAttributeInCreatedCallback() { createdCallbackCalled = true; is(attributeChangedCallbackCalled, false, "Attribute changed callback should not have been called prior to setting the attribute."); this.setAttribute("foo", "bar"); - is(attributeChangedCallbackCalled, false, "While element is being created, element should not be added to the current element callback queue."); + is(attributeChangedCallbackCalled, true, "While element is being created, element should be added to the current element callback queue."); + runNextTest(); }; p.attributeChangedCallback = function(name, oldValue, newValue) { @@ -36,7 +37,6 @@ function testChangeAttributeInCreatedCallback() { is(attributeChangedCallbackCalled, false, "attributeChanged callback should only be called once in this tests."); is(newValue, "bar", "The new value should be 'bar'"); attributeChangedCallbackCalled = true; - runNextTest(); }; document.registerElement("x-one", { prototype: p }); diff --git a/dom/tests/mochitest/webcomponents/test_document_shared_registry.html b/dom/tests/mochitest/webcomponents/test_document_shared_registry.html index 76c2ea8ec..db72e1e6c 100644 --- a/dom/tests/mochitest/webcomponents/test_document_shared_registry.html +++ b/dom/tests/mochitest/webcomponents/test_document_shared_registry.html @@ -14,37 +14,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783129 <script> var container = document.getElementById("container"); -function createdCallbackFromMainDoc() { - var createdCallbackCalled = false; - var assocDoc = document.implementation.createHTMLDocument(); - - var proto = Object.create(HTMLElement.prototype); - proto.createdCallback = function() { - is(createdCallbackCalled, false, "created callback should only be called once in this tests."); - createdCallbackCalled = true; - runNextTest(); - }; - - assocDoc.registerElement("x-associated-doc-callback-elem", { prototype: proto }); - document.createElement("x-associated-doc-callback-elem"); -} - -function createdCallbackFromDocHTMLNamespace() { - var createdCallbackCalled = false; - var assocDoc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", null); - var somediv = assocDoc.createElement("div"); - - var proto = Object.create(HTMLElement.prototype); - proto.createdCallback = function() { - is(createdCallbackCalled, false, "created callback should only be called once in this tests."); - createdCallbackCalled = true; - runNextTest(); - }; - - assocDoc.registerElement("x-assoc-doc-with-ns-callback-elem", { prototype: proto }); - document.createElement("x-assoc-doc-with-ns-callback-elem"); -} - function registerNoRegistryDoc() { var assocDoc = document.implementation.createDocument(null, "html"); try { @@ -65,8 +34,6 @@ function runNextTest() { } var testFunctions = [ - createdCallbackFromMainDoc, - createdCallbackFromDocHTMLNamespace, registerNoRegistryDoc, SimpleTest.finish ]; diff --git a/dom/tests/moz.build b/dom/tests/moz.build index f7c3e2437..7fc81abbd 100644 --- a/dom/tests/moz.build +++ b/dom/tests/moz.build @@ -37,6 +37,7 @@ MOCHITEST_CHROME_MANIFESTS += [ 'mochitest/geolocation/chrome.ini', 'mochitest/localstorage/chrome.ini', 'mochitest/sessionstorage/chrome.ini', + 'mochitest/webcomponents/chrome.ini', 'mochitest/whatwg/chrome.ini', ] diff --git a/dom/webidl/Attr.webidl b/dom/webidl/Attr.webidl index c836afd9b..763ed02ef 100644 --- a/dom/webidl/Attr.webidl +++ b/dom/webidl/Attr.webidl @@ -12,7 +12,7 @@ interface Attr : Node { readonly attribute DOMString localName; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString value; [Constant] diff --git a/dom/webidl/CSSStyleDeclaration.webidl b/dom/webidl/CSSStyleDeclaration.webidl index d9b2511de..561e5cce1 100644 --- a/dom/webidl/CSSStyleDeclaration.webidl +++ b/dom/webidl/CSSStyleDeclaration.webidl @@ -10,7 +10,7 @@ interface CSSRule; interface CSSStyleDeclaration { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString cssText; readonly attribute unsigned long length; @@ -22,9 +22,9 @@ interface CSSStyleDeclaration { [Throws] CSSValue? getPropertyCSSValue(DOMString property); DOMString getPropertyPriority(DOMString property); - [Throws] + [CEReactions, Throws] void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = ""); - [Throws] + [CEReactions, Throws] DOMString removeProperty(DOMString property); readonly attribute CSSRule? parentRule; diff --git a/dom/webidl/ChildNode.webidl b/dom/webidl/ChildNode.webidl index fcf388059..ae36cd93e 100644 --- a/dom/webidl/ChildNode.webidl +++ b/dom/webidl/ChildNode.webidl @@ -9,13 +9,13 @@ [NoInterfaceObject] interface ChildNode { - [Throws, Unscopable] + [CEReactions, Throws, Unscopable] void before((Node or DOMString)... nodes); - [Throws, Unscopable] + [CEReactions, Throws, Unscopable] void after((Node or DOMString)... nodes); - [Throws, Unscopable] + [CEReactions, Throws, Unscopable] void replaceWith((Node or DOMString)... nodes); - [Unscopable] + [CEReactions, Unscopable] void remove(); }; diff --git a/dom/webidl/CustomElementRegistry.webidl b/dom/webidl/CustomElementRegistry.webidl index dff612174..788b6a4ed 100644 --- a/dom/webidl/CustomElementRegistry.webidl +++ b/dom/webidl/CustomElementRegistry.webidl @@ -5,7 +5,7 @@ // https://html.spec.whatwg.org/#dom-window-customelements [Func="CustomElementRegistry::IsCustomElementEnabled"] interface CustomElementRegistry { - [Throws] + [CEReactions, Throws] void define(DOMString name, Function functionConstructor, optional ElementDefinitionOptions options); any get(DOMString name); diff --git a/dom/webidl/DOMStringMap.webidl b/dom/webidl/DOMStringMap.webidl index 0ed98e148..a59910e0b 100644 --- a/dom/webidl/DOMStringMap.webidl +++ b/dom/webidl/DOMStringMap.webidl @@ -14,7 +14,8 @@ [OverrideBuiltins] interface DOMStringMap { getter DOMString (DOMString name); - [Throws] + [CEReactions, Throws] setter creator void (DOMString name, DOMString value); + [CEReactions] deleter void (DOMString name); }; diff --git a/dom/webidl/DOMTokenList.webidl b/dom/webidl/DOMTokenList.webidl index a1ea243b3..69663d055 100644 --- a/dom/webidl/DOMTokenList.webidl +++ b/dom/webidl/DOMTokenList.webidl @@ -14,17 +14,17 @@ interface DOMTokenList { readonly attribute unsigned long length; getter DOMString? item(unsigned long index); boolean contains(DOMString token); - [Throws] + [CEReactions, Throws] void add(DOMString... tokens); - [Throws] + [CEReactions, Throws] void remove(DOMString... tokens); - [Throws] + [CEReactions, Throws] void replace(DOMString token, DOMString newToken); - [Throws] + [CEReactions, Throws] boolean toggle(DOMString token, optional boolean force); - [Throws] + [CEReactions, Throws] boolean supports(DOMString token); - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString value; stringifier DOMString (); iterable<DOMString?>; diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index 904b1fb77..b28903ae2 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -65,9 +65,9 @@ interface Document : Node { [NewObject, Throws] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - [Throws] + [CEReactions, Throws] Node importNode(Node node, optional boolean deep = false); - [Throws] + [CEReactions, Throws] Node adoptNode(Node node); [NewObject, Throws] @@ -108,9 +108,9 @@ partial interface Document { // DOM tree accessors //(Not proxy yet)getter object (DOMString name); - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString title; - [Pure] + [CEReactions, Pure] attribute DOMString dir; //(HTML only) attribute HTMLElement? body; //(HTML only)readonly attribute HTMLHeadElement? head; diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl index cf17523a5..a6b2bfdd5 100644 --- a/dom/webidl/Element.webidl +++ b/dom/webidl/Element.webidl @@ -25,9 +25,9 @@ interface Element : Node { [Pure] readonly attribute DOMString tagName; - [Pure] + [CEReactions, Pure] attribute DOMString id; - [Pure] + [CEReactions, Pure] attribute DOMString className; [Constant, PutForwards=value] readonly attribute DOMTokenList classList; @@ -40,15 +40,15 @@ interface Element : Node { DOMString? getAttribute(DOMString name); [Pure] DOMString? getAttributeNS(DOMString? namespace, DOMString localName); - [Throws] + [CEReactions, Throws] boolean toggleAttribute(DOMString name, optional boolean force); - [Throws] + [CEReactions, Throws] void setAttribute(DOMString name, DOMString value); - [Throws] + [CEReactions, Throws] void setAttributeNS(DOMString? namespace, DOMString name, DOMString value); - [Throws] + [CEReactions, Throws] void removeAttribute(DOMString name); - [Throws] + [CEReactions, Throws] void removeAttributeNS(DOMString? namespace, DOMString localName); [Pure] boolean hasAttribute(DOMString name); @@ -72,7 +72,7 @@ interface Element : Node { [Pure] HTMLCollection getElementsByClassName(DOMString classNames); - [Throws, Pure] + [CEReactions, Throws, Pure] Element? insertAdjacentElement(DOMString where, Element element); // historical [Throws] @@ -137,12 +137,12 @@ interface Element : Node { // Obsolete methods. Attr? getAttributeNode(DOMString name); - [Throws] + [CEReactions, Throws] Attr? setAttributeNode(Attr newAttr); - [Throws] + [CEReactions, Throws] Attr? removeAttributeNode(Attr oldAttr); Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName); - [Throws] + [CEReactions, Throws] Attr? setAttributeNodeNS(Attr newAttr); [ChromeOnly] @@ -212,11 +212,11 @@ partial interface Element { // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface partial interface Element { - [Pure,SetterThrows,TreatNullAs=EmptyString] + [CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString] attribute DOMString innerHTML; - [Pure,SetterThrows,TreatNullAs=EmptyString] + [CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString] attribute DOMString outerHTML; - [Throws] + [CEReactions, Throws] void insertAdjacentHTML(DOMString position, DOMString text); }; diff --git a/dom/webidl/EventHandler.webidl b/dom/webidl/EventHandler.webidl index b92e3a2bb..484a8e95c 100644 --- a/dom/webidl/EventHandler.webidl +++ b/dom/webidl/EventHandler.webidl @@ -94,7 +94,6 @@ interface GlobalEventHandlers { [Pref="dom.select_events.enabled"] attribute EventHandler onselectstart; - [Pref="dom.details_element.enabled"] attribute EventHandler ontoggle; // Pointer events handlers diff --git a/dom/webidl/HTMLAnchorElement.webidl b/dom/webidl/HTMLAnchorElement.webidl index 0b8ded6d7..0326dff6a 100644 --- a/dom/webidl/HTMLAnchorElement.webidl +++ b/dom/webidl/HTMLAnchorElement.webidl @@ -12,25 +12,26 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-a-element +[HTMLConstructor] interface HTMLAnchorElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString target; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString download; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString ping; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString rel; - [SetterThrows, Pref="network.http.enablePerElementReferrer"] + [CEReactions, SetterThrows, Pref="network.http.enablePerElementReferrer"] attribute DOMString referrerPolicy; [PutForwards=value] readonly attribute DOMTokenList relList; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString hreflang; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString text; }; @@ -38,14 +39,14 @@ HTMLAnchorElement implements HTMLHyperlinkElementUtils; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLAnchorElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString coords; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString charset; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString name; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString rev; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString shape; }; diff --git a/dom/webidl/HTMLAreaElement.webidl b/dom/webidl/HTMLAreaElement.webidl index be3f37885..0980d178a 100644 --- a/dom/webidl/HTMLAreaElement.webidl +++ b/dom/webidl/HTMLAreaElement.webidl @@ -13,20 +13,21 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-area-element +[HTMLConstructor] interface HTMLAreaElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString alt; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString coords; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString shape; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString target; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString download; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString ping; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString rel; [SetterThrows, Pref="network.http.enablePerElementReferrer"] attribute DOMString referrerPolicy; @@ -38,6 +39,6 @@ HTMLAreaElement implements HTMLHyperlinkElementUtils; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLAreaElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean noHref; }; diff --git a/dom/webidl/HTMLAudioElement.webidl b/dom/webidl/HTMLAudioElement.webidl index 8537453c0..725669839 100644 --- a/dom/webidl/HTMLAudioElement.webidl +++ b/dom/webidl/HTMLAudioElement.webidl @@ -11,6 +11,6 @@ * and create derivative works of this document. */ -[NamedConstructor=Audio(optional DOMString src)] +[HTMLConstructor, NamedConstructor=Audio(optional DOMString src)] interface HTMLAudioElement : HTMLMediaElement {}; diff --git a/dom/webidl/HTMLBRElement.webidl b/dom/webidl/HTMLBRElement.webidl index cf5cb8a67..b0b0f80ed 100644 --- a/dom/webidl/HTMLBRElement.webidl +++ b/dom/webidl/HTMLBRElement.webidl @@ -13,11 +13,12 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-br-element +[HTMLConstructor] interface HTMLBRElement : HTMLElement {}; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLBRElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString clear; }; diff --git a/dom/webidl/HTMLBaseElement.webidl b/dom/webidl/HTMLBaseElement.webidl index d982f4654..ed86f8c77 100644 --- a/dom/webidl/HTMLBaseElement.webidl +++ b/dom/webidl/HTMLBaseElement.webidl @@ -12,10 +12,11 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-base-element +[HTMLConstructor] interface HTMLBaseElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString href; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString target; }; diff --git a/dom/webidl/HTMLBodyElement.webidl b/dom/webidl/HTMLBodyElement.webidl index 95df2d43a..f89c287d7 100644 --- a/dom/webidl/HTMLBodyElement.webidl +++ b/dom/webidl/HTMLBodyElement.webidl @@ -11,16 +11,23 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLBodyElement : HTMLElement { }; partial interface HTMLBodyElement { - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString text; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString link; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString vLink; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString aLink; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString bgColor; - [SetterThrows] attribute DOMString background; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString text; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString link; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString vLink; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString aLink; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString bgColor; + [CEReactions, SetterThrows] + attribute DOMString background; }; HTMLBodyElement implements WindowEventHandlers; diff --git a/dom/webidl/HTMLButtonElement.webidl b/dom/webidl/HTMLButtonElement.webidl index 579efa39c..f129dbd7b 100644 --- a/dom/webidl/HTMLButtonElement.webidl +++ b/dom/webidl/HTMLButtonElement.webidl @@ -11,28 +11,29 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-button-element +[HTMLConstructor] interface HTMLButtonElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean autofocus; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean disabled; [Pure] readonly attribute HTMLFormElement? form; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString formAction; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString formEnctype; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString formMethod; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean formNoValidate; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString formTarget; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString type; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString value; // Not yet implemented: // attribute HTMLMenuElement? menu; diff --git a/dom/webidl/HTMLCanvasElement.webidl b/dom/webidl/HTMLCanvasElement.webidl index 15e94f154..b567c69eb 100644 --- a/dom/webidl/HTMLCanvasElement.webidl +++ b/dom/webidl/HTMLCanvasElement.webidl @@ -13,10 +13,11 @@ interface nsISupports; interface Variant; +[HTMLConstructor] interface HTMLCanvasElement : HTMLElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute unsigned long width; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute unsigned long height; [Throws] diff --git a/dom/webidl/HTMLDListElement.webidl b/dom/webidl/HTMLDListElement.webidl index 08020a497..4cf1c2183 100644 --- a/dom/webidl/HTMLDListElement.webidl +++ b/dom/webidl/HTMLDListElement.webidl @@ -13,11 +13,12 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-dl-element +[HTMLConstructor] interface HTMLDListElement : HTMLElement { }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLDListElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean compact; }; diff --git a/dom/webidl/HTMLDataElement.webidl b/dom/webidl/HTMLDataElement.webidl index 821b8b483..d24537871 100644 --- a/dom/webidl/HTMLDataElement.webidl +++ b/dom/webidl/HTMLDataElement.webidl @@ -7,7 +7,8 @@ * http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-data-element */ +[HTMLConstructor] interface HTMLDataElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString value; }; diff --git a/dom/webidl/HTMLDataListElement.webidl b/dom/webidl/HTMLDataListElement.webidl index 83b20cd2b..4c38fddf3 100644 --- a/dom/webidl/HTMLDataListElement.webidl +++ b/dom/webidl/HTMLDataListElement.webidl @@ -11,6 +11,7 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLDataListElement : HTMLElement { readonly attribute HTMLCollection options; }; diff --git a/dom/webidl/HTMLDetailsElement.webidl b/dom/webidl/HTMLDetailsElement.webidl index 133ecf125..04df82e30 100644 --- a/dom/webidl/HTMLDetailsElement.webidl +++ b/dom/webidl/HTMLDetailsElement.webidl @@ -11,8 +11,8 @@ * and create derivative works of this document. */ -[Pref="dom.details_element.enabled"] +[HTMLConstructor] interface HTMLDetailsElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean open; }; diff --git a/dom/webidl/HTMLDialogElement.webidl b/dom/webidl/HTMLDialogElement.webidl index b6cdbacf6..563740c87 100644 --- a/dom/webidl/HTMLDialogElement.webidl +++ b/dom/webidl/HTMLDialogElement.webidl @@ -13,11 +13,13 @@ [Pref="dom.dialog_element.enabled"] interface HTMLDialogElement : HTMLElement { - [SetterThrows] attribute boolean open; + [CEReactions, SetterThrows] + attribute boolean open; attribute DOMString returnValue; - + [CEReactions] void show(); - [Throws] void showModal(); - + [CEReactions, Throws] + void showModal(); + [CEReactions] void close(optional DOMString returnValue); }; diff --git a/dom/webidl/HTMLDirectoryElement.webidl b/dom/webidl/HTMLDirectoryElement.webidl index 9d5160af1..65becbb60 100644 --- a/dom/webidl/HTMLDirectoryElement.webidl +++ b/dom/webidl/HTMLDirectoryElement.webidl @@ -12,8 +12,9 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis +[HTMLConstructor] interface HTMLDirectoryElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean compact; }; diff --git a/dom/webidl/HTMLDivElement.webidl b/dom/webidl/HTMLDivElement.webidl index f50e2aad0..2b762c6fa 100644 --- a/dom/webidl/HTMLDivElement.webidl +++ b/dom/webidl/HTMLDivElement.webidl @@ -11,9 +11,10 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLDivElement : HTMLElement {}; partial interface HTMLDivElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; }; diff --git a/dom/webidl/HTMLDocument.webidl b/dom/webidl/HTMLDocument.webidl index ffb61ccdd..ffa38d97d 100644 --- a/dom/webidl/HTMLDocument.webidl +++ b/dom/webidl/HTMLDocument.webidl @@ -13,7 +13,7 @@ interface HTMLDocument : Document { // DOM tree accessors [Throws] getter object (DOMString name); - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute HTMLElement? body; [Pure] readonly attribute HTMLHeadElement? head; @@ -32,20 +32,20 @@ interface HTMLDocument : Document { NodeList getElementsByName(DOMString elementName); // dynamic markup insertion - [Throws] + [CEReactions, Throws] Document open(optional DOMString type = "text/html", optional DOMString replace = ""); - [Throws] + [CEReactions, Throws] WindowProxy? open(DOMString url, DOMString name, DOMString features, optional boolean replace = false); - [Throws] + [CEReactions, Throws] void close(); - [Throws] + [CEReactions, Throws] void write(DOMString... text); - [Throws] + [CEReactions, Throws] void writeln(DOMString... text); - [SetterThrows, NeedsSubjectPrincipal] + [CEReactions, SetterThrows, NeedsSubjectPrincipal] attribute DOMString designMode; - [Throws] + [CEReactions, Throws] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = ""); [Throws] @@ -58,11 +58,11 @@ interface HTMLDocument : Document { [Throws] DOMString queryCommandValue(DOMString commandId); - [TreatNullAs=EmptyString] attribute DOMString fgColor; - [TreatNullAs=EmptyString] attribute DOMString linkColor; - [TreatNullAs=EmptyString] attribute DOMString vlinkColor; - [TreatNullAs=EmptyString] attribute DOMString alinkColor; - [TreatNullAs=EmptyString] attribute DOMString bgColor; + [CEReactions, TreatNullAs=EmptyString] attribute DOMString fgColor; + [CEReactions, TreatNullAs=EmptyString] attribute DOMString linkColor; + [CEReactions, TreatNullAs=EmptyString] attribute DOMString vlinkColor; + [CEReactions, TreatNullAs=EmptyString] attribute DOMString alinkColor; + [CEReactions, TreatNullAs=EmptyString] attribute DOMString bgColor; [Pure] readonly attribute HTMLCollection anchors; diff --git a/dom/webidl/HTMLElement.webidl b/dom/webidl/HTMLElement.webidl index 5ce5024e6..815f4a3bd 100644 --- a/dom/webidl/HTMLElement.webidl +++ b/dom/webidl/HTMLElement.webidl @@ -12,34 +12,37 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLElement : Element { // metadata attributes + [CEReactions] attribute DOMString title; + [CEReactions] attribute DOMString lang; // attribute boolean translate; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString dir; [Constant] readonly attribute DOMStringMap dataset; - [GetterThrows, Pure, TreatNullAs=EmptyString] + [CEReactions, GetterThrows, Pure, TreatNullAs=EmptyString] attribute DOMString innerText; // user interaction - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean hidden; void click(); - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute long tabIndex; [Throws] void focus(); [Throws] void blur(); - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString accessKey; [Pure] readonly attribute DOMString accessKeyLabel; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean draggable; //[PutForwards=value] readonly attribute DOMTokenList dropzone; [SetterThrows, Pure] @@ -50,7 +53,7 @@ interface HTMLElement : Element { readonly attribute HTMLMenuElement? contextMenu; //[SetterThrows] // attribute HTMLMenuElement? contextMenu; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean spellcheck; // command API diff --git a/dom/webidl/HTMLEmbedElement.webidl b/dom/webidl/HTMLEmbedElement.webidl index 36668595b..9c5361221 100644 --- a/dom/webidl/HTMLEmbedElement.webidl +++ b/dom/webidl/HTMLEmbedElement.webidl @@ -13,15 +13,15 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-embed-element -[NeedResolve] +[HTMLConstructor, NeedResolve] interface HTMLEmbedElement : HTMLElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString src; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString type; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString width; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString height; [Throws] legacycaller any (any... arguments); @@ -29,9 +29,9 @@ interface HTMLEmbedElement : HTMLElement { // http://www.whatwg.org/specs/web-apps/current-work/#HTMLEmbedElement-partial partial interface HTMLEmbedElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString align; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString name; }; diff --git a/dom/webidl/HTMLFieldSetElement.webidl b/dom/webidl/HTMLFieldSetElement.webidl index 6c9eee52b..63393bf42 100644 --- a/dom/webidl/HTMLFieldSetElement.webidl +++ b/dom/webidl/HTMLFieldSetElement.webidl @@ -11,11 +11,12 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLFieldSetElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean disabled; readonly attribute HTMLFormElement? form; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString name; readonly attribute DOMString type; diff --git a/dom/webidl/HTMLFontElement.webidl b/dom/webidl/HTMLFontElement.webidl index 781dabb88..8db6d3246 100644 --- a/dom/webidl/HTMLFontElement.webidl +++ b/dom/webidl/HTMLFontElement.webidl @@ -11,8 +11,9 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLFontElement : HTMLElement { - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString color; - [SetterThrows] attribute DOMString face; - [SetterThrows] attribute DOMString size; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] attribute DOMString color; + [CEReactions, SetterThrows] attribute DOMString face; + [CEReactions, SetterThrows] attribute DOMString size; }; diff --git a/dom/webidl/HTMLFormElement.webidl b/dom/webidl/HTMLFormElement.webidl index 8d248e1a5..064fe9fad 100644 --- a/dom/webidl/HTMLFormElement.webidl +++ b/dom/webidl/HTMLFormElement.webidl @@ -11,25 +11,25 @@ * and create derivative works of this document. */ -[OverrideBuiltins, LegacyUnenumerableNamedProperties] +[OverrideBuiltins, LegacyUnenumerableNamedProperties, HTMLConstructor] interface HTMLFormElement : HTMLElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString acceptCharset; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString action; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString autocomplete; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString enctype; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString encoding; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString method; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString name; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean noValidate; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString target; [Constant] @@ -43,6 +43,7 @@ interface HTMLFormElement : HTMLElement { [Throws] void submit(); + [CEReactions] void reset(); boolean checkValidity(); boolean reportValidity(); diff --git a/dom/webidl/HTMLFrameElement.webidl b/dom/webidl/HTMLFrameElement.webidl index 9c5aca7c4..c3ba0de63 100644 --- a/dom/webidl/HTMLFrameElement.webidl +++ b/dom/webidl/HTMLFrameElement.webidl @@ -11,25 +11,28 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#htmlframeelement +[HTMLConstructor] interface HTMLFrameElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString name; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString scrolling; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString src; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString frameBorder; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString longDesc; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean noResize; [NeedsSubjectPrincipal] readonly attribute Document? contentDocument; readonly attribute WindowProxy? contentWindow; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString marginHeight; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString marginWidth; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString marginHeight; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString marginWidth; }; HTMLFrameElement implements MozFrameLoaderOwner; diff --git a/dom/webidl/HTMLFrameSetElement.webidl b/dom/webidl/HTMLFrameSetElement.webidl index ce00d487f..afc4465d1 100644 --- a/dom/webidl/HTMLFrameSetElement.webidl +++ b/dom/webidl/HTMLFrameSetElement.webidl @@ -11,10 +11,11 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLFrameSetElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString cols; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString rows; }; diff --git a/dom/webidl/HTMLHRElement.webidl b/dom/webidl/HTMLHRElement.webidl index 0495e43b3..24ba3112a 100644 --- a/dom/webidl/HTMLHRElement.webidl +++ b/dom/webidl/HTMLHRElement.webidl @@ -12,19 +12,20 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-hr-element +[HTMLConstructor] interface HTMLHRElement : HTMLElement { }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLHRElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString color; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean noShade; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString size; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString width; }; diff --git a/dom/webidl/HTMLHeadElement.webidl b/dom/webidl/HTMLHeadElement.webidl index 0ad45e384..b649712a6 100644 --- a/dom/webidl/HTMLHeadElement.webidl +++ b/dom/webidl/HTMLHeadElement.webidl @@ -12,5 +12,6 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-head-element +[HTMLConstructor] interface HTMLHeadElement : HTMLElement {}; diff --git a/dom/webidl/HTMLHeadingElement.webidl b/dom/webidl/HTMLHeadingElement.webidl index c07e5cb99..a39e24cfb 100644 --- a/dom/webidl/HTMLHeadingElement.webidl +++ b/dom/webidl/HTMLHeadingElement.webidl @@ -12,11 +12,12 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements +[HTMLConstructor] interface HTMLHeadingElement : HTMLElement { }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLHeadingElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; }; diff --git a/dom/webidl/HTMLHtmlElement.webidl b/dom/webidl/HTMLHtmlElement.webidl index b06de7761..5b2a9a926 100644 --- a/dom/webidl/HTMLHtmlElement.webidl +++ b/dom/webidl/HTMLHtmlElement.webidl @@ -13,10 +13,11 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-html-element +[HTMLConstructor] interface HTMLHtmlElement : HTMLElement {}; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLHtmlElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString version; }; diff --git a/dom/webidl/HTMLHyperlinkElementUtils.webidl b/dom/webidl/HTMLHyperlinkElementUtils.webidl index 25f175db9..ae53fd75e 100644 --- a/dom/webidl/HTMLHyperlinkElementUtils.webidl +++ b/dom/webidl/HTMLHyperlinkElementUtils.webidl @@ -18,17 +18,26 @@ interface HTMLHyperlinkElementUtils { // Bug 824857 should remove this. stringifier; - [SetterThrows] + [CEReactions, SetterThrows] attribute USVString href; readonly attribute USVString origin; + [CEReactions] attribute USVString protocol; + [CEReactions] attribute USVString username; + [CEReactions] attribute USVString password; + [CEReactions] attribute USVString host; + [CEReactions] attribute USVString hostname; + [CEReactions] attribute USVString port; + [CEReactions] attribute USVString pathname; + [CEReactions] attribute USVString search; + [CEReactions] attribute USVString hash; }; diff --git a/dom/webidl/HTMLIFrameElement.webidl b/dom/webidl/HTMLIFrameElement.webidl index 0a1b49aff..d2859c6db 100644 --- a/dom/webidl/HTMLIFrameElement.webidl +++ b/dom/webidl/HTMLIFrameElement.webidl @@ -11,22 +11,23 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLIFrameElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString src; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString srcdoc; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; [PutForwards=value] readonly attribute DOMTokenList sandbox; // attribute boolean seamless; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean allowFullscreen; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString width; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString height; - [SetterThrows, Pure, Pref="network.http.enablePerElementReferrer"] + [CEReactions, SetterThrows, Pure, Pref="network.http.enablePerElementReferrer"] attribute DOMString referrerPolicy; [NeedsSubjectPrincipal] readonly attribute Document? contentDocument; @@ -35,17 +36,19 @@ interface HTMLIFrameElement : HTMLElement { // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLIFrameElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString align; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString scrolling; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString frameBorder; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString longDesc; - [TreatNullAs=EmptyString,SetterThrows,Pure] attribute DOMString marginHeight; - [TreatNullAs=EmptyString,SetterThrows,Pure] attribute DOMString marginWidth; + [CEReactions, TreatNullAs=EmptyString, SetterThrows, Pure] + attribute DOMString marginHeight; + [CEReactions, TreatNullAs=EmptyString, SetterThrows, Pure] + attribute DOMString marginWidth; }; partial interface HTMLIFrameElement { diff --git a/dom/webidl/HTMLImageElement.webidl b/dom/webidl/HTMLImageElement.webidl index 243c65509..e50a9ef8e 100644 --- a/dom/webidl/HTMLImageElement.webidl +++ b/dom/webidl/HTMLImageElement.webidl @@ -16,25 +16,26 @@ interface imgIRequest; interface URI; interface nsIStreamListener; -[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)] +[HTMLConstructor, + NamedConstructor=Image(optional unsigned long width, optional unsigned long height)] interface HTMLImageElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString alt; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString src; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString srcset; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString? crossOrigin; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString useMap; - [SetterThrows, Pref="network.http.enablePerElementReferrer"] + [CEReactions, SetterThrows, Pref="network.http.enablePerElementReferrer"] attribute DOMString referrerPolicy; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean isMap; - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long width; - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long height; readonly attribute unsigned long naturalWidth; readonly attribute unsigned long naturalHeight; @@ -43,30 +44,31 @@ interface HTMLImageElement : HTMLElement { // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLImageElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString name; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long hspace; - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long vspace; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString longDesc; - [TreatNullAs=EmptyString,SetterThrows] attribute DOMString border; + [CEReactions, TreatNullAs=EmptyString,SetterThrows] attribute DOMString border; }; // [Update me: not in whatwg spec yet] // http://picture.responsiveimages.org/#the-img-element partial interface HTMLImageElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString sizes; readonly attribute DOMString currentSrc; }; // Mozilla extensions. partial interface HTMLImageElement { + [CEReactions] attribute DOMString lowsrc; // These attributes are offsets from the closest view (to mimic diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl index cf3e9a4c7..93ad90f45 100644 --- a/dom/webidl/HTMLInputElement.webidl +++ b/dom/webidl/HTMLInputElement.webidl @@ -21,79 +21,81 @@ enum SelectionMode { interface nsIControllers; +[HTMLConstructor] interface HTMLInputElement : HTMLElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString accept; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString alt; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString autocomplete; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean autofocus; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean defaultChecked; [Pure] attribute boolean checked; // Bug 850337 - attribute DOMString dirName; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean disabled; readonly attribute HTMLFormElement? form; [Pure] readonly attribute FileList? files; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString formAction; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString formEnctype; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString formMethod; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean formNoValidate; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString formTarget; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute unsigned long height; [Pure] attribute boolean indeterminate; - [Pure, SetterThrows, Pref="dom.forms.inputmode"] + [CEReactions, Pure, SetterThrows, Pref="dom.forms.inputmode"] attribute DOMString inputMode; [Pure] readonly attribute HTMLElement? list; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString max; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute long maxLength; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString min; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute long minLength; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean multiple; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString name; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString pattern; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString placeholder; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean readOnly; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean required; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute unsigned long size; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString src; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString step; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString type; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString defaultValue; - [Pure, TreatNullAs=EmptyString, Throws] + [CEReactions, Pure, TreatNullAs=EmptyString, Throws] attribute DOMString value; [Throws, Func="HTMLInputElement::ValueAsDateEnabled"] attribute Date? valueAsDate; [Pure, SetterThrows] attribute unrestricted double valueAsNumber; + [CEReactions] attribute unsigned long width; [Throws] @@ -132,9 +134,9 @@ interface HTMLInputElement : HTMLElement { }; partial interface HTMLInputElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString align; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString useMap; }; diff --git a/dom/webidl/HTMLLIElement.webidl b/dom/webidl/HTMLLIElement.webidl index c20e00846..3f104d09e 100644 --- a/dom/webidl/HTMLLIElement.webidl +++ b/dom/webidl/HTMLLIElement.webidl @@ -13,13 +13,14 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-li-element +[HTMLConstructor] interface HTMLLIElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute long value; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLLIElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString type; }; diff --git a/dom/webidl/HTMLLabelElement.webidl b/dom/webidl/HTMLLabelElement.webidl index f44a56219..4b624dfaf 100644 --- a/dom/webidl/HTMLLabelElement.webidl +++ b/dom/webidl/HTMLLabelElement.webidl @@ -11,8 +11,10 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLLabelElement : HTMLElement { readonly attribute HTMLFormElement? form; + [CEReactions] attribute DOMString htmlFor; readonly attribute HTMLElement? control; }; diff --git a/dom/webidl/HTMLLegendElement.webidl b/dom/webidl/HTMLLegendElement.webidl index 0ce4ae88b..6f03ecf1b 100644 --- a/dom/webidl/HTMLLegendElement.webidl +++ b/dom/webidl/HTMLLegendElement.webidl @@ -13,12 +13,13 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-legend-element +[HTMLConstructor] interface HTMLLegendElement : HTMLElement { readonly attribute HTMLFormElement? form; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLLegendElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; }; diff --git a/dom/webidl/HTMLLinkElement.webidl b/dom/webidl/HTMLLinkElement.webidl index ec094e55e..eb83deab1 100644 --- a/dom/webidl/HTMLLinkElement.webidl +++ b/dom/webidl/HTMLLinkElement.webidl @@ -12,24 +12,25 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-link-element +[HTMLConstructor] interface HTMLLinkElement : HTMLElement { [Pure] attribute boolean disabled; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString href; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString? crossOrigin; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString rel; [PutForwards=value] readonly attribute DOMTokenList relList; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString media; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString hreflang; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString type; - [SetterThrows, Pure, Pref="network.http.enablePerElementReferrer"] + [CEReactions, SetterThrows, Pure, Pref="network.http.enablePerElementReferrer"] attribute DOMString referrerPolicy; [PutForwards=value] readonly attribute DOMTokenList sizes; }; @@ -37,11 +38,11 @@ HTMLLinkElement implements LinkStyle; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLLinkElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString charset; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString rev; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString target; }; @@ -53,6 +54,6 @@ partial interface HTMLLinkElement { // https://w3c.github.io/webappsec/specs/subresourceintegrity/#htmllinkelement-1 partial interface HTMLLinkElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString integrity; }; diff --git a/dom/webidl/HTMLMapElement.webidl b/dom/webidl/HTMLMapElement.webidl index 88fe4e54c..199c70876 100644 --- a/dom/webidl/HTMLMapElement.webidl +++ b/dom/webidl/HTMLMapElement.webidl @@ -11,8 +11,9 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-map-element +[HTMLConstructor] interface HTMLMapElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; [Constant] readonly attribute HTMLCollection areas; diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl index be79d8679..ad31f38cb 100644 --- a/dom/webidl/HTMLMediaElement.webidl +++ b/dom/webidl/HTMLMediaElement.webidl @@ -17,18 +17,18 @@ interface HTMLMediaElement : HTMLElement { readonly attribute MediaError? error; // network state - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString src; readonly attribute DOMString currentSrc; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString? crossOrigin; const unsigned short NETWORK_EMPTY = 0; const unsigned short NETWORK_IDLE = 1; const unsigned short NETWORK_LOADING = 2; const unsigned short NETWORK_NO_SOURCE = 3; readonly attribute unsigned short networkState; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString preload; [NewObject] readonly attribute TimeRanges buffered; @@ -63,9 +63,9 @@ interface HTMLMediaElement : HTMLElement { [NewObject] readonly attribute TimeRanges seekable; readonly attribute boolean ended; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean autoplay; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean loop; [Throws] Promise<void> play(); @@ -78,12 +78,12 @@ interface HTMLMediaElement : HTMLElement { // attribute MediaController? controller; // controls - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean controls; [SetterThrows] attribute double volume; attribute boolean muted; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean defaultMuted; // TODO: Bug 847379 diff --git a/dom/webidl/HTMLMenuElement.webidl b/dom/webidl/HTMLMenuElement.webidl index ff81a7c80..1194226c5 100644 --- a/dom/webidl/HTMLMenuElement.webidl +++ b/dom/webidl/HTMLMenuElement.webidl @@ -15,16 +15,17 @@ interface MenuBuilder; // http://www.whatwg.org/specs/web-apps/current-work/#the-menu-element +[HTMLConstructor] interface HTMLMenuElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString label; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLMenuElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean compact; }; diff --git a/dom/webidl/HTMLMenuItemElement.webidl b/dom/webidl/HTMLMenuItemElement.webidl index 7064885a1..f09104501 100644 --- a/dom/webidl/HTMLMenuItemElement.webidl +++ b/dom/webidl/HTMLMenuItemElement.webidl @@ -12,23 +12,24 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-menuitem-element +[HTMLConstructor] interface HTMLMenuItemElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString label; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString icon; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean disabled; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean checked; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString radiogroup; // This should be 'default' but in the IDL implementation // this has been renamed 'defaultChecked'. - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean defaultChecked; // Currently not implemented. diff --git a/dom/webidl/HTMLMetaElement.webidl b/dom/webidl/HTMLMetaElement.webidl index 5b7b0f92c..30014a955 100644 --- a/dom/webidl/HTMLMetaElement.webidl +++ b/dom/webidl/HTMLMetaElement.webidl @@ -12,17 +12,18 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-meta-element +[HTMLConstructor] interface HTMLMetaElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString httpEquiv; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString content; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLMetaElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString scheme; }; diff --git a/dom/webidl/HTMLMeterElement.webidl b/dom/webidl/HTMLMeterElement.webidl index 104e00353..8f93bd71e 100644 --- a/dom/webidl/HTMLMeterElement.webidl +++ b/dom/webidl/HTMLMeterElement.webidl @@ -12,18 +12,19 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-meter-element +[HTMLConstructor] interface HTMLMeterElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute double value; - [SetterThrows] + [CEReactions, SetterThrows] attribute double min; - [SetterThrows] + [CEReactions, SetterThrows] attribute double max; - [SetterThrows] + [CEReactions, SetterThrows] attribute double low; - [SetterThrows] + [CEReactions, SetterThrows] attribute double high; - [SetterThrows] + [CEReactions, SetterThrows] attribute double optimum; readonly attribute NodeList labels; diff --git a/dom/webidl/HTMLModElement.webidl b/dom/webidl/HTMLModElement.webidl index 45086cceb..8ed8b994b 100644 --- a/dom/webidl/HTMLModElement.webidl +++ b/dom/webidl/HTMLModElement.webidl @@ -11,9 +11,10 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#attributes-common-to-ins-and-del-elements +[HTMLConstructor] interface HTMLModElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString cite; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString dateTime; }; diff --git a/dom/webidl/HTMLOListElement.webidl b/dom/webidl/HTMLOListElement.webidl index f41abf3ea..93084c227 100644 --- a/dom/webidl/HTMLOListElement.webidl +++ b/dom/webidl/HTMLOListElement.webidl @@ -13,17 +13,18 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-ol-element +[HTMLConstructor] interface HTMLOListElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean reversed; - [SetterThrows] + [CEReactions, SetterThrows] attribute long start; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLOListElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean compact; }; diff --git a/dom/webidl/HTMLObjectElement.webidl b/dom/webidl/HTMLObjectElement.webidl index ebb95ab09..7c9f7f8bc 100644 --- a/dom/webidl/HTMLObjectElement.webidl +++ b/dom/webidl/HTMLObjectElement.webidl @@ -13,23 +13,23 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-object-element -[NeedResolve, UnsafeInPrerendering] +[HTMLConstructor, NeedResolve, UnsafeInPrerendering] interface HTMLObjectElement : HTMLElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString data; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString type; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean typeMustMatch; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString name; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString useMap; [Pure] readonly attribute HTMLFormElement? form; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString width; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString height; // Not pure: can trigger about:blank instantiation [NeedsSubjectPrincipal] @@ -51,26 +51,26 @@ interface HTMLObjectElement : HTMLElement { // http://www.whatwg.org/specs/web-apps/current-work/#HTMLObjectElement-partial partial interface HTMLObjectElement { - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString align; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString archive; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString code; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute boolean declare; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute unsigned long hspace; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString standby; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute unsigned long vspace; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString codeBase; - [Pure, SetterThrows] + [CEReactions, Pure, SetterThrows] attribute DOMString codeType; - [TreatNullAs=EmptyString, Pure, SetterThrows] + [CEReactions, TreatNullAs=EmptyString, Pure, SetterThrows] attribute DOMString border; }; diff --git a/dom/webidl/HTMLOptGroupElement.webidl b/dom/webidl/HTMLOptGroupElement.webidl index a23aee30d..d46fb869d 100644 --- a/dom/webidl/HTMLOptGroupElement.webidl +++ b/dom/webidl/HTMLOptGroupElement.webidl @@ -11,9 +11,10 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLOptGroupElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean disabled; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString label; }; diff --git a/dom/webidl/HTMLOptionElement.webidl b/dom/webidl/HTMLOptionElement.webidl index c80bedeef..b94afa3e9 100644 --- a/dom/webidl/HTMLOptionElement.webidl +++ b/dom/webidl/HTMLOptionElement.webidl @@ -11,21 +11,21 @@ * and create derivative works of this document. */ -[NamedConstructor=Option(optional DOMString text, optional DOMString value, optional boolean defaultSelected, optional boolean selected)] +[HTMLConstructor, NamedConstructor=Option(optional DOMString text, optional DOMString value, optional boolean defaultSelected, optional boolean selected)] interface HTMLOptionElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean disabled; readonly attribute HTMLFormElement? form; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString label; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean defaultSelected; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean selected; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString value; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString text; readonly attribute long index; }; diff --git a/dom/webidl/HTMLOptionsCollection.webidl b/dom/webidl/HTMLOptionsCollection.webidl index 4d4385d82..d8d1046ad 100644 --- a/dom/webidl/HTMLOptionsCollection.webidl +++ b/dom/webidl/HTMLOptionsCollection.webidl @@ -11,13 +11,14 @@ */ interface HTMLOptionsCollection : HTMLCollection { + [CEReactions] attribute unsigned long length; - [Throws] + [CEReactions, Throws] setter creator void (unsigned long index, HTMLOptionElement? option); - [Throws] + [CEReactions, Throws] void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); - [Throws] + [CEReactions, Throws] void remove(long index); - [Throws] + [CEReactions, Throws] attribute long selectedIndex; }; diff --git a/dom/webidl/HTMLOutputElement.webidl b/dom/webidl/HTMLOutputElement.webidl index d0e4ecbe6..4d65209a9 100644 --- a/dom/webidl/HTMLOutputElement.webidl +++ b/dom/webidl/HTMLOutputElement.webidl @@ -12,18 +12,19 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-output-element +[HTMLConstructor] interface HTMLOutputElement : HTMLElement { [PutForwards=value, Constant] readonly attribute DOMTokenList htmlFor; readonly attribute HTMLFormElement? form; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; [Constant] readonly attribute DOMString type; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString defaultValue; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString value; readonly attribute boolean willValidate; diff --git a/dom/webidl/HTMLParagraphElement.webidl b/dom/webidl/HTMLParagraphElement.webidl index 2a626d257..289af4c9f 100644 --- a/dom/webidl/HTMLParagraphElement.webidl +++ b/dom/webidl/HTMLParagraphElement.webidl @@ -12,11 +12,12 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-p-element +[HTMLConstructor] interface HTMLParagraphElement : HTMLElement { }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLParagraphElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; }; diff --git a/dom/webidl/HTMLParamElement.webidl b/dom/webidl/HTMLParamElement.webidl index e2c7e8d7f..cf6b5a35a 100644 --- a/dom/webidl/HTMLParamElement.webidl +++ b/dom/webidl/HTMLParamElement.webidl @@ -13,17 +13,18 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-param-element +[HTMLConstructor] interface HTMLParamElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString value; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLParamElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString type; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString valueType; }; diff --git a/dom/webidl/HTMLPictureElement.webidl b/dom/webidl/HTMLPictureElement.webidl index eff30f750..387eee78d 100644 --- a/dom/webidl/HTMLPictureElement.webidl +++ b/dom/webidl/HTMLPictureElement.webidl @@ -4,5 +4,6 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ +[HTMLConstructor] interface HTMLPictureElement : HTMLElement { }; diff --git a/dom/webidl/HTMLPreElement.webidl b/dom/webidl/HTMLPreElement.webidl index db220b74c..6929cd533 100644 --- a/dom/webidl/HTMLPreElement.webidl +++ b/dom/webidl/HTMLPreElement.webidl @@ -12,11 +12,12 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-pre-element +[HTMLConstructor] interface HTMLPreElement : HTMLElement { }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLPreElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute long width; }; diff --git a/dom/webidl/HTMLProgressElement.webidl b/dom/webidl/HTMLProgressElement.webidl index 028728e22..564b9f2a4 100644 --- a/dom/webidl/HTMLProgressElement.webidl +++ b/dom/webidl/HTMLProgressElement.webidl @@ -11,10 +11,11 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLProgressElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute double value; - [SetterThrows] + [CEReactions, SetterThrows] attribute double max; readonly attribute double position; readonly attribute NodeList labels; diff --git a/dom/webidl/HTMLQuoteElement.webidl b/dom/webidl/HTMLQuoteElement.webidl index a266dd353..c999b1478 100644 --- a/dom/webidl/HTMLQuoteElement.webidl +++ b/dom/webidl/HTMLQuoteElement.webidl @@ -12,8 +12,9 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-blockquote-element +[HTMLConstructor] interface HTMLQuoteElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString cite; }; diff --git a/dom/webidl/HTMLScriptElement.webidl b/dom/webidl/HTMLScriptElement.webidl index 5b64c42d7..286c0673d 100644 --- a/dom/webidl/HTMLScriptElement.webidl +++ b/dom/webidl/HTMLScriptElement.webidl @@ -8,35 +8,36 @@ * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis */ +[HTMLConstructor] interface HTMLScriptElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString src; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; - [SetterThrows, Pref="dom.moduleScripts.enabled"] + [CEReactions, SetterThrows, Pref="dom.moduleScripts.enabled"] attribute boolean noModule; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString charset; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean async; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean defer; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString? crossOrigin; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString text; }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLScriptElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString event; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString htmlFor; }; // https://w3c.github.io/webappsec/specs/subresourceintegrity/#htmlscriptelement-1 partial interface HTMLScriptElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString integrity; }; diff --git a/dom/webidl/HTMLSelectElement.webidl b/dom/webidl/HTMLSelectElement.webidl index b18ca3634..537e9d84f 100644 --- a/dom/webidl/HTMLSelectElement.webidl +++ b/dom/webidl/HTMLSelectElement.webidl @@ -7,22 +7,23 @@ * http://www.whatwg.org/html/#the-select-element */ +[HTMLConstructor] interface HTMLSelectElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean autofocus; - [Pref="dom.forms.autocomplete.experimental", SetterThrows, Pure] + [CEReactions, Pref="dom.forms.autocomplete.experimental", SetterThrows, Pure] attribute DOMString autocomplete; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean disabled; [Pure] readonly attribute HTMLFormElement? form; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean multiple; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean required; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute unsigned long size; [Pure] @@ -30,14 +31,15 @@ interface HTMLSelectElement : HTMLElement { [Constant] readonly attribute HTMLOptionsCollection options; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute unsigned long length; getter Element? item(unsigned long index); HTMLOptionElement? namedItem(DOMString name); - [Throws] + [CEReactions, Throws] void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); + [CEReactions] void remove(long index); - [Throws] + [CEReactions, Throws] setter creator void (unsigned long index, HTMLOptionElement? option); readonly attribute HTMLCollection selectedOptions; @@ -56,6 +58,7 @@ interface HTMLSelectElement : HTMLElement { readonly attribute NodeList labels; // https://www.w3.org/Bugs/Public/show_bug.cgi?id=20720 + [CEReactions] void remove(); }; diff --git a/dom/webidl/HTMLSourceElement.webidl b/dom/webidl/HTMLSourceElement.webidl index 10b8e6fd5..55f25e469 100644 --- a/dom/webidl/HTMLSourceElement.webidl +++ b/dom/webidl/HTMLSourceElement.webidl @@ -11,18 +11,19 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLSourceElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString src; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; }; partial interface HTMLSourceElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString srcset; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString sizes; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString media; }; diff --git a/dom/webidl/HTMLSpanElement.webidl b/dom/webidl/HTMLSpanElement.webidl index 43a2d97f2..6f65cdfb3 100644 --- a/dom/webidl/HTMLSpanElement.webidl +++ b/dom/webidl/HTMLSpanElement.webidl @@ -12,4 +12,5 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-span-element +[HTMLConstructor] interface HTMLSpanElement : HTMLElement {}; diff --git a/dom/webidl/HTMLStyleElement.webidl b/dom/webidl/HTMLStyleElement.webidl index 7ed01a8f1..3cacbf62f 100644 --- a/dom/webidl/HTMLStyleElement.webidl +++ b/dom/webidl/HTMLStyleElement.webidl @@ -8,12 +8,13 @@ * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis */ +[HTMLConstructor] interface HTMLStyleElement : HTMLElement { [Pure] attribute boolean disabled; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString media; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString type; [SetterThrows, Pure] attribute boolean scoped; diff --git a/dom/webidl/HTMLTableCaptionElement.webidl b/dom/webidl/HTMLTableCaptionElement.webidl index 688b9f925..48c9d354a 100644 --- a/dom/webidl/HTMLTableCaptionElement.webidl +++ b/dom/webidl/HTMLTableCaptionElement.webidl @@ -11,9 +11,10 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLTableCaptionElement : HTMLElement {}; partial interface HTMLTableCaptionElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; }; diff --git a/dom/webidl/HTMLTableCellElement.webidl b/dom/webidl/HTMLTableCellElement.webidl index e970a5040..aff94914f 100644 --- a/dom/webidl/HTMLTableCellElement.webidl +++ b/dom/webidl/HTMLTableCellElement.webidl @@ -11,41 +11,43 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLTableCellElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long colSpan; - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long rowSpan; //[PutForwards=value] readonly attribute DOMTokenList headers; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString headers; readonly attribute long cellIndex; // Mozilla-specific extensions - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString abbr; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString scope; }; partial interface HTMLTableCellElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString axis; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString height; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString width; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString ch; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString chOff; - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean noWrap; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString vAlign; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString bgColor; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString bgColor; }; diff --git a/dom/webidl/HTMLTableColElement.webidl b/dom/webidl/HTMLTableColElement.webidl index c927541a3..02be4590a 100644 --- a/dom/webidl/HTMLTableColElement.webidl +++ b/dom/webidl/HTMLTableColElement.webidl @@ -11,20 +11,21 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLTableColElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long span; }; partial interface HTMLTableColElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString ch; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString chOff; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString vAlign; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString width; }; diff --git a/dom/webidl/HTMLTableElement.webidl b/dom/webidl/HTMLTableElement.webidl index a06f590e0..f81e00041 100644 --- a/dom/webidl/HTMLTableElement.webidl +++ b/dom/webidl/HTMLTableElement.webidl @@ -11,45 +11,52 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLTableElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute HTMLTableCaptionElement? caption; HTMLElement createCaption(); + [CEReactions] void deleteCaption(); - [SetterThrows] + [CEReactions, SetterThrows] attribute HTMLTableSectionElement? tHead; HTMLElement createTHead(); + [CEReactions] void deleteTHead(); - [SetterThrows] + [CEReactions, SetterThrows] attribute HTMLTableSectionElement? tFoot; HTMLElement createTFoot(); + [CEReactions] void deleteTFoot(); readonly attribute HTMLCollection tBodies; HTMLElement createTBody(); readonly attribute HTMLCollection rows; [Throws] HTMLElement insertRow(optional long index = -1); - [Throws] + [CEReactions, Throws] void deleteRow(long index); // attribute boolean sortable; //void stopSorting(); }; partial interface HTMLTableElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString border; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString frame; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString rules; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString summary; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString width; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString bgColor; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString cellPadding; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString cellSpacing; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString bgColor; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString cellPadding; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString cellSpacing; }; diff --git a/dom/webidl/HTMLTableRowElement.webidl b/dom/webidl/HTMLTableRowElement.webidl index 2a356a20e..153d271f1 100644 --- a/dom/webidl/HTMLTableRowElement.webidl +++ b/dom/webidl/HTMLTableRowElement.webidl @@ -11,25 +11,27 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLTableRowElement : HTMLElement { readonly attribute long rowIndex; readonly attribute long sectionRowIndex; readonly attribute HTMLCollection cells; - [Throws] + [CEReactions, Throws] HTMLElement insertCell(optional long index = -1); [Throws] void deleteCell(long index); }; partial interface HTMLTableRowElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString ch; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString chOff; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString vAlign; - [TreatNullAs=EmptyString, SetterThrows] attribute DOMString bgColor; + [CEReactions, TreatNullAs=EmptyString, SetterThrows] + attribute DOMString bgColor; }; diff --git a/dom/webidl/HTMLTableSectionElement.webidl b/dom/webidl/HTMLTableSectionElement.webidl index 310d0ece6..a71682fc1 100644 --- a/dom/webidl/HTMLTableSectionElement.webidl +++ b/dom/webidl/HTMLTableSectionElement.webidl @@ -11,21 +11,22 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLTableSectionElement : HTMLElement { readonly attribute HTMLCollection rows; [Throws] HTMLElement insertRow(optional long index = -1); - [Throws] + [CEReactions, Throws] void deleteRow(long index); }; partial interface HTMLTableSectionElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString align; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString ch; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString chOff; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString vAlign; }; diff --git a/dom/webidl/HTMLTemplateElement.webidl b/dom/webidl/HTMLTemplateElement.webidl index c518995f6..f77eeaa42 100644 --- a/dom/webidl/HTMLTemplateElement.webidl +++ b/dom/webidl/HTMLTemplateElement.webidl @@ -9,6 +9,7 @@ * liability, trademark and document use rules apply. */ +[HTMLConstructor] interface HTMLTemplateElement : HTMLElement { readonly attribute DocumentFragment content; }; diff --git a/dom/webidl/HTMLTextAreaElement.webidl b/dom/webidl/HTMLTextAreaElement.webidl index 4df687a0b..7a181bf39 100644 --- a/dom/webidl/HTMLTextAreaElement.webidl +++ b/dom/webidl/HTMLTextAreaElement.webidl @@ -14,40 +14,41 @@ interface nsIEditor; interface MozControllers; +[HTMLConstructor] interface HTMLTextAreaElement : HTMLElement { // attribute DOMString autocomplete; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean autofocus; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute unsigned long cols; // attribute DOMString dirName; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean disabled; [Pure] readonly attribute HTMLFormElement? form; // attribute DOMString inputMode; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute long maxLength; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute long minLength; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString name; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString placeholder; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean readOnly; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean required; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute unsigned long rows; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString wrap; [Constant] readonly attribute DOMString type; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString defaultValue; - [TreatNullAs=EmptyString] attribute DOMString value; + [CEReactions, TreatNullAs=EmptyString] attribute DOMString value; readonly attribute unsigned long textLength; readonly attribute boolean willValidate; diff --git a/dom/webidl/HTMLTimeElement.webidl b/dom/webidl/HTMLTimeElement.webidl index 517ca9981..35c06fef3 100644 --- a/dom/webidl/HTMLTimeElement.webidl +++ b/dom/webidl/HTMLTimeElement.webidl @@ -7,7 +7,8 @@ * http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-time-element */ +[HTMLConstructor] interface HTMLTimeElement : HTMLElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString dateTime; }; diff --git a/dom/webidl/HTMLTitleElement.webidl b/dom/webidl/HTMLTitleElement.webidl index e6c8f2c61..bbce70bb2 100644 --- a/dom/webidl/HTMLTitleElement.webidl +++ b/dom/webidl/HTMLTitleElement.webidl @@ -7,7 +7,8 @@ * http://www.whatwg.org/specs/web-apps/current-work/#the-title-element */ +[HTMLConstructor] interface HTMLTitleElement : HTMLElement { - [Throws] + [CEReactions, Throws] attribute DOMString text; }; diff --git a/dom/webidl/HTMLTrackElement.webidl b/dom/webidl/HTMLTrackElement.webidl index dd88e9beb..cbb70db2a 100644 --- a/dom/webidl/HTMLTrackElement.webidl +++ b/dom/webidl/HTMLTrackElement.webidl @@ -7,16 +7,17 @@ * http://www.whatwg.org/specs/web-apps/current-work/#the-track-element */ +[HTMLConstructor] interface HTMLTrackElement : HTMLElement { - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString kind; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString src; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString srclang; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString label; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute boolean default; const unsigned short NONE = 0; diff --git a/dom/webidl/HTMLUListElement.webidl b/dom/webidl/HTMLUListElement.webidl index 0528198c9..725437494 100644 --- a/dom/webidl/HTMLUListElement.webidl +++ b/dom/webidl/HTMLUListElement.webidl @@ -13,13 +13,14 @@ */ // http://www.whatwg.org/specs/web-apps/current-work/#the-ul-element +[HTMLConstructor] interface HTMLUListElement : HTMLElement { }; // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis partial interface HTMLUListElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute boolean compact; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString type; }; diff --git a/dom/webidl/HTMLVideoElement.webidl b/dom/webidl/HTMLVideoElement.webidl index af28d5418..5ae4c016f 100644 --- a/dom/webidl/HTMLVideoElement.webidl +++ b/dom/webidl/HTMLVideoElement.webidl @@ -11,14 +11,15 @@ * and create derivative works of this document. */ +[HTMLConstructor] interface HTMLVideoElement : HTMLMediaElement { - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long width; - [SetterThrows] + [CEReactions, SetterThrows] attribute unsigned long height; readonly attribute unsigned long videoWidth; readonly attribute unsigned long videoHeight; - [SetterThrows] + [CEReactions, SetterThrows] attribute DOMString poster; }; diff --git a/dom/webidl/NamedNodeMap.webidl b/dom/webidl/NamedNodeMap.webidl index 41fbfcbb4..88e2ff51f 100644 --- a/dom/webidl/NamedNodeMap.webidl +++ b/dom/webidl/NamedNodeMap.webidl @@ -6,17 +6,17 @@ [LegacyUnenumerableNamedProperties] interface NamedNodeMap { getter Attr? getNamedItem(DOMString name); - [Throws, BinaryName="setNamedItemNS"] + [CEReactions, Throws, BinaryName="setNamedItemNS"] Attr? setNamedItem(Attr arg); - [Throws] + [CEReactions, Throws] Attr removeNamedItem(DOMString name); getter Attr? item(unsigned long index); readonly attribute unsigned long length; Attr? getNamedItemNS(DOMString? namespaceURI, DOMString localName); - [Throws] + [CEReactions, Throws] Attr? setNamedItemNS(Attr arg); - [Throws] + [CEReactions, Throws] Attr removeNamedItemNS(DOMString? namespaceURI, DOMString localName); }; diff --git a/dom/webidl/Node.webidl b/dom/webidl/Node.webidl index 7d18899b0..8b6dca788 100644 --- a/dom/webidl/Node.webidl +++ b/dom/webidl/Node.webidl @@ -57,21 +57,21 @@ interface Node : EventTarget { [Pure] readonly attribute Node? nextSibling; - [SetterThrows, Pure] + [CEReactions, SetterThrows, Pure] attribute DOMString? nodeValue; - [Throws, Pure] + [CEReactions, Throws, Pure] attribute DOMString? textContent; - [Throws] + [CEReactions, Throws] Node insertBefore(Node node, Node? child); - [Throws] + [CEReactions, Throws] Node appendChild(Node node); - [Throws] + [CEReactions, Throws] Node replaceChild(Node node, Node child); - [Throws] + [CEReactions, Throws] Node removeChild(Node child); void normalize(); - [Throws] + [CEReactions, Throws] Node cloneNode(optional boolean deep = false); [Pure] boolean isSameNode(Node? node); diff --git a/dom/webidl/ParentNode.webidl b/dom/webidl/ParentNode.webidl index 5834b9be3..aa6ca5db2 100644 --- a/dom/webidl/ParentNode.webidl +++ b/dom/webidl/ParentNode.webidl @@ -18,8 +18,8 @@ interface ParentNode { [Pure] readonly attribute unsigned long childElementCount; - [Throws, Unscopable] + [CEReactions, Throws, Unscopable] void prepend((Node or DOMString)... nodes); - [Throws, Unscopable] + [CEReactions, Throws, Unscopable] void append((Node or DOMString)... nodes); }; diff --git a/dom/webidl/Range.webidl b/dom/webidl/Range.webidl index ac8e1ebf0..6b8be970b 100644 --- a/dom/webidl/Range.webidl +++ b/dom/webidl/Range.webidl @@ -50,15 +50,15 @@ interface Range { const unsigned short END_TO_START = 3; [Throws] short compareBoundaryPoints(unsigned short how, Range sourceRange); - [Throws] + [CEReactions, Throws] void deleteContents(); - [Throws] + [CEReactions, Throws] DocumentFragment extractContents(); - [Throws] + [CEReactions, Throws] DocumentFragment cloneContents(); - [Throws] + [CEReactions, Throws] void insertNode(Node node); - [Throws] + [CEReactions, Throws] void surroundContents(Node newParent); Range cloneRange(); @@ -77,7 +77,7 @@ interface Range { // http://domparsing.spec.whatwg.org/#dom-range-createcontextualfragment partial interface Range { - [Throws] + [CEReactions, Throws] DocumentFragment createContextualFragment(DOMString fragment); }; diff --git a/dom/webidl/ShadowRoot.webidl b/dom/webidl/ShadowRoot.webidl index a6c6de254..8dd069244 100644 --- a/dom/webidl/ShadowRoot.webidl +++ b/dom/webidl/ShadowRoot.webidl @@ -17,7 +17,7 @@ interface ShadowRoot : DocumentFragment HTMLCollection getElementsByTagName(DOMString localName); HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); HTMLCollection getElementsByClassName(DOMString classNames); - [SetterThrows,TreatNullAs=EmptyString] + [CEReactions, SetterThrows, TreatNullAs=EmptyString] attribute DOMString innerHTML; readonly attribute Element host; readonly attribute ShadowRoot? olderShadowRoot; diff --git a/dom/webidl/WebComponents.webidl b/dom/webidl/WebComponents.webidl index 3dfb960bc..f9bb8214a 100644 --- a/dom/webidl/WebComponents.webidl +++ b/dom/webidl/WebComponents.webidl @@ -10,15 +10,19 @@ * liability, trademark and document use rules apply. */ -callback LifecycleCreatedCallback = void(); -callback LifecycleAttachedCallback = void(); -callback LifecycleDetachedCallback = void(); -callback LifecycleAttributeChangedCallback = void(DOMString attrName, DOMString? oldValue, DOMString? newValue); +callback LifecycleConnectedCallback = void(); +callback LifecycleDisconnectedCallback = void(); +callback LifecycleAdoptedCallback = void(Document? oldDocument, + Document? newDocment); +callback LifecycleAttributeChangedCallback = void(DOMString attrName, + DOMString? oldValue, + DOMString? newValue, + DOMString? namespaceURI); dictionary LifecycleCallbacks { - LifecycleCreatedCallback? createdCallback; - LifecycleAttachedCallback? attachedCallback; - LifecycleDetachedCallback? detachedCallback; + LifecycleConnectedCallback? connectedCallback; + LifecycleDisconnectedCallback? disconnectedCallback; + LifecycleAdoptedCallback? adoptedCallback; LifecycleAttributeChangedCallback? attributeChangedCallback; }; diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 468f1cc8a..ab03bf40b 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -78,9 +78,6 @@ typedef any Transferable; [Throws, UnsafeInPrerendering, NeedsSubjectPrincipal] boolean confirm(optional DOMString message = ""); [Throws, UnsafeInPrerendering, NeedsSubjectPrincipal] DOMString? prompt(optional DOMString message = "", optional DOMString default = ""); [Throws, UnsafeInPrerendering] void print(); - //[Throws] any showModalDialog(DOMString url, optional any argument); - [Throws, Func="nsGlobalWindow::IsShowModalDialogEnabled", UnsafeInPrerendering, NeedsSubjectPrincipal] - any showModalDialog(DOMString url, optional any argument, optional DOMString options = ""); [Throws, CrossOriginCallable, NeedsSubjectPrincipal] void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer); @@ -240,17 +237,6 @@ interface SpeechSynthesisGetter { Window implements SpeechSynthesisGetter; #endif -// http://www.whatwg.org/specs/web-apps/current-work/ -[NoInterfaceObject] -interface WindowModal { - [Throws, Func="nsGlobalWindow::IsModalContentWindow", NeedsSubjectPrincipal] - readonly attribute any dialogArguments; - - [Throws, Func="nsGlobalWindow::IsModalContentWindow", NeedsSubjectPrincipal] - attribute any returnValue; -}; -Window implements WindowModal; - // Mozilla-specific stuff partial interface Window { //[NewObject, Throws] CSSStyleDeclaration getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = ""); diff --git a/dom/webidl/XSLTProcessor.webidl b/dom/webidl/XSLTProcessor.webidl index ce9ed846f..276e1b3fa 100644 --- a/dom/webidl/XSLTProcessor.webidl +++ b/dom/webidl/XSLTProcessor.webidl @@ -30,7 +30,7 @@ interface XSLTProcessor { * @param output This document is used to generate the output * @return DocumentFragment The result of the transformation */ - [Throws] + [CEReactions, Throws] DocumentFragment transformToFragment(Node source, Document output); @@ -41,7 +41,7 @@ interface XSLTProcessor { * @param source The node to be transformed * @return Document The result of the transformation */ - [Throws] + [CEReactions, Throws] Document transformToDocument(Node source); /** diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index e351a46eb..a854f53ec 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -174,33 +174,6 @@ nsXULElement::~nsXULElement() { } -nsXULElement::nsXULSlots::nsXULSlots() - : nsXULElement::nsDOMSlots() -{ -} - -nsXULElement::nsXULSlots::~nsXULSlots() -{ - NS_IF_RELEASE(mControllers); // Forces release - nsCOMPtr<nsIFrameLoader> frameLoader = do_QueryInterface(mFrameLoaderOrOpener); - if (frameLoader) { - static_cast<nsFrameLoader*>(frameLoader.get())->Destroy(); - } -} - -void -nsXULElement::nsXULSlots::Traverse(nsCycleCollectionTraversalCallback &cb) -{ - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mFrameLoaderOrOpener"); - cb.NoteXPCOMChild(mFrameLoaderOrOpener); -} - -nsINode::nsSlots* -nsXULElement::CreateSlots() -{ - return new nsXULSlots(); -} - void nsXULElement::MaybeUpdatePrivateLifetime() { @@ -326,12 +299,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement, nsStyledElement) - { - nsXULSlots* slots = static_cast<nsXULSlots*>(tmp->GetExistingSlots()); - if (slots) { - slots->Traverse(cb); - } - } + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULElement, @@ -895,9 +863,9 @@ nsXULElement::UnbindFromTree(bool aDeep, bool aNullParent) // mDocument in nsGlobalWindow::SetDocShell, but I'm not // sure whether that would fix all possible cycles through // mControllers.) - nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots()); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { - NS_IF_RELEASE(slots->mControllers); + slots->mControllers = nullptr; RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(); if (frameLoader) { frameLoader->Destroy(); @@ -1241,9 +1209,9 @@ nsXULElement::RemoveBroadcaster(const nsAString & broadcasterId) void nsXULElement::DestroyContent() { - nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots()); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (slots) { - NS_IF_RELEASE(slots->mControllers); + slots->mControllers = nullptr; RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(); if (frameLoader) { frameLoader->Destroy(); @@ -1473,7 +1441,7 @@ nsIControllers* nsXULElement::GetControllers(ErrorResult& rv) { if (! Controllers()) { - nsDOMSlots* slots = DOMSlots(); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); rv = NS_NewXULControllers(nullptr, NS_GET_IID(nsIControllers), reinterpret_cast<void**>(&slots->mControllers)); @@ -1578,7 +1546,7 @@ nsXULElement::LoadSrc() RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(); if (!frameLoader) { // Check if we have an opener we need to be setting - nsXULSlots* slots = static_cast<nsXULSlots*>(Slots()); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryInterface(slots->mFrameLoaderOrOpener); if (!opener) { // If we are a content-primary xul-browser, we want to take the opener property! @@ -1624,7 +1592,7 @@ nsXULElement::GetFrameLoaderXPCOM(nsIFrameLoader **aFrameLoader) already_AddRefed<nsFrameLoader> nsXULElement::GetFrameLoader() { - nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingSlots()); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); if (!slots) return nullptr; @@ -1646,7 +1614,7 @@ nsXULElement::GetParentApplication(mozIApplication** aApplication) void nsXULElement::PresetOpenerWindow(mozIDOMWindowProxy* aWindow, ErrorResult& aRv) { - nsXULSlots* slots = static_cast<nsXULSlots*>(Slots()); + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); MOZ_ASSERT(!slots->mFrameLoaderOrOpener, "A frameLoader or opener is present when calling PresetOpenerWindow"); slots->mFrameLoaderOrOpener = aWindow; @@ -1662,7 +1630,7 @@ nsXULElement::SetIsPrerendered() void nsXULElement::InternalSetFrameLoader(nsIFrameLoader* aNewFrameLoader) { - nsXULSlots* slots = static_cast<nsXULSlots*>(GetExistingDOMSlots()); + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); MOZ_ASSERT(slots); slots->mFrameLoaderOrOpener = aNewFrameLoader; diff --git a/dom/xul/nsXULElement.h b/dom/xul/nsXULElement.h index 164afacd3..80424412f 100644 --- a/dom/xul/nsXULElement.h +++ b/dom/xul/nsXULElement.h @@ -609,19 +609,6 @@ protected: nsresult AddPopupListener(nsIAtom* aName); - class nsXULSlots : public mozilla::dom::Element::nsDOMSlots - { - public: - nsXULSlots(); - virtual ~nsXULSlots(); - - void Traverse(nsCycleCollectionTraversalCallback &cb); - - nsCOMPtr<nsISupports> mFrameLoaderOrOpener; - }; - - virtual nsINode::nsSlots* CreateSlots() override; - nsresult LoadSrc(); /** @@ -677,8 +664,8 @@ protected: // Internal accessor. This shadows the 'Slots', and returns // appropriate value. nsIControllers *Controllers() { - nsDOMSlots* slots = GetExistingDOMSlots(); - return slots ? slots->mControllers : nullptr; + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); + return slots ? slots->mControllers.get() : nullptr; } void UnregisterAccessKey(const nsAString& aOldValue); |