Implement Custom Elements v1.
parent
cd5cc91f9d
commit
99fd13b6dd
File diff suppressed because it is too large
Load Diff
|
@ -7,13 +7,16 @@
|
||||||
#ifndef mozilla_dom_CustomElementRegistry_h
|
#ifndef mozilla_dom_CustomElementRegistry_h
|
||||||
#define mozilla_dom_CustomElementRegistry_h
|
#define mozilla_dom_CustomElementRegistry_h
|
||||||
|
|
||||||
|
#include "js/GCHashTable.h"
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
|
||||||
#include "nsWrapperCache.h"
|
|
||||||
#include "mozilla/dom/FunctionBinding.h"
|
#include "mozilla/dom/FunctionBinding.h"
|
||||||
|
#include "mozilla/dom/WebComponentsBinding.h"
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsGenericHTMLElement.h"
|
||||||
|
#include "nsWrapperCache.h"
|
||||||
|
|
||||||
class nsDocument;
|
class nsDocument;
|
||||||
|
|
||||||
|
@ -22,8 +25,8 @@ namespace dom {
|
||||||
|
|
||||||
struct CustomElementData;
|
struct CustomElementData;
|
||||||
struct ElementDefinitionOptions;
|
struct ElementDefinitionOptions;
|
||||||
struct LifecycleCallbacks;
|
|
||||||
class CallbackFunction;
|
class CallbackFunction;
|
||||||
|
class CustomElementReaction;
|
||||||
class Function;
|
class Function;
|
||||||
class Promise;
|
class Promise;
|
||||||
|
|
||||||
|
@ -32,6 +35,13 @@ struct LifecycleCallbackArgs
|
||||||
nsString name;
|
nsString name;
|
||||||
nsString oldValue;
|
nsString oldValue;
|
||||||
nsString newValue;
|
nsString newValue;
|
||||||
|
nsString namespaceURI;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LifecycleAdoptedCallbackArgs
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDocument> mOldDocument;
|
||||||
|
nsCOMPtr<nsIDocument> mNewDocument;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CustomElementCallback
|
class CustomElementCallback
|
||||||
|
@ -39,8 +49,7 @@ class CustomElementCallback
|
||||||
public:
|
public:
|
||||||
CustomElementCallback(Element* aThisObject,
|
CustomElementCallback(Element* aThisObject,
|
||||||
nsIDocument::ElementCallbackType aCallbackType,
|
nsIDocument::ElementCallbackType aCallbackType,
|
||||||
CallbackFunction* aCallback,
|
CallbackFunction* aCallback);
|
||||||
CustomElementData* aOwnerData);
|
|
||||||
void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
|
void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
|
||||||
void Call();
|
void Call();
|
||||||
void SetArgs(LifecycleCallbackArgs& aArgs)
|
void SetArgs(LifecycleCallbackArgs& aArgs)
|
||||||
|
@ -50,6 +59,13 @@ public:
|
||||||
mArgs = aArgs;
|
mArgs = aArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetAdoptedCallbackArgs(LifecycleAdoptedCallbackArgs& aAdoptedCallbackArgs)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mType == nsIDocument::eAdopted,
|
||||||
|
"Arguments are only used by adopted callback.");
|
||||||
|
mAdoptedCallbackArgs = aAdoptedCallbackArgs;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The this value to use for invocation of the callback.
|
// The this value to use for invocation of the callback.
|
||||||
RefPtr<Element> mThisObject;
|
RefPtr<Element> mThisObject;
|
||||||
|
@ -59,9 +75,19 @@ private:
|
||||||
// Arguments to be passed to the callback,
|
// Arguments to be passed to the callback,
|
||||||
// used by the attribute changed callback.
|
// used by the attribute changed callback.
|
||||||
LifecycleCallbackArgs mArgs;
|
LifecycleCallbackArgs mArgs;
|
||||||
// CustomElementData that contains this callback in the
|
LifecycleAdoptedCallbackArgs mAdoptedCallbackArgs;
|
||||||
// callback queue.
|
};
|
||||||
CustomElementData* mOwnerData;
|
|
||||||
|
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
|
// Each custom element has an associated callback queue and an element is
|
||||||
|
@ -70,63 +96,299 @@ struct CustomElementData
|
||||||
{
|
{
|
||||||
NS_INLINE_DECL_REFCOUNTING(CustomElementData)
|
NS_INLINE_DECL_REFCOUNTING(CustomElementData)
|
||||||
|
|
||||||
explicit CustomElementData(nsIAtom* aType);
|
// https://dom.spec.whatwg.org/#concept-element-custom-element-state
|
||||||
// Objects in this array are transient and empty after each microtask
|
// CustomElementData is only created on the element which is a custom element
|
||||||
// checkpoint.
|
// or an upgrade candidate, so the state of an element without
|
||||||
nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
|
// CustomElementData is "uncustomized".
|
||||||
// Custom element type, for <button is="x-button"> or <x-button>
|
enum class State {
|
||||||
// this would be x-button.
|
eUndefined,
|
||||||
nsCOMPtr<nsIAtom> mType;
|
eFailed,
|
||||||
// The callback that is next to be processed upon calling RunCallbackQueue.
|
eCustom
|
||||||
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.
|
explicit CustomElementData(nsIAtom* aType);
|
||||||
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:
|
private:
|
||||||
virtual ~CustomElementData() {}
|
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:
|
// The required information for a custom element as defined in:
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
|
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
|
||||||
struct CustomElementDefinition
|
struct CustomElementDefinition
|
||||||
{
|
{
|
||||||
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CustomElementDefinition)
|
||||||
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CustomElementDefinition)
|
||||||
|
|
||||||
CustomElementDefinition(nsIAtom* aType,
|
CustomElementDefinition(nsIAtom* aType,
|
||||||
nsIAtom* aLocalName,
|
nsIAtom* aLocalName,
|
||||||
JSObject* aConstructor,
|
Function* aConstructor,
|
||||||
|
nsCOMArray<nsIAtom>&& aObservedAttributes,
|
||||||
JSObject* aPrototype,
|
JSObject* aPrototype,
|
||||||
mozilla::dom::LifecycleCallbacks* aCallbacks,
|
mozilla::dom::LifecycleCallbacks* aCallbacks,
|
||||||
uint32_t aDocOrder);
|
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;
|
nsCOMPtr<nsIAtom> mType;
|
||||||
|
|
||||||
// The localname to (e.g. <button is=type> -- this would be button).
|
// The localname to (e.g. <button is=type> -- this would be button).
|
||||||
nsCOMPtr<nsIAtom> mLocalName;
|
nsCOMPtr<nsIAtom> mLocalName;
|
||||||
|
|
||||||
// The custom element constructor.
|
// 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.
|
// The prototype to use for new custom elements of this type.
|
||||||
JS::Heap<JSObject *> mPrototype;
|
JS::Heap<JSObject *> mPrototype;
|
||||||
|
|
||||||
// The lifecycle callbacks to call for this custom element.
|
// The lifecycle callbacks to call for this custom element.
|
||||||
nsAutoPtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
|
UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
|
||||||
|
|
||||||
// A construction stack.
|
// A construction stack. Use nullptr to represent an "already constructed marker".
|
||||||
// TODO: Bug 1287348 - Implement construction stack for upgrading an element
|
nsTArray<RefPtr<nsGenericHTMLElement>> mConstructionStack;
|
||||||
|
|
||||||
// The document custom element order.
|
// The document custom element order.
|
||||||
uint32_t mDocOrder;
|
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,
|
class CustomElementRegistry final : public nsISupports,
|
||||||
|
@ -142,36 +404,33 @@ public:
|
||||||
public:
|
public:
|
||||||
static bool IsCustomElementEnabled(JSContext* aCx = nullptr,
|
static bool IsCustomElementEnabled(JSContext* aCx = nullptr,
|
||||||
JSObject* aObject = 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.
|
* Looking up a custom element definition.
|
||||||
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition
|
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition
|
||||||
*/
|
*/
|
||||||
CustomElementDefinition* LookupCustomElementDefinition(
|
CustomElementDefinition* LookupCustomElementDefinition(
|
||||||
const nsAString& aLocalName, const nsAString* aIs = nullptr) const;
|
nsIAtom* aNameAtom, nsIAtom* aTypeAtom) const;
|
||||||
|
|
||||||
/**
|
CustomElementDefinition* LookupCustomElementDefinition(
|
||||||
* Enqueue created callback or register upgrade candidate for
|
JSContext* aCx, JSObject *aConstructor) const;
|
||||||
* 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);
|
|
||||||
|
|
||||||
void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
||||||
Element* aCustomElement,
|
Element* aCustomElement,
|
||||||
LifecycleCallbackArgs* aArgs,
|
LifecycleCallbackArgs* aArgs,
|
||||||
CustomElementDefinition* aDefinition);
|
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||||
|
CustomElementDefinition* aDefinition);
|
||||||
|
|
||||||
void GetCustomPrototype(nsIAtom* aAtom,
|
void GetCustomPrototype(nsIAtom* aAtom,
|
||||||
JS::MutableHandle<JSObject*> aPrototype);
|
JS::MutableHandle<JSObject*> aPrototype);
|
||||||
|
|
||||||
private:
|
/**
|
||||||
explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow);
|
* Upgrade an element.
|
||||||
~CustomElementRegistry();
|
* 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
|
* Registers an unresolved custom element that is a candidate for
|
||||||
|
@ -184,23 +443,48 @@ private:
|
||||||
void RegisterUnresolvedElement(Element* aElement,
|
void RegisterUnresolvedElement(Element* aElement,
|
||||||
nsIAtom* aTypeName = nullptr);
|
nsIAtom* aTypeName = nullptr);
|
||||||
|
|
||||||
void UpgradeCandidates(JSContext* aCx,
|
/**
|
||||||
nsIAtom* aKey,
|
* Unregister an unresolved custom element that is a candidate for
|
||||||
CustomElementDefinition* aDefinition);
|
* upgrade when a custom element is removed from tree.
|
||||||
|
*/
|
||||||
|
void UnregisterUnresolvedElement(Element* aElement,
|
||||||
|
nsIAtom* aTypeName = nullptr);
|
||||||
|
private:
|
||||||
|
~CustomElementRegistry();
|
||||||
|
|
||||||
typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition>
|
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
|
||||||
|
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
|
||||||
|
LifecycleCallbackArgs* aArgs,
|
||||||
|
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||||
|
CustomElementDefinition* aDefinition);
|
||||||
|
|
||||||
|
void UpgradeCandidates(nsIAtom* aKey,
|
||||||
|
CustomElementDefinition* aDefinition,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
typedef nsRefPtrHashtable<nsISupportsHashKey, CustomElementDefinition>
|
||||||
DefinitionMap;
|
DefinitionMap;
|
||||||
typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>>
|
typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>>
|
||||||
CandidateMap;
|
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.
|
// Hashtable for custom element definitions in web components.
|
||||||
// Custom prototypes are stored in the compartment where
|
// Custom prototypes are stored in the compartment where
|
||||||
// registerElement was called.
|
// registerElement was called.
|
||||||
DefinitionMap mCustomDefinitions;
|
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>
|
typedef nsRefPtrHashtable<nsISupportsHashKey, Promise>
|
||||||
WhenDefinedPromiseMap;
|
WhenDefinedPromiseMap;
|
||||||
WhenDefinedPromiseMap mWhenDefinedPromiseMap;
|
WhenDefinedPromiseMap mWhenDefinedPromiseMap;
|
||||||
|
|
||||||
// The "upgrade candidates map" from the web components spec. Maps from a
|
// 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
|
// namespace id and local name to a list of elements to upgrade if that
|
||||||
// element is registered as a custom element.
|
// element is registered as a custom element.
|
||||||
|
@ -208,14 +492,6 @@ private:
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
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.
|
// It is used to prevent reentrant invocations of element definition.
|
||||||
bool mIsCustomDefinitionRunning;
|
bool mIsCustomDefinitionRunning;
|
||||||
|
|
||||||
|
@ -252,6 +528,31 @@ public:
|
||||||
already_AddRefed<Promise> WhenDefined(const nsAString& aName, ErrorResult& aRv);
|
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 dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,9 @@ DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey)
|
||||||
DocGroup::~DocGroup()
|
DocGroup::~DocGroup()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mDocuments.IsEmpty());
|
MOZ_ASSERT(mDocuments.IsEmpty());
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
NS_ReleaseOnMainThread(mReactionsStack.forget());
|
||||||
|
}
|
||||||
mTabGroup->mDocGroups.RemoveEntry(mKey);
|
mTabGroup->mDocGroups.RemoveEntry(mKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
|
#include "mozilla/dom/CustomElementRegistry.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
@ -52,6 +53,14 @@ public:
|
||||||
{
|
{
|
||||||
return mTabGroup;
|
return mTabGroup;
|
||||||
}
|
}
|
||||||
|
mozilla::dom::CustomElementReactionsStack* CustomElementReactionsStack()
|
||||||
|
{
|
||||||
|
if (!mReactionsStack) {
|
||||||
|
mReactionsStack = new mozilla::dom::CustomElementReactionsStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mReactionsStack;
|
||||||
|
}
|
||||||
void RemoveDocument(nsIDocument* aWindow);
|
void RemoveDocument(nsIDocument* aWindow);
|
||||||
|
|
||||||
// Iterators for iterating over every document within the DocGroup
|
// Iterators for iterating over every document within the DocGroup
|
||||||
|
@ -71,6 +80,7 @@ private:
|
||||||
nsCString mKey;
|
nsCString mKey;
|
||||||
RefPtr<TabGroup> mTabGroup;
|
RefPtr<TabGroup> mTabGroup;
|
||||||
nsTArray<nsIDocument*> mDocuments;
|
nsTArray<nsIDocument*> mDocuments;
|
||||||
|
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -479,9 +479,13 @@ Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
if (data) {
|
if (data) {
|
||||||
// If this is a registered custom element then fix the prototype.
|
// If this is a registered custom element then fix the prototype.
|
||||||
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
|
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
|
||||||
data->mType, &customProto);
|
data->GetCustomElementType(), &customProto);
|
||||||
if (customProto &&
|
if (customProto &&
|
||||||
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(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
|
// 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
|
// customProto to null to flag that we don't need to do any post-facto
|
||||||
// proto fixups here.
|
// proto fixups here.
|
||||||
|
@ -1595,7 +1599,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (aBindingParent) {
|
if (aBindingParent) {
|
||||||
nsDOMSlots *slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
|
|
||||||
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
|
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
|
||||||
}
|
}
|
||||||
|
@ -1618,7 +1622,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||||
}
|
}
|
||||||
ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
|
ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
|
||||||
if (parentContainingShadow) {
|
if (parentContainingShadow) {
|
||||||
DOMSlots()->mContainingShadow = parentContainingShadow;
|
ExtendedDOMSlots()->mContainingShadow = parentContainingShadow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1684,14 +1688,17 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||||
SetSubtreeRootPointer(aParent->SubtreeRoot());
|
SetSubtreeRootPointer(aParent->SubtreeRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIDocument* composedDoc = GetComposedDoc();
|
if (CustomElementRegistry::IsCustomElementEnabled() && IsInComposedDoc()) {
|
||||||
if (composedDoc) {
|
// Connected callback must be enqueued whenever a custom element becomes
|
||||||
// Attached callback must be enqueued whenever custom element is inserted into a
|
// connected.
|
||||||
// document and this document has a browsing context.
|
CustomElementData* data = GetCustomElementData();
|
||||||
if (GetCustomElementData() && composedDoc->GetDocShell()) {
|
if (data) {
|
||||||
// Enqueue an attached callback for the custom element.
|
if (data->mState == CustomElementData::State::eCustom) {
|
||||||
nsContentUtils::EnqueueLifecycleCallback(
|
nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this);
|
||||||
composedDoc, nsIDocument::eAttached, 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);
|
document->ClearBoxObjectFor(this);
|
||||||
|
|
||||||
// Detached must be enqueued whenever custom element is removed from
|
// Disconnected must be enqueued whenever a connected custom element becomes
|
||||||
// the document and this document has a browsing context.
|
// disconnected.
|
||||||
if (GetCustomElementData() && document->GetDocShell()) {
|
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||||
// Enqueue a detached callback for the custom element.
|
CustomElementData* data = GetCustomElementData();
|
||||||
nsContentUtils::EnqueueLifecycleCallback(
|
if (data) {
|
||||||
document, nsIDocument::eDetached, this);
|
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
|
#endif
|
||||||
|
|
||||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
if (clearBindingParent) {
|
if (clearBindingParent) {
|
||||||
slots->mBindingParent = nullptr;
|
slots->mBindingParent = nullptr;
|
||||||
|
@ -2055,7 +2071,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||||
nsICSSDeclaration*
|
nsICSSDeclaration*
|
||||||
Element::GetSMILOverrideStyle()
|
Element::GetSMILOverrideStyle()
|
||||||
{
|
{
|
||||||
Element::nsDOMSlots *slots = DOMSlots();
|
Element::nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
|
|
||||||
if (!slots->mSMILOverrideStyle) {
|
if (!slots->mSMILOverrideStyle) {
|
||||||
slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
|
slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
|
||||||
|
@ -2067,7 +2083,7 @@ Element::GetSMILOverrideStyle()
|
||||||
DeclarationBlock*
|
DeclarationBlock*
|
||||||
Element::GetSMILOverrideStyleDeclaration()
|
Element::GetSMILOverrideStyleDeclaration()
|
||||||
{
|
{
|
||||||
Element::nsDOMSlots *slots = GetExistingDOMSlots();
|
Element::nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
return slots ? slots->mSMILOverrideStyleDeclaration.get() : nullptr;
|
return slots ? slots->mSMILOverrideStyleDeclaration.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2075,7 +2091,7 @@ nsresult
|
||||||
Element::SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration,
|
Element::SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration,
|
||||||
bool aNotify)
|
bool aNotify)
|
||||||
{
|
{
|
||||||
Element::nsDOMSlots *slots = DOMSlots();
|
Element::nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
|
|
||||||
slots->mSMILOverrideStyleDeclaration = aDeclaration;
|
slots->mSMILOverrideStyleDeclaration = aDeclaration;
|
||||||
|
|
||||||
|
@ -2586,19 +2602,32 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||||
|
|
||||||
UpdateState(aNotify);
|
UpdateState(aNotify);
|
||||||
|
|
||||||
nsIDocument* ownerDoc = OwnerDoc();
|
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||||
if (ownerDoc && GetCustomElementData()) {
|
if (CustomElementData* data = GetCustomElementData()) {
|
||||||
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
|
if (CustomElementDefinition* definition =
|
||||||
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
nsContentUtils::GetElementDefinitionIfObservingAttr(this,
|
||||||
LifecycleCallbackArgs args = {
|
data->GetCustomElementType(),
|
||||||
nsDependentAtomString(aName),
|
aName)) {
|
||||||
aModType == nsIDOMMutationEvent::ADDITION ?
|
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
|
||||||
NullString() : nsDependentAtomString(oldValueAtom),
|
"AttributeChanged callback should fire only if "
|
||||||
nsDependentAtomString(newValueAtom)
|
"custom element state is custom");
|
||||||
};
|
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
|
||||||
|
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||||
|
nsAutoString ns;
|
||||||
|
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||||
|
|
||||||
nsContentUtils::EnqueueLifecycleCallback(
|
LifecycleCallbackArgs args = {
|
||||||
ownerDoc, nsIDocument::eAttributeChanged, this, &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) {
|
if (aCallAfterSetAttr) {
|
||||||
|
@ -2843,17 +2872,30 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||||
|
|
||||||
UpdateState(aNotify);
|
UpdateState(aNotify);
|
||||||
|
|
||||||
nsIDocument* ownerDoc = OwnerDoc();
|
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||||
if (ownerDoc && GetCustomElementData()) {
|
if (CustomElementData* data = GetCustomElementData()) {
|
||||||
nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom();
|
if (CustomElementDefinition* definition =
|
||||||
LifecycleCallbackArgs args = {
|
nsContentUtils::GetElementDefinitionIfObservingAttr(this,
|
||||||
nsDependentAtomString(aName),
|
data->GetCustomElementType(),
|
||||||
nsDependentAtomString(oldValueAtom),
|
aName)) {
|
||||||
NullString()
|
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);
|
||||||
|
|
||||||
nsContentUtils::EnqueueLifecycleCallback(
|
nsCOMPtr<nsIAtom> oldValueAtom = oldValue.GetAsAtom();
|
||||||
ownerDoc, nsIDocument::eAttributeChanged, this, &args);
|
LifecycleCallbackArgs args = {
|
||||||
|
nsDependentAtomString(aName),
|
||||||
|
nsDependentAtomString(oldValueAtom),
|
||||||
|
NullString(),
|
||||||
|
(ns.IsEmpty() ? NullString() : ns)
|
||||||
|
};
|
||||||
|
|
||||||
|
nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged,
|
||||||
|
this, &args, nullptr, definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aNotify) {
|
if (aNotify) {
|
||||||
|
@ -3988,7 +4030,7 @@ Element::ClearDataset()
|
||||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
|
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
|
||||||
Element::RegisteredIntersectionObservers()
|
Element::RegisteredIntersectionObservers()
|
||||||
{
|
{
|
||||||
nsDOMSlots* slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
return &slots->mRegisteredIntersectionObservers;
|
return &slots->mRegisteredIntersectionObservers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4037,3 +4079,31 @@ Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32
|
||||||
}
|
}
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -390,6 +390,45 @@ public:
|
||||||
|
|
||||||
Directionality GetComputedDirectionality() const;
|
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:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Method to get the _intrinsic_ content state of this element. This is the
|
* Method to get the _intrinsic_ content state of this element. This is the
|
||||||
|
@ -814,7 +853,7 @@ public:
|
||||||
|
|
||||||
ShadowRoot *FastGetShadowRoot() const
|
ShadowRoot *FastGetShadowRoot() const
|
||||||
{
|
{
|
||||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
return slots ? slots->mShadowRoot.get() : nullptr;
|
return slots ? slots->mShadowRoot.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -530,8 +530,7 @@ nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr)
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
FragmentOrElement::nsDOMSlots::nsDOMSlots()
|
FragmentOrElement::nsDOMSlots::nsDOMSlots()
|
||||||
: nsINode::nsSlots(),
|
: nsINode::nsSlots(),
|
||||||
mDataset(nullptr),
|
mDataset(nullptr)
|
||||||
mBindingParent(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,84 +542,104 @@ FragmentOrElement::nsDOMSlots::~nsDOMSlots()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL)
|
FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||||
{
|
{
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
|
||||||
cb.NoteXPCOMChild(mStyle.get());
|
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");
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
|
||||||
cb.NoteXPCOMChild(mAttributeMap.get());
|
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->mXBLBinding");
|
|
||||||
cb.NoteNativeChild(mXBLBinding, NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
|
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent");
|
|
||||||
cb.NoteXPCOMChild(mXBLInsertionParent.get());
|
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mShadowRoot");
|
|
||||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mShadowRoot));
|
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
|
|
||||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
|
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
|
||||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
|
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList");
|
|
||||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList));
|
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
|
||||||
cb.NoteXPCOMChild(mClassList.get());
|
cb.NoteXPCOMChild(mClassList.get());
|
||||||
|
|
||||||
if (mCustomElementData) {
|
if (!mExtendedSlots) {
|
||||||
for (uint32_t i = 0; i < mCustomElementData->mCallbackQueue.Length(); i++) {
|
return;
|
||||||
mCustomElementData->mCallbackQueue[i]->Traverse(cb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto iter = mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mSMILOverrideStyle");
|
||||||
|
cb.NoteXPCOMChild(mExtendedSlots->mSMILOverrideStyle.get());
|
||||||
|
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mControllers");
|
||||||
|
cb.NoteXPCOMChild(mExtendedSlots->mControllers);
|
||||||
|
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mLabelsList");
|
||||||
|
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*,mExtendedSlots-> mLabelsList));
|
||||||
|
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mShadowRoot");
|
||||||
|
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mShadowRoot));
|
||||||
|
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow");
|
||||||
|
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow));
|
||||||
|
|
||||||
|
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, "mExtendedSlots->mXBLInsertionParent");
|
||||||
|
cb.NoteXPCOMChild(mExtendedSlots->mXBLInsertionParent.get());
|
||||||
|
|
||||||
|
if (mExtendedSlots->mCustomElementData) {
|
||||||
|
mExtendedSlots->mCustomElementData->Traverse(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto iter = mExtendedSlots->mRegisteredIntersectionObservers.Iter();
|
||||||
|
!iter.Done(); iter.Next()) {
|
||||||
DOMIntersectionObserver* observer = iter.Key();
|
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);
|
cb.NoteXPCOMChild(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mFrameLoaderOrOpener");
|
||||||
|
cb.NoteXPCOMChild(mExtendedSlots->mFrameLoaderOrOpener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
|
FragmentOrElement::nsDOMSlots::Unlink()
|
||||||
{
|
{
|
||||||
mStyle = nullptr;
|
mStyle = nullptr;
|
||||||
mSMILOverrideStyle = nullptr;
|
|
||||||
if (mAttributeMap) {
|
if (mAttributeMap) {
|
||||||
mAttributeMap->DropReference();
|
mAttributeMap->DropReference();
|
||||||
mAttributeMap = nullptr;
|
mAttributeMap = nullptr;
|
||||||
}
|
}
|
||||||
if (aIsXUL)
|
|
||||||
NS_IF_RELEASE(mControllers);
|
|
||||||
|
|
||||||
MOZ_ASSERT(!mXBLBinding);
|
|
||||||
|
|
||||||
mXBLInsertionParent = nullptr;
|
|
||||||
mShadowRoot = nullptr;
|
|
||||||
mContainingShadow = nullptr;
|
|
||||||
mChildrenList = nullptr;
|
mChildrenList = nullptr;
|
||||||
mLabelsList = nullptr;
|
|
||||||
mCustomElementData = nullptr;
|
|
||||||
mClassList = 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
|
size_t
|
||||||
FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||||
{
|
{
|
||||||
size_t n = aMallocSizeOf(this);
|
size_t n = aMallocSizeOf(this);
|
||||||
|
if (mExtendedSlots) {
|
||||||
|
n += aMallocSizeOf(mExtendedSlots.get());
|
||||||
|
}
|
||||||
|
|
||||||
if (mAttributeMap) {
|
if (mAttributeMap) {
|
||||||
n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf);
|
n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf);
|
||||||
|
@ -641,6 +660,19 @@ FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) c
|
||||||
return n;
|
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)
|
FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||||
: nsIContent(aNodeInfo)
|
: nsIContent(aNodeInfo)
|
||||||
{
|
{
|
||||||
|
@ -962,7 +994,7 @@ FragmentOrElement::IsLink(nsIURI** aURI) const
|
||||||
nsIContent*
|
nsIContent*
|
||||||
FragmentOrElement::GetBindingParent() const
|
FragmentOrElement::GetBindingParent() const
|
||||||
{
|
{
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
|
|
||||||
if (slots) {
|
if (slots) {
|
||||||
return slots->mBindingParent;
|
return slots->mBindingParent;
|
||||||
|
@ -974,7 +1006,7 @@ nsXBLBinding*
|
||||||
FragmentOrElement::GetXBLBinding() const
|
FragmentOrElement::GetXBLBinding() const
|
||||||
{
|
{
|
||||||
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
return slots->mXBLBinding;
|
return slots->mXBLBinding;
|
||||||
}
|
}
|
||||||
|
@ -1009,11 +1041,11 @@ FragmentOrElement::SetXBLBinding(nsXBLBinding* aBinding,
|
||||||
|
|
||||||
if (aBinding) {
|
if (aBinding) {
|
||||||
SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
|
SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
|
||||||
nsDOMSlots *slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
slots->mXBLBinding = aBinding;
|
slots->mXBLBinding = aBinding;
|
||||||
bindingManager->AddBoundContent(this);
|
bindingManager->AddBoundContent(this);
|
||||||
} else {
|
} else {
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
slots->mXBLBinding = nullptr;
|
slots->mXBLBinding = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1028,7 +1060,7 @@ nsIContent*
|
||||||
FragmentOrElement::GetXBLInsertionParent() const
|
FragmentOrElement::GetXBLInsertionParent() const
|
||||||
{
|
{
|
||||||
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
return slots->mXBLInsertionParent;
|
return slots->mXBLInsertionParent;
|
||||||
}
|
}
|
||||||
|
@ -1040,7 +1072,7 @@ FragmentOrElement::GetXBLInsertionParent() const
|
||||||
ShadowRoot*
|
ShadowRoot*
|
||||||
FragmentOrElement::GetContainingShadow() const
|
FragmentOrElement::GetContainingShadow() const
|
||||||
{
|
{
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
return slots->mContainingShadow;
|
return slots->mContainingShadow;
|
||||||
}
|
}
|
||||||
|
@ -1050,21 +1082,21 @@ FragmentOrElement::GetContainingShadow() const
|
||||||
void
|
void
|
||||||
FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
|
FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
|
||||||
{
|
{
|
||||||
nsDOMSlots *slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
slots->mShadowRoot = aShadowRoot;
|
slots->mShadowRoot = aShadowRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsIContent*>&
|
nsTArray<nsIContent*>&
|
||||||
FragmentOrElement::DestInsertionPoints()
|
FragmentOrElement::DestInsertionPoints()
|
||||||
{
|
{
|
||||||
nsDOMSlots *slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
return slots->mDestInsertionPoints;
|
return slots->mDestInsertionPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsIContent*>*
|
nsTArray<nsIContent*>*
|
||||||
FragmentOrElement::GetExistingDestInsertionPoints() const
|
FragmentOrElement::GetExistingDestInsertionPoints() const
|
||||||
{
|
{
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
return &slots->mDestInsertionPoints;
|
return &slots->mDestInsertionPoints;
|
||||||
}
|
}
|
||||||
|
@ -1075,35 +1107,17 @@ void
|
||||||
FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent)
|
FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent)
|
||||||
{
|
{
|
||||||
if (aContent) {
|
if (aContent) {
|
||||||
nsDOMSlots *slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
|
SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
|
||||||
slots->mXBLInsertionParent = aContent;
|
slots->mXBLInsertionParent = aContent;
|
||||||
} else {
|
} else {
|
||||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
slots->mXBLInsertionParent = nullptr;
|
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
|
nsresult
|
||||||
FragmentOrElement::InsertChildAt(nsIContent* aKid,
|
FragmentOrElement::InsertChildAt(nsIContent* aKid,
|
||||||
uint32_t aIndex,
|
uint32_t aIndex,
|
||||||
|
@ -1366,14 +1380,15 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
|
||||||
{
|
{
|
||||||
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
if (tmp->IsElement()) {
|
if (slots->mExtendedSlots && tmp->IsElement()) {
|
||||||
Element* elem = tmp->AsElement();
|
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();
|
DOMIntersectionObserver* observer = iter.Key();
|
||||||
observer->UnlinkTarget(*elem);
|
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();
|
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
||||||
if (slots) {
|
if (slots) {
|
||||||
slots->Traverse(cb, tmp->IsXULElement());
|
slots->Traverse(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "nsAttrAndChildArray.h" // member
|
#include "nsAttrAndChildArray.h" // member
|
||||||
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
|
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
|
||||||
#include "nsIContent.h" // base class
|
#include "nsIContent.h" // base class
|
||||||
|
@ -37,6 +38,7 @@ class nsIURI;
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
class DeclarationBlock;
|
class DeclarationBlock;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
struct CustomElementData;
|
||||||
class DOMIntersectionObserver;
|
class DOMIntersectionObserver;
|
||||||
class Element;
|
class Element;
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
@ -159,9 +161,6 @@ public:
|
||||||
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
|
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
|
||||||
virtual bool IsLink(nsIURI** aURI) const 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 DestroyContent() override;
|
||||||
virtual void SaveSubtreeState() override;
|
virtual void SaveSubtreeState() override;
|
||||||
|
|
||||||
|
@ -241,8 +240,6 @@ protected:
|
||||||
nsresult CopyInnerTo(FragmentOrElement* aDest);
|
nsresult CopyInnerTo(FragmentOrElement* aDest);
|
||||||
|
|
||||||
public:
|
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
|
* There are a set of DOM- and scripting-specific instance variables
|
||||||
* that may only be instantiated when a content object is accessed
|
* 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
|
* in a side structure that's only allocated when the content is
|
||||||
* accessed through the DOM.
|
* accessed through the DOM.
|
||||||
*/
|
*/
|
||||||
class nsDOMSlots : public nsINode::nsSlots
|
|
||||||
|
class nsExtendedDOMSlots
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsDOMSlots();
|
nsExtendedDOMSlots();
|
||||||
virtual ~nsDOMSlots();
|
|
||||||
|
|
||||||
void Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL);
|
~nsExtendedDOMSlots();
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The .dataset attribute.
|
|
||||||
* @see nsGenericHTMLElement::GetDataset
|
|
||||||
*/
|
|
||||||
nsDOMStringMap* mDataset; // [Weak]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SMIL Overridde style rules (for SMIL animation of CSS properties)
|
* SMIL Overridde style rules (for SMIL animation of CSS properties)
|
||||||
|
@ -287,35 +268,17 @@ public:
|
||||||
RefPtr<mozilla::DeclarationBlock> mSMILOverrideStyleDeclaration;
|
RefPtr<mozilla::DeclarationBlock> mSMILOverrideStyleDeclaration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object implementing nsIDOMMozNamedAttrMap for this content (attributes)
|
* The nearest enclosing content node with a binding that created us.
|
||||||
* @see FragmentOrElement::GetAttributes
|
* @see FragmentOrElement::GetBindingParent
|
||||||
*/
|
*/
|
||||||
RefPtr<nsDOMAttributeMap> mAttributeMap;
|
nsIContent* mBindingParent; // [Weak]
|
||||||
|
|
||||||
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]
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object implementing the .children property for this element.
|
* The controllers of the XUL Element.
|
||||||
*/
|
*/
|
||||||
RefPtr<nsContentList> mChildrenList;
|
nsCOMPtr<nsIControllers> mControllers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object implementing the .classList property for this element.
|
|
||||||
*/
|
|
||||||
RefPtr<nsDOMTokenList> mClassList;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* An object implementing the .labels property for this element.
|
* An object implementing the .labels property for this element.
|
||||||
*/
|
*/
|
||||||
RefPtr<nsLabelsNodeList> mLabelsList;
|
RefPtr<nsLabelsNodeList> mLabelsList;
|
||||||
|
@ -356,6 +319,55 @@ public:
|
||||||
*/
|
*/
|
||||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
|
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
|
||||||
mRegisteredIntersectionObservers;
|
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:
|
protected:
|
||||||
|
@ -375,6 +387,26 @@ protected:
|
||||||
return static_cast<nsDOMSlots*>(GetExistingSlots());
|
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
|
* Calls SetIsElementInStyleScopeFlagOnSubtree for each shadow tree attached
|
||||||
* to this node, which is assumed to be an Element.
|
* to this node, which is assumed to be an Element.
|
||||||
|
|
|
@ -75,8 +75,8 @@ ShadowRoot::ShadowRoot(nsIContent* aContent,
|
||||||
|
|
||||||
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||||
|
|
||||||
DOMSlots()->mBindingParent = aContent;
|
ExtendedDOMSlots()->mBindingParent = aContent;
|
||||||
DOMSlots()->mContainingShadow = this;
|
ExtendedDOMSlots()->mContainingShadow = this;
|
||||||
|
|
||||||
// Add the ShadowRoot as a mutation observer on the host to watch
|
// Add the ShadowRoot as a mutation observer on the host to watch
|
||||||
// for mutations because the insertion points in this ShadowRoot
|
// for mutations because the insertion points in this ShadowRoot
|
||||||
|
|
|
@ -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>
|
|
@ -209,3 +209,4 @@ load 1230422.html
|
||||||
load 1251361.html
|
load 1251361.html
|
||||||
load 1304437.html
|
load 1304437.html
|
||||||
pref(clipboard.autocopy,true) load 1385272-1.html
|
pref(clipboard.autocopy,true) load 1385272-1.html
|
||||||
|
pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class Element;
|
class Element;
|
||||||
class NodeInfo;
|
class NodeInfo;
|
||||||
|
struct CustomElementDefinition;
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -41,7 +42,8 @@ nsresult
|
||||||
NS_NewHTMLElement(mozilla::dom::Element** aResult,
|
NS_NewHTMLElement(mozilla::dom::Element** aResult,
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||||
mozilla::dom::FromParser aFromParser,
|
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
|
// First argument should be nsHTMLTag, but that adds dependency to parser
|
||||||
// for a bunch of files.
|
// for a bunch of files.
|
||||||
|
|
|
@ -227,6 +227,7 @@ extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
|
||||||
int ns_aware, const char** colon);
|
int ns_aware, const char** colon);
|
||||||
|
|
||||||
class imgLoader;
|
class imgLoader;
|
||||||
|
class nsIAtom;
|
||||||
|
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
using namespace mozilla::ipc;
|
using namespace mozilla::ipc;
|
||||||
|
@ -258,7 +259,6 @@ nsIWordBreaker *nsContentUtils::sWordBreaker;
|
||||||
nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
|
nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
|
||||||
uint32_t nsContentUtils::sScriptBlockerCount = 0;
|
uint32_t nsContentUtils::sScriptBlockerCount = 0;
|
||||||
uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
|
uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
|
||||||
uint32_t nsContentUtils::sMicroTaskLevel = 0;
|
|
||||||
AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr;
|
AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr;
|
||||||
uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
|
uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
|
||||||
nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
|
nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
|
||||||
|
@ -284,6 +284,8 @@ bool nsContentUtils::sIsResourceTimingEnabled = false;
|
||||||
bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false;
|
bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false;
|
||||||
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
|
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
|
||||||
bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
|
bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
|
||||||
|
bool nsContentUtils::sIsWebComponentsEnabled = false;
|
||||||
|
bool nsContentUtils::sIsCustomElementsEnabled = false;
|
||||||
bool nsContentUtils::sEncodeDecodeURLHash = false;
|
bool nsContentUtils::sEncodeDecodeURLHash = false;
|
||||||
bool nsContentUtils::sGettersDecodeURLHash = false;
|
bool nsContentUtils::sGettersDecodeURLHash = false;
|
||||||
bool nsContentUtils::sPrivacyResistFingerprinting = false;
|
bool nsContentUtils::sPrivacyResistFingerprinting = false;
|
||||||
|
@ -584,6 +586,12 @@ nsContentUtils::Init()
|
||||||
Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled,
|
Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled,
|
||||||
"dom.forms.autocomplete.experimental", false);
|
"dom.forms.autocomplete.experimental", false);
|
||||||
|
|
||||||
|
Preferences::AddBoolVarCache(&sIsWebComponentsEnabled,
|
||||||
|
"dom.webcomponents.enabled", false);
|
||||||
|
|
||||||
|
Preferences::AddBoolVarCache(&sIsCustomElementsEnabled,
|
||||||
|
"dom.webcomponents.customelements.enabled", false);
|
||||||
|
|
||||||
Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
|
Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
|
||||||
"dom.url.encode_decode_hash", false);
|
"dom.url.encode_decode_hash", false);
|
||||||
|
|
||||||
|
@ -5293,51 +5301,6 @@ nsContentUtils::RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable)
|
||||||
CycleCollectedJSContext::Get()->RunInMetastableState(Move(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.
|
* Helper function for nsContentUtils::ProcessViewportInfo.
|
||||||
*
|
*
|
||||||
|
@ -9567,11 +9530,34 @@ nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument)
|
||||||
return false;
|
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*
|
/* static */ CustomElementDefinition*
|
||||||
nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
|
nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
|
||||||
const nsAString& aLocalName,
|
nsIAtom* aNameAtom,
|
||||||
uint32_t aNameSpaceID,
|
uint32_t aNameSpaceID,
|
||||||
const nsAString* aIs)
|
nsIAtom* aTypeAtom)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aDoc);
|
MOZ_ASSERT(aDoc);
|
||||||
|
|
||||||
|
@ -9593,30 +9579,16 @@ nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return registry->LookupCustomElementDefinition(aLocalName, aIs);
|
return registry->LookupCustomElementDefinition(aNameAtom, aTypeAtom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
nsContentUtils::SetupCustomElement(Element* aElement,
|
nsContentUtils::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
|
||||||
const nsAString* aTypeExtension)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aElement);
|
MOZ_ASSERT(aElement);
|
||||||
|
|
||||||
nsCOMPtr<nsIDocument> doc = aElement->OwnerDoc();
|
nsIDocument* doc = aElement->OwnerDoc();
|
||||||
|
nsPIDOMWindowInner* window(doc->GetInnerWindow());
|
||||||
if (!doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To support imported document.
|
|
||||||
doc = doc->MasterDocument();
|
|
||||||
|
|
||||||
if (aElement->GetNameSpaceID() != kNameSpaceID_XHTML ||
|
|
||||||
!doc->GetDocShell()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -9626,26 +9598,18 @@ nsContentUtils::SetupCustomElement(Element* aElement,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return registry->SetupCustomElement(aElement, aTypeExtension);
|
registry->RegisterUnresolvedElement(aElement, aTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc,
|
nsContentUtils::UnregisterUnresolvedElement(Element* aElement)
|
||||||
nsIDocument::ElementCallbackType aType,
|
|
||||||
Element* aCustomElement,
|
|
||||||
LifecycleCallbackArgs* aArgs,
|
|
||||||
CustomElementDefinition* aDefinition)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aDoc);
|
MOZ_ASSERT(aElement);
|
||||||
|
|
||||||
// To support imported document.
|
RefPtr<nsIAtom> typeAtom =
|
||||||
nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
|
aElement->GetCustomElementData()->GetCustomElementType();
|
||||||
|
nsIDocument* doc = aElement->OwnerDoc();
|
||||||
if (!doc->GetDocShell()) {
|
nsPIDOMWindowInner* window(doc->GetInnerWindow());
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -9655,7 +9619,59 @@ nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
registry->EnqueueLifecycleCallback(aType, aCustomElement, aArgs, aDefinition);
|
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::EnqueueUpgradeReaction(Element* aElement,
|
||||||
|
CustomElementDefinition* aDefinition)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aElement);
|
||||||
|
|
||||||
|
nsIDocument* doc = aElement->OwnerDoc();
|
||||||
|
|
||||||
|
// No DocGroup means no custom element reactions stack.
|
||||||
|
if (!doc->GetDocGroup()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomElementReactionsStack* stack =
|
||||||
|
doc->GetDocGroup()->CustomElementReactionsStack();
|
||||||
|
stack->EnqueueUpgradeReaction(aElement, aDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomElementRegistry::EnqueueLifecycleCallback(aType, aCustomElement, aArgs,
|
||||||
|
aAdoptedCallbackArgs,
|
||||||
|
aDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
|
@ -9834,4 +9850,4 @@ nsContentUtils::IsLocalRefURL(const nsString& aString)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,7 @@ class EventTarget;
|
||||||
class IPCDataTransfer;
|
class IPCDataTransfer;
|
||||||
class IPCDataTransferItem;
|
class IPCDataTransferItem;
|
||||||
struct LifecycleCallbackArgs;
|
struct LifecycleCallbackArgs;
|
||||||
|
struct LifecycleAdoptedCallbackArgs;
|
||||||
class NodeInfo;
|
class NodeInfo;
|
||||||
class nsIContentChild;
|
class nsIContentChild;
|
||||||
class nsIContentParent;
|
class nsIContentParent;
|
||||||
|
@ -1739,17 +1740,6 @@ public:
|
||||||
*/
|
*/
|
||||||
static void RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable);
|
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
|
/* Process viewport META data. This gives us information for the scale
|
||||||
* and zoom of a page on mobile devices. We stick the information in
|
* and zoom of a page on mobile devices. We stick the information in
|
||||||
* the document header and use it later on after rendering.
|
* the document header and use it later on after rendering.
|
||||||
|
@ -2710,23 +2700,37 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool HttpsStateIsModern(nsIDocument* aDocument);
|
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.
|
* Looking up a custom element definition.
|
||||||
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition
|
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition
|
||||||
*/
|
*/
|
||||||
static mozilla::dom::CustomElementDefinition*
|
static mozilla::dom::CustomElementDefinition*
|
||||||
LookupCustomElementDefinition(nsIDocument* aDoc,
|
LookupCustomElementDefinition(nsIDocument* aDoc,
|
||||||
const nsAString& aLocalName,
|
nsIAtom* aNameAtom,
|
||||||
uint32_t aNameSpaceID,
|
uint32_t aNameSpaceID,
|
||||||
const nsAString* aIs = nullptr);
|
nsIAtom* aTypeAtom);
|
||||||
|
|
||||||
static void SetupCustomElement(Element* aElement,
|
static void RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName);
|
||||||
const nsAString* aTypeExtension = nullptr);
|
static void UnregisterUnresolvedElement(Element* aElement);
|
||||||
|
|
||||||
static void EnqueueLifecycleCallback(nsIDocument* aDoc,
|
static mozilla::dom::CustomElementDefinition*
|
||||||
nsIDocument::ElementCallbackType aType,
|
GetElementDefinitionIfObservingAttr(Element* aCustomElement,
|
||||||
|
nsIAtom* aExtensionType,
|
||||||
|
nsIAtom* aAttrName);
|
||||||
|
|
||||||
|
static void EnqueueUpgradeReaction(Element* aElement,
|
||||||
|
mozilla::dom::CustomElementDefinition* aDefinition);
|
||||||
|
|
||||||
|
static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
||||||
Element* aCustomElement,
|
Element* aCustomElement,
|
||||||
mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
|
mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
|
||||||
|
mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr,
|
||||||
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
|
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
|
||||||
|
|
||||||
static void GetCustomPrototype(nsIDocument* aDoc,
|
static void GetCustomPrototype(nsIDocument* aDoc,
|
||||||
|
@ -2743,6 +2747,12 @@ public:
|
||||||
static bool
|
static bool
|
||||||
IsLocalRefURL(const nsString& aString);
|
IsLocalRefURL(const nsString& aString);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsWebComponentsEnabled() { return sIsWebComponentsEnabled; }
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool InitializeEventTable();
|
static bool InitializeEventTable();
|
||||||
|
|
||||||
|
@ -2829,7 +2839,6 @@ private:
|
||||||
static bool sInitialized;
|
static bool sInitialized;
|
||||||
static uint32_t sScriptBlockerCount;
|
static uint32_t sScriptBlockerCount;
|
||||||
static uint32_t sDOMNodeRemovedSuppressCount;
|
static uint32_t sDOMNodeRemovedSuppressCount;
|
||||||
static uint32_t sMicroTaskLevel;
|
|
||||||
// Not an nsCOMArray because removing elements from those is slower
|
// Not an nsCOMArray because removing elements from those is slower
|
||||||
static AutoTArray<nsCOMPtr<nsIRunnable>, 8>* sBlockedScriptRunners;
|
static AutoTArray<nsCOMPtr<nsIRunnable>, 8>* sBlockedScriptRunners;
|
||||||
static uint32_t sRunnersCountAtFirstBlocker;
|
static uint32_t sRunnersCountAtFirstBlocker;
|
||||||
|
@ -2850,6 +2859,8 @@ private:
|
||||||
static bool sIsUserTimingLoggingEnabled;
|
static bool sIsUserTimingLoggingEnabled;
|
||||||
static bool sIsFrameTimingPrefEnabled;
|
static bool sIsFrameTimingPrefEnabled;
|
||||||
static bool sIsExperimentalAutocompleteEnabled;
|
static bool sIsExperimentalAutocompleteEnabled;
|
||||||
|
static bool sIsWebComponentsEnabled;
|
||||||
|
static bool sIsCustomElementsEnabled;
|
||||||
static bool sEncodeDecodeURLHash;
|
static bool sEncodeDecodeURLHash;
|
||||||
static bool sGettersDecodeURLHash;
|
static bool sGettersDecodeURLHash;
|
||||||
static bool sPrivacyResistFingerprinting;
|
static bool sPrivacyResistFingerprinting;
|
||||||
|
@ -2905,19 +2916,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MOZ_STACK_CLASS nsAutoMicroTask
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
nsAutoMicroTask()
|
|
||||||
{
|
|
||||||
nsContentUtils::EnterMicroTask();
|
|
||||||
}
|
|
||||||
~nsAutoMicroTask()
|
|
||||||
{
|
|
||||||
nsContentUtils::LeaveMicroTask();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,6 @@ using mozilla::dom::Element;
|
||||||
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
|
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
|
||||||
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
|
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
|
||||||
|
|
||||||
nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
|
|
||||||
|
|
||||||
uint32_t nsDOMMutationObserver::sMutationLevel = 0;
|
uint32_t nsDOMMutationObserver::sMutationLevel = 0;
|
||||||
uint64_t nsDOMMutationObserver::sCount = 0;
|
uint64_t nsDOMMutationObserver::sCount = 0;
|
||||||
|
|
||||||
|
@ -597,10 +595,32 @@ nsDOMMutationObserver::ScheduleForRun()
|
||||||
RescheduleForRun();
|
RescheduleForRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MutationObserverMicroTask final : public MicroTaskRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void Run(AutoSlowOperation& aAso) override
|
||||||
|
{
|
||||||
|
nsDOMMutationObserver::HandleMutations(aAso);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Suppressed() override
|
||||||
|
{
|
||||||
|
return nsDOMMutationObserver::AllScheduledMutationObserversAreSuppressed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDOMMutationObserver::RescheduleForRun()
|
nsDOMMutationObserver::RescheduleForRun()
|
||||||
{
|
{
|
||||||
if (!sScheduledMutationObservers) {
|
if (!sScheduledMutationObservers) {
|
||||||
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (!ccjs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<MutationObserverMicroTask> momt =
|
||||||
|
new MutationObserverMicroTask();
|
||||||
|
ccjs->DispatchMicroTaskRunnable(momt.forget());
|
||||||
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
|
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -862,36 +882,9 @@ nsDOMMutationObserver::HandleMutation()
|
||||||
mCallback->Call(this, mutations, *this);
|
mCallback->Call(this, mutations, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncMutationHandler : public mozilla::Runnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
nsDOMMutationObserver::HandleMutations();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
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;
|
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
|
||||||
|
|
||||||
while (sScheduledMutationObservers) {
|
while (sScheduledMutationObservers) {
|
||||||
|
@ -899,20 +892,21 @@ nsDOMMutationObserver::HandleMutationsInternal()
|
||||||
sScheduledMutationObservers;
|
sScheduledMutationObservers;
|
||||||
sScheduledMutationObservers = nullptr;
|
sScheduledMutationObservers = nullptr;
|
||||||
for (uint32_t i = 0; i < observers->Length(); ++i) {
|
for (uint32_t i = 0; i < observers->Length(); ++i) {
|
||||||
sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]);
|
RefPtr<nsDOMMutationObserver> currentObserver =
|
||||||
if (!sCurrentObserver->Suppressed()) {
|
static_cast<nsDOMMutationObserver*>((*observers)[i]);
|
||||||
sCurrentObserver->HandleMutation();
|
if (!currentObserver->Suppressed()) {
|
||||||
|
currentObserver->HandleMutation();
|
||||||
} else {
|
} else {
|
||||||
if (!suppressedObservers) {
|
if (!suppressedObservers) {
|
||||||
suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >;
|
suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >;
|
||||||
}
|
}
|
||||||
if (!suppressedObservers->Contains(sCurrentObserver)) {
|
if (!suppressedObservers->Contains(currentObserver)) {
|
||||||
suppressedObservers->AppendElement(sCurrentObserver);
|
suppressedObservers->AppendElement(currentObserver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete observers;
|
delete observers;
|
||||||
aso.CheckForInterrupt();
|
aAso.CheckForInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (suppressedObservers) {
|
if (suppressedObservers) {
|
||||||
|
@ -923,7 +917,6 @@ nsDOMMutationObserver::HandleMutationsInternal()
|
||||||
delete suppressedObservers;
|
delete suppressedObservers;
|
||||||
suppressedObservers = nullptr;
|
suppressedObservers = nullptr;
|
||||||
}
|
}
|
||||||
sCurrentObserver = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsDOMMutationRecord*
|
nsDOMMutationRecord*
|
||||||
|
|
|
@ -552,13 +552,29 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// static methods
|
// static methods
|
||||||
static void HandleMutations()
|
static void HandleMutations(mozilla::AutoSlowOperation& aAso)
|
||||||
{
|
{
|
||||||
if (sScheduledMutationObservers) {
|
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 EnterMutationHandling();
|
||||||
static void LeaveMutationHandling();
|
static void LeaveMutationHandling();
|
||||||
|
|
||||||
|
@ -594,7 +610,7 @@ protected:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleMutationsInternal();
|
static void HandleMutationsInternal(mozilla::AutoSlowOperation& aAso);
|
||||||
|
|
||||||
static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
|
static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
|
||||||
uint32_t aMutationLevel);
|
uint32_t aMutationLevel);
|
||||||
|
@ -622,7 +638,6 @@ protected:
|
||||||
|
|
||||||
static uint64_t sCount;
|
static uint64_t sCount;
|
||||||
static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers;
|
static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers;
|
||||||
static nsDOMMutationObserver* sCurrentObserver;
|
|
||||||
|
|
||||||
static uint32_t sMutationLevel;
|
static uint32_t sMutationLevel;
|
||||||
static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*
|
static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*
|
||||||
|
|
|
@ -1329,7 +1329,8 @@ nsIDocument::nsIDocument()
|
||||||
mFrameRequestCallbacksScheduled(false),
|
mFrameRequestCallbacksScheduled(false),
|
||||||
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
|
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
|
||||||
mPartID(0),
|
mPartID(0),
|
||||||
mUserHasInteracted(false)
|
mUserHasInteracted(false),
|
||||||
|
mThrowOnDynamicMarkupInsertionCounter(0)
|
||||||
{
|
{
|
||||||
SetIsInDocument();
|
SetIsInDocument();
|
||||||
|
|
||||||
|
@ -5395,18 +5396,14 @@ nsDocument::CreateElement(const nsAString& aTagName,
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsString* is = nullptr;
|
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(
|
RefPtr<Element> elem = CreateElem(
|
||||||
needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
|
needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
|
||||||
|
|
||||||
|
if (is) {
|
||||||
|
elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
|
||||||
|
}
|
||||||
|
|
||||||
return elem.forget();
|
return elem.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5443,14 +5440,6 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsString* is = nullptr;
|
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;
|
nsCOMPtr<Element> element;
|
||||||
rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
|
rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
|
||||||
|
@ -5459,6 +5448,10 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is) {
|
||||||
|
element->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
|
||||||
|
}
|
||||||
|
|
||||||
return element.forget();
|
return element.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5681,24 +5674,70 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
|
nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
|
||||||
CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom);
|
CustomElementDefinition* definition =
|
||||||
|
registry->mCustomDefinitions.GetWeak(typeAtom);
|
||||||
if (!definition) {
|
if (!definition) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsDependentAtomString localName(definition->mLocalName);
|
RefPtr<Element> element;
|
||||||
|
|
||||||
nsCOMPtr<Element> element =
|
// We integrate with construction stack and do prototype swizzling here, so
|
||||||
document->CreateElem(localName, nullptr, kNameSpaceID_XHTML);
|
// that old upgrade behavior could also share the new upgrade steps.
|
||||||
NS_ENSURE_TRUE(element, true);
|
// 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);
|
||||||
|
|
||||||
if (definition->mLocalName != typeAtom) {
|
// Do prototype swizzling if dom reflector exists.
|
||||||
// This element is a custom element by extension, thus we need to
|
JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
|
||||||
// do some special setup. For non-extended custom elements, this happens
|
if (reflector) {
|
||||||
// when the element is created.
|
Maybe<JSAutoCompartment> ac;
|
||||||
nsContentUtils::SetupCustomElement(element, &elemName);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap into current context.
|
||||||
|
if (!JS_WrapObject(aCx, &reflector)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
|
||||||
NS_ENSURE_SUCCESS(rv, true);
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
|
|
||||||
|
@ -5710,7 +5749,7 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
|
||||||
{
|
{
|
||||||
JS::Rooted<JSObject*> obj(aCx, aObject);
|
JS::Rooted<JSObject*> obj(aCx, aObject);
|
||||||
|
|
||||||
if (Preferences::GetBool("dom.webcomponents.enabled")) {
|
if (nsContentUtils::IsWebComponentsEnabled()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5726,7 +5765,7 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
|
||||||
bool
|
bool
|
||||||
nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
|
nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
|
||||||
{
|
{
|
||||||
if (Preferences::GetBool("dom.webcomponents.enabled")) {
|
if (nsContentUtils::IsWebComponentsEnabled()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5770,6 +5809,8 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(),
|
||||||
|
aCx);
|
||||||
// Unconditionally convert TYPE to lowercase.
|
// Unconditionally convert TYPE to lowercase.
|
||||||
nsAutoString lcType;
|
nsAutoString lcType;
|
||||||
nsContentUtils::ASCIIToLower(aType, lcType);
|
nsContentUtils::ASCIIToLower(aType, lcType);
|
||||||
|
@ -6536,6 +6577,49 @@ nsIDocument::GetHtmlChildElement(nsIAtom* aTag)
|
||||||
return nullptr;
|
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*
|
Element*
|
||||||
nsDocument::GetTitleElement()
|
nsDocument::GetTitleElement()
|
||||||
{
|
{
|
||||||
|
@ -12526,8 +12610,12 @@ MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
|
||||||
|
|
||||||
nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
|
nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
|
||||||
{
|
{
|
||||||
mMicroTaskLevel = nsContentUtils::MicroTaskLevel();
|
mMicroTaskLevel = 0;
|
||||||
nsContentUtils::SetMicroTaskLevel(0);
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
mMicroTaskLevel = ccjs->MicroTaskLevel();
|
||||||
|
ccjs->SetMicroTaskLevel(0);
|
||||||
|
}
|
||||||
if (aDoc) {
|
if (aDoc) {
|
||||||
if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
|
if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
|
||||||
if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) {
|
if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) {
|
||||||
|
@ -12543,7 +12631,10 @@ nsAutoSyncOperation::~nsAutoSyncOperation()
|
||||||
for (int32_t i = 0; i < mDocuments.Count(); ++i) {
|
for (int32_t i = 0; i < mDocuments.Count(); ++i) {
|
||||||
mDocuments[i]->SetIsInSyncOperation(false);
|
mDocuments[i]->SetIsInSyncOperation(false);
|
||||||
}
|
}
|
||||||
nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel);
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->SetMicroTaskLevel(mMicroTaskLevel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxUserFontSet*
|
gfxUserFontSet*
|
||||||
|
@ -12713,30 +12804,6 @@ nsIDocument::UpdateStyleBackendType()
|
||||||
#endif
|
#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*
|
Selection*
|
||||||
nsIDocument::GetSelection(ErrorResult& aRv)
|
nsIDocument::GetSelection(ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1388,20 +1388,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
|
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:
|
public:
|
||||||
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
|
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||||
GetCustomElementRegistry() override;
|
GetCustomElementRegistry() override;
|
||||||
|
|
|
@ -793,17 +793,6 @@ nsGenericDOMDataNode::SetXBLInsertionParent(nsIContent* aContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomElementData *
|
|
||||||
nsGenericDOMDataNode::GetCustomElementData() const
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsGenericDOMDataNode::SetCustomElementData(CustomElementData* aData)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const
|
nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -162,9 +162,6 @@ public:
|
||||||
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
||||||
virtual bool IsLink(nsIURI** aURI) 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 WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
|
||||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
||||||
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||||
|
|
|
@ -4241,8 +4241,9 @@ CustomElementRegistry*
|
||||||
nsGlobalWindow::CustomElements()
|
nsGlobalWindow::CustomElements()
|
||||||
{
|
{
|
||||||
MOZ_RELEASE_ASSERT(IsInnerWindow());
|
MOZ_RELEASE_ASSERT(IsInnerWindow());
|
||||||
|
|
||||||
if (!mCustomElements) {
|
if (!mCustomElements) {
|
||||||
mCustomElements = CustomElementRegistry::Create(AsInner());
|
mCustomElements = new CustomElementRegistry(AsInner());
|
||||||
}
|
}
|
||||||
|
|
||||||
return mCustomElements;
|
return mCustomElements;
|
||||||
|
|
|
@ -26,7 +26,6 @@ namespace mozilla {
|
||||||
class EventChainPreVisitor;
|
class EventChainPreVisitor;
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class ShadowRoot;
|
class ShadowRoot;
|
||||||
struct CustomElementData;
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
namespace widget {
|
namespace widget {
|
||||||
struct IMEState;
|
struct IMEState;
|
||||||
|
@ -729,22 +728,6 @@ public:
|
||||||
*/
|
*/
|
||||||
nsINode *GetFlattenedTreeParentNodeInternal() const;
|
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
|
* 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
|
* (e.g. a click event). Specializations for HTML/SVG/generic XML allow for
|
||||||
|
|
|
@ -61,6 +61,7 @@ class nsFrameLoader;
|
||||||
class nsHTMLCSSStyleSheet;
|
class nsHTMLCSSStyleSheet;
|
||||||
class nsHTMLDocument;
|
class nsHTMLDocument;
|
||||||
class nsHTMLStyleSheet;
|
class nsHTMLStyleSheet;
|
||||||
|
class nsGenericHTMLElement;
|
||||||
class nsIAtom;
|
class nsIAtom;
|
||||||
class nsIBFCacheEntry;
|
class nsIBFCacheEntry;
|
||||||
class nsIChannel;
|
class nsIChannel;
|
||||||
|
@ -1036,6 +1037,11 @@ public:
|
||||||
Element* GetHeadElement() {
|
Element* GetHeadElement() {
|
||||||
return GetHtmlChildElement(nsGkAtoms::head);
|
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.
|
* Accessors to the collection of stylesheets owned by this document.
|
||||||
|
@ -2573,9 +2579,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ElementCallbackType {
|
enum ElementCallbackType {
|
||||||
eCreated,
|
eConnected,
|
||||||
eAttached,
|
eDisconnected,
|
||||||
eDetached,
|
eAdopted,
|
||||||
eAttributeChanged
|
eAttributeChanged
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2872,6 +2878,22 @@ public:
|
||||||
virtual void ScheduleIntersectionObserverNotification() = 0;
|
virtual void ScheduleIntersectionObserverNotification() = 0;
|
||||||
virtual void NotifyIntersectionObservers() = 0;
|
virtual void NotifyIntersectionObservers() = 0;
|
||||||
|
|
||||||
|
bool ShouldThrowOnDynamicMarkupInsertion()
|
||||||
|
{
|
||||||
|
return mThrowOnDynamicMarkupInsertionCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncrementThrowOnDynamicMarkupInsertionCounter()
|
||||||
|
{
|
||||||
|
++mThrowOnDynamicMarkupInsertionCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecrementThrowOnDynamicMarkupInsertionCounter()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mThrowOnDynamicMarkupInsertionCounter);
|
||||||
|
--mThrowOnDynamicMarkupInsertionCounter;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||||
{
|
{
|
||||||
|
@ -3319,6 +3341,11 @@ protected:
|
||||||
|
|
||||||
uint32_t mBlockDOMContentLoaded;
|
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
|
// Our live MediaQueryLists
|
||||||
PRCList mDOMMediaQueryLists;
|
PRCList mDOMMediaQueryLists;
|
||||||
|
|
||||||
|
@ -3392,6 +3419,23 @@ private:
|
||||||
uint32_t mMicroTaskLevel;
|
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
|
// XXX These belong somewhere else
|
||||||
nsresult
|
nsresult
|
||||||
NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false);
|
NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
|
#include "mozilla/CycleCollectedJSContext.h"
|
||||||
#include "mozilla/dom/BindingUtils.h"
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
#include "mozilla/dom/Date.h"
|
#include "mozilla/dom/Date.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
|
@ -159,7 +159,8 @@ nsJSUtils::EvaluateString(JSContext* aCx,
|
||||||
aEvaluationGlobal);
|
aEvaluationGlobal);
|
||||||
MOZ_ASSERT_IF(aOffThreadToken, aCompileOptions.noScriptRval);
|
MOZ_ASSERT_IF(aOffThreadToken, aCompileOptions.noScriptRval);
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
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
|
// 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
|
// in a different, less efficient way. Furthermore, it can't JIT them in many
|
||||||
|
@ -293,7 +294,8 @@ nsJSUtils::CompileModule(JSContext* aCx,
|
||||||
aEvaluationGlobal);
|
aEvaluationGlobal);
|
||||||
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
|
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
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);
|
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(aCx == nsContentUtils::GetCurrentJSContext());
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
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);
|
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
||||||
|
|
||||||
|
|
|
@ -301,9 +301,12 @@ nsNodeUtils::LastRelease(nsINode* aNode)
|
||||||
Element* elem = aNode->AsElement();
|
Element* elem = aNode->AsElement();
|
||||||
FragmentOrElement::nsDOMSlots* domSlots =
|
FragmentOrElement::nsDOMSlots* domSlots =
|
||||||
static_cast<FragmentOrElement::nsDOMSlots*>(slots);
|
static_cast<FragmentOrElement::nsDOMSlots*>(slots);
|
||||||
for (auto iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
|
if (domSlots->mExtendedSlots) {
|
||||||
DOMIntersectionObserver* observer = iter.Key();
|
for (auto iter = domSlots->mExtendedSlots->mRegisteredIntersectionObservers.Iter();
|
||||||
observer->UnlinkTarget(*elem);
|
!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));
|
rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (clone->IsElement()) {
|
if (CustomElementRegistry::IsCustomElementEnabled() &&
|
||||||
|
clone->IsHTMLElement()) {
|
||||||
// The cloned node may be a custom element that may require
|
// The cloned node may be a custom element that may require
|
||||||
// enqueing created callback and prototype swizzling.
|
// enqueing upgrade reaction.
|
||||||
Element* elem = clone->AsElement();
|
Element* cloneElem = clone->AsElement();
|
||||||
if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) {
|
RefPtr<nsIAtom> tagAtom = nodeInfo->NameAtom();
|
||||||
nsContentUtils::SetupCustomElement(elem);
|
CustomElementData* data = elem->GetCustomElementData();
|
||||||
} else {
|
|
||||||
// Check if node may be custom element by type extension.
|
// Check if node may be custom element by type extension.
|
||||||
// ex. <button is="x-button">
|
// ex. <button is="x-button">
|
||||||
nsAutoString extension;
|
nsAutoString extension;
|
||||||
if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) &&
|
if (!data || data->GetCustomElementType() != tagAtom) {
|
||||||
!extension.IsEmpty()) {
|
cloneElem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension);
|
||||||
nsContentUtils::SetupCustomElement(elem, &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();
|
nsIDocument* newDoc = aNode->OwnerDoc();
|
||||||
if (newDoc) {
|
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
|
// XXX what if oldDoc is null, we don't know if this should be
|
||||||
// registered or not! Can that really happen?
|
// registered or not! Can that really happen?
|
||||||
if (wasRegistered) {
|
if (wasRegistered) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
var proto = Object.create(HTMLElement.prototype);
|
var proto = Object.create(HTMLElement.prototype);
|
||||||
proto.magicNumber = 42;
|
proto.magicNumber = 42;
|
||||||
proto.createdCallback = function() {
|
proto.connectedCallback = function() {
|
||||||
finishTest(this.magicNumber === 42);
|
finishTest(this.magicNumber === 42);
|
||||||
};
|
};
|
||||||
document.registerElement("x-foo", { prototype: proto });
|
document.registerElement("x-foo", { prototype: proto });
|
||||||
|
|
||||||
document.createElement("x-foo");
|
document.firstChild.appendChild(document.createElement("x-foo"));
|
||||||
|
|
|
@ -21,19 +21,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
||||||
<script type="application/javascript"><![CDATA[
|
<script type="application/javascript"><![CDATA[
|
||||||
|
|
||||||
/** Test for Bug 1130028 **/
|
/** Test for Bug 1130028 **/
|
||||||
SimpleTest.waitForExplicitFinish();
|
var connectedCallbackCount = 0;
|
||||||
|
|
||||||
var createdCallbackCount = 0;
|
// Callback should be called only once by element created in content.
|
||||||
|
function connectedCallbackCalled() {
|
||||||
// Callback should be called once by element created in chrome,
|
connectedCallbackCount++;
|
||||||
// and once by element created in content.
|
is(connectedCallbackCount, 1, "Connected callback called, should be called once in test.");
|
||||||
function createdCallbackCalled() {
|
|
||||||
createdCallbackCount++;
|
|
||||||
ok(true, "Created callback called, should be called twice in test.");
|
|
||||||
is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
|
is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
|
||||||
if (createdCallbackCount == 2) {
|
|
||||||
SimpleTest.finish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function startTests() {
|
function startTests() {
|
||||||
|
@ -45,10 +39,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
||||||
|
|
||||||
var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
|
var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
|
||||||
proto.magicNumber = 42;
|
proto.magicNumber = 42;
|
||||||
proto.createdCallback = createdCallbackCalled;
|
proto.connectedCallback = connectedCallbackCalled;
|
||||||
frame.contentDocument.registerElement("x-bar", { prototype: proto });
|
|
||||||
|
|
||||||
frame.contentDocument.createElement("x-bar");
|
frame.contentDocument.registerElement("x-bar", { prototype: proto });
|
||||||
|
is(connectedCallbackCount, 1, "Connected callback should be called by element created in content.");
|
||||||
|
|
||||||
|
var element = frame.contentDocument.createElement("x-bar");
|
||||||
|
is(element.magicNumber, 42, "Should be able to see the custom prototype on created element.");
|
||||||
}
|
}
|
||||||
|
|
||||||
]]></script>
|
]]></script>
|
||||||
|
|
|
@ -26,8 +26,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
function finishTest(canSeePrototype) {
|
function finishTest(canSeePrototype) {
|
||||||
ok(true, "createdCallback called when reigsterElement was called with an extended principal.");
|
ok(true, "connectedCallback called when reigsterElement was called with an extended principal.");
|
||||||
ok(canSeePrototype, "createdCallback should be able to see custom prototype.");
|
ok(canSeePrototype, "connectedCallback should be able to see custom prototype.");
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,7 +362,7 @@ function testChildList5() {
|
||||||
is(records[5].previousSibling, c3, "");
|
is(records[5].previousSibling, c3, "");
|
||||||
is(records[5].nextSibling, c5, "");
|
is(records[5].nextSibling, c5, "");
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
then(testAdoptNode);
|
then(testNestedMutations);
|
||||||
m = null;
|
m = null;
|
||||||
});
|
});
|
||||||
m.observe(div, { childList: true, subtree: true });
|
m.observe(div, { childList: true, subtree: true });
|
||||||
|
@ -375,6 +375,37 @@ function testChildList5() {
|
||||||
div.appendChild(emptyDF); // empty document shouldn't cause mutation records
|
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() {
|
function testAdoptNode() {
|
||||||
var d1 = document.implementation.createHTMLDocument(null);
|
var d1 = document.implementation.createHTMLDocument(null);
|
||||||
var d2 = document.implementation.createHTMLDocument(null);
|
var d2 = document.implementation.createHTMLDocument(null);
|
||||||
|
|
|
@ -16,13 +16,16 @@
|
||||||
#include "mozilla/SizePrintfMacros.h"
|
#include "mozilla/SizePrintfMacros.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "mozilla/UseCounter.h"
|
#include "mozilla/UseCounter.h"
|
||||||
|
#include "mozilla/dom/DocGroup.h"
|
||||||
|
|
||||||
#include "AccessCheck.h"
|
#include "AccessCheck.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
|
#include "nsContentCreatorFunctions.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsIDocShell.h"
|
#include "nsIDocShell.h"
|
||||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||||
|
#include "nsIParserService.h"
|
||||||
#include "nsIPermissionManager.h"
|
#include "nsIPermissionManager.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsIXPConnect.h"
|
#include "nsIXPConnect.h"
|
||||||
|
@ -37,6 +40,7 @@
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
|
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
|
#include "mozilla/dom/CustomElementRegistry.h"
|
||||||
#include "mozilla/dom/DOMError.h"
|
#include "mozilla/dom/DOMError.h"
|
||||||
#include "mozilla/dom/DOMErrorBinding.h"
|
#include "mozilla/dom/DOMErrorBinding.h"
|
||||||
#include "mozilla/dom/DOMException.h"
|
#include "mozilla/dom/DOMException.h"
|
||||||
|
@ -44,6 +48,7 @@
|
||||||
#include "mozilla/dom/HTMLObjectElement.h"
|
#include "mozilla/dom/HTMLObjectElement.h"
|
||||||
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
||||||
#include "mozilla/dom/HTMLSharedObjectElement.h"
|
#include "mozilla/dom/HTMLSharedObjectElement.h"
|
||||||
|
#include "mozilla/dom/HTMLElementBinding.h"
|
||||||
#include "mozilla/dom/HTMLEmbedElementBinding.h"
|
#include "mozilla/dom/HTMLEmbedElementBinding.h"
|
||||||
#include "mozilla/dom/HTMLAppletElementBinding.h"
|
#include "mozilla/dom/HTMLAppletElementBinding.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
|
@ -62,6 +67,30 @@ namespace dom {
|
||||||
|
|
||||||
using namespace workers;
|
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[] = {
|
const JSErrorFormatString ErrorFormatString[] = {
|
||||||
#define MSG_DEF(_name, _argc, _exn, _str) \
|
#define MSG_DEF(_name, _argc, _exn, _str) \
|
||||||
{ #_name, _str, _argc, _exn },
|
{ #_name, _str, _argc, _exn },
|
||||||
|
@ -3377,6 +3406,189 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
|
||||||
return true;
|
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
|
#ifdef DEBUG
|
||||||
namespace binding_detail {
|
namespace binding_detail {
|
||||||
void
|
void
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#include "nsWrapperCacheInlines.h"
|
#include "nsWrapperCacheInlines.h"
|
||||||
|
|
||||||
|
class nsGenericHTMLElement;
|
||||||
class nsIJSID;
|
class nsIJSID;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -49,6 +50,7 @@ namespace mozilla {
|
||||||
enum UseCounter : int16_t;
|
enum UseCounter : int16_t;
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
class CustomElementReactionsStack;
|
||||||
template<typename KeyType, typename ValueType> class Record;
|
template<typename KeyType, typename ValueType> class Record;
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -3420,6 +3422,19 @@ bool
|
||||||
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
|
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
|
||||||
JS::MutableHandle<JSObject*> aDesiredProto);
|
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
|
void
|
||||||
SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
|
SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
|
||||||
UseCounter aUseCounter);
|
UseCounter aUseCounter);
|
||||||
|
|
|
@ -1638,6 +1638,15 @@ DOMInterfaces = {
|
||||||
'register': False,
|
'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
|
# These are temporary, until they've been converted to use new DOM bindings
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/dom/CallbackObject.h"
|
#include "mozilla/dom/CallbackObject.h"
|
||||||
|
#include "mozilla/CycleCollectedJSContext.h"
|
||||||
#include "mozilla/dom/BindingUtils.h"
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "nsIScriptGlobalObject.h"
|
#include "nsIScriptGlobalObject.h"
|
||||||
|
@ -79,7 +80,10 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||||
, mIsMainThread(NS_IsMainThread())
|
, mIsMainThread(NS_IsMainThread())
|
||||||
{
|
{
|
||||||
if (mIsMainThread) {
|
if (mIsMainThread) {
|
||||||
nsContentUtils::EnterMicroTask();
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->EnterMicroTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the caller's subject principal (if necessary) early, before we
|
// 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
|
// It is important that this is the last thing we do, after leaving the
|
||||||
// compartment and undoing all our entry/incumbent script changes
|
// compartment and undoing all our entry/incumbent script changes
|
||||||
if (mIsMainThread) {
|
if (mIsMainThread) {
|
||||||
nsContentUtils::LeaveMicroTask();
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->LeaveMicroTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1747,6 +1747,71 @@ class CGClassConstructor(CGAbstractStaticMethod):
|
||||||
else:
|
else:
|
||||||
ctorName = self.descriptor.interface.identifier.name
|
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(
|
preamble = fill(
|
||||||
"""
|
"""
|
||||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||||
|
@ -1757,19 +1822,41 @@ class CGClassConstructor(CGAbstractStaticMethod):
|
||||||
// Adding more relocations
|
// Adding more relocations
|
||||||
return ThrowConstructorWithoutNew(cx, "${ctorName}");
|
return ThrowConstructorWithoutNew(cx, "${ctorName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalObject global(cx, obj);
|
||||||
|
if (global.Failed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$*{htmlConstructorSanityCheck}
|
||||||
JS::Rooted<JSObject*> desiredProto(cx);
|
JS::Rooted<JSObject*> desiredProto(cx);
|
||||||
if (!GetDesiredProto(cx, args, &desiredProto)) {
|
if (!GetDesiredProto(cx, args, &desiredProto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$*{htmlConstructorFallback}
|
||||||
""",
|
""",
|
||||||
chromeOnlyCheck=chromeOnlyCheck,
|
chromeOnlyCheck=chromeOnlyCheck,
|
||||||
ctorName=ctorName)
|
ctorName=ctorName,
|
||||||
|
htmlConstructorSanityCheck=htmlConstructorSanityCheck,
|
||||||
|
htmlConstructorFallback=htmlConstructorFallback)
|
||||||
|
|
||||||
name = self._ctor.identifier.name
|
if self._ctor.isHTMLConstructor():
|
||||||
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
|
signatures = self._ctor.signatures()
|
||||||
callGenerator = CGMethodCall(nativeName, True, self.descriptor,
|
assert len(signatures) == 1
|
||||||
self._ctor, isConstructor=True,
|
# Given that HTMLConstructor takes no args, we can just codegen a
|
||||||
constructorName=ctorName)
|
# 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()
|
return preamble + "\n" + callGenerator.define()
|
||||||
|
|
||||||
|
|
||||||
|
@ -7386,7 +7473,7 @@ class CGPerSignatureCall(CGThing):
|
||||||
def __init__(self, returnType, arguments, nativeMethodName, static,
|
def __init__(self, returnType, arguments, nativeMethodName, static,
|
||||||
descriptor, idlNode, argConversionStartsAt=0, getter=False,
|
descriptor, idlNode, argConversionStartsAt=0, getter=False,
|
||||||
setter=False, isConstructor=False, useCounterName=None,
|
setter=False, isConstructor=False, useCounterName=None,
|
||||||
resultVar=None):
|
resultVar=None, objectName="obj"):
|
||||||
assert idlNode.isMethod() == (not getter and not setter)
|
assert idlNode.isMethod() == (not getter and not setter)
|
||||||
assert idlNode.isAttr() == (getter or setter)
|
assert idlNode.isAttr() == (getter or setter)
|
||||||
# Constructors are always static
|
# Constructors are always static
|
||||||
|
@ -7440,26 +7527,23 @@ class CGPerSignatureCall(CGThing):
|
||||||
|
|
||||||
argsPre = []
|
argsPre = []
|
||||||
if idlNode.isStatic():
|
if idlNode.isStatic():
|
||||||
# If we're a constructor, "obj" may not be a function, so calling
|
# If we're a constructor, the GlobalObject struct will be created in
|
||||||
# XrayAwareCalleeGlobal() on it is not safe. Of course in the
|
# CGClassConstructor.
|
||||||
# constructor case either "obj" is an Xray or we're already in the
|
if not isConstructor:
|
||||||
# content compartment, not the Xray compartment, so just
|
cgThings.append(CGGeneric(dedent(
|
||||||
# constructing the GlobalObject from "obj" is fine.
|
"""
|
||||||
if isConstructor:
|
GlobalObject global(cx, xpc::XrayAwareCalleeGlobal(obj));
|
||||||
objForGlobalObject = "obj"
|
if (global.Failed()) {
|
||||||
else:
|
return false;
|
||||||
objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)"
|
}
|
||||||
cgThings.append(CGGeneric(fill(
|
|
||||||
"""
|
""")))
|
||||||
GlobalObject global(cx, ${obj});
|
|
||||||
if (global.Failed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
""",
|
|
||||||
obj=objForGlobalObject)))
|
|
||||||
argsPre.append("global")
|
argsPre.append("global")
|
||||||
|
|
||||||
|
if isConstructor and idlNode.isHTMLConstructor():
|
||||||
|
argsPre.extend(["args", "desiredProto"])
|
||||||
|
|
||||||
# For JS-implemented interfaces we do not want to base the
|
# For JS-implemented interfaces we do not want to base the
|
||||||
# needsCx decision on the types involved, just on our extended
|
# needsCx decision on the types involved, just on our extended
|
||||||
# attributes. Also, JSContext is not needed for the static case
|
# attributes. Also, JSContext is not needed for the static case
|
||||||
|
@ -7588,6 +7672,17 @@ class CGPerSignatureCall(CGThing):
|
||||||
CGIfWrapper(CGList(xraySteps),
|
CGIfWrapper(CGList(xraySteps),
|
||||||
"objIsXray"))
|
"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
|
# If this is a method that was generated by a maplike/setlike
|
||||||
# interface, use the maplike/setlike generator to fill in the body.
|
# interface, use the maplike/setlike generator to fill in the body.
|
||||||
# Otherwise, use CGCallGenerator to call the native method.
|
# 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 won't do any argument conversion of its own.
|
||||||
CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
|
CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
|
||||||
False, descriptor, operation,
|
False, descriptor, operation,
|
||||||
len(arguments), resultVar=resultVar)
|
len(arguments), resultVar=resultVar,
|
||||||
|
objectName="proxy")
|
||||||
|
|
||||||
if operation.isSetter() or operation.isCreator():
|
if operation.isSetter() or operation.isCreator():
|
||||||
# arguments[0] is the index or name of the item that we're setting.
|
# arguments[0] is the index or name of the item that we're setting.
|
||||||
|
@ -13755,12 +13851,18 @@ class CGBindingRoot(CGThing):
|
||||||
iface = desc.interface
|
iface = desc.interface
|
||||||
return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface])
|
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(
|
bindingHeaders["nsIDocument.h"] = any(
|
||||||
descriptorDeprecated(d) for d in descriptors)
|
descriptorDeprecated(d) for d in descriptors)
|
||||||
bindingHeaders["mozilla/Preferences.h"] = any(
|
bindingHeaders["mozilla/Preferences.h"] = any(
|
||||||
descriptorRequiresPreferences(d) for d in descriptors)
|
descriptorRequiresPreferences(d) for d in descriptors)
|
||||||
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
|
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
|
||||||
d.concrete and d.proxy for d in descriptors)
|
d.concrete and d.proxy for d in descriptors)
|
||||||
|
bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any(
|
||||||
|
descriptorHasCEReactions(d) for d in descriptors)
|
||||||
|
|
||||||
def descriptorHasChromeOnly(desc):
|
def descriptorHasChromeOnly(desc):
|
||||||
ctor = desc.interface.ctor()
|
ctor = desc.interface.ctor()
|
||||||
|
|
|
@ -1582,7 +1582,7 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||||
[self.location])
|
[self.location])
|
||||||
|
|
||||||
self._noInterfaceObject = True
|
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():
|
if identifier == "Constructor" and not self.hasInterfaceObject():
|
||||||
raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible",
|
raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible",
|
||||||
[self.location])
|
[self.location])
|
||||||
|
@ -1595,11 +1595,20 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||||
raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible",
|
raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible",
|
||||||
[self.location])
|
[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 []
|
args = attr.args() if attr.hasArgs() else []
|
||||||
|
|
||||||
retType = IDLWrapperType(self.location, self)
|
retType = IDLWrapperType(self.location, self)
|
||||||
|
|
||||||
if identifier == "Constructor" or identifier == "ChromeConstructor":
|
if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor":
|
||||||
name = "constructor"
|
name = "constructor"
|
||||||
allowForbidden = True
|
allowForbidden = True
|
||||||
else:
|
else:
|
||||||
|
@ -1610,7 +1619,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||||
allowForbidden=allowForbidden)
|
allowForbidden=allowForbidden)
|
||||||
|
|
||||||
method = IDLMethod(self.location, methodIdentifier, retType,
|
method = IDLMethod(self.location, methodIdentifier, retType,
|
||||||
args, static=True)
|
args, static=True,
|
||||||
|
htmlConstructor=(identifier == "HTMLConstructor"))
|
||||||
# Constructors are always NewObject and are always
|
# Constructors are always NewObject and are always
|
||||||
# assumed to be able to throw (since there's no way to
|
# assumed to be able to throw (since there's no way to
|
||||||
# indicate otherwise) and never have any other
|
# indicate otherwise) and never have any other
|
||||||
|
@ -1622,7 +1632,7 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||||
method.addExtendedAttributes(
|
method.addExtendedAttributes(
|
||||||
[IDLExtendedAttribute(self.location, ("ChromeOnly",))])
|
[IDLExtendedAttribute(self.location, ("ChromeOnly",))])
|
||||||
|
|
||||||
if identifier == "Constructor" or identifier == "ChromeConstructor":
|
if identifier == "Constructor" or identifier == "ChromeConstructor" or identifier == "HTMLConstructor":
|
||||||
method.resolve(self)
|
method.resolve(self)
|
||||||
else:
|
else:
|
||||||
# We need to detect conflicts for NamedConstructors across
|
# 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 "
|
raise WebIDLError("Attribute returns a type that is not exposed "
|
||||||
"everywhere where the attribute is exposed",
|
"everywhere where the attribute is exposed",
|
||||||
[self.location])
|
[self.location])
|
||||||
|
if self.getExtendedAttribute("CEReactions"):
|
||||||
|
if self.readonly:
|
||||||
|
raise WebIDLError("[CEReactions] is not allowed on "
|
||||||
|
"readonly attributes",
|
||||||
|
[self.location])
|
||||||
|
|
||||||
def handleExtendedAttribute(self, attr):
|
def handleExtendedAttribute(self, attr):
|
||||||
identifier = attr.identifier()
|
identifier = attr.identifier()
|
||||||
|
@ -4243,6 +4258,10 @@ class IDLAttribute(IDLInterfaceMember):
|
||||||
raise WebIDLError("[Unscopable] is only allowed on non-static "
|
raise WebIDLError("[Unscopable] is only allowed on non-static "
|
||||||
"attributes and operations",
|
"attributes and operations",
|
||||||
[attr.location, self.location])
|
[attr.location, self.location])
|
||||||
|
elif identifier == "CEReactions":
|
||||||
|
if not attr.noArguments():
|
||||||
|
raise WebIDLError("[CEReactions] must take no arguments",
|
||||||
|
[attr.location])
|
||||||
elif (identifier == "Pref" or
|
elif (identifier == "Pref" or
|
||||||
identifier == "Deprecated" or
|
identifier == "Deprecated" or
|
||||||
identifier == "SetterThrows" or
|
identifier == "SetterThrows" or
|
||||||
|
@ -4537,7 +4556,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
static=False, getter=False, setter=False, creator=False,
|
static=False, getter=False, setter=False, creator=False,
|
||||||
deleter=False, specialType=NamedOrIndexed.Neither,
|
deleter=False, specialType=NamedOrIndexed.Neither,
|
||||||
legacycaller=False, stringifier=False, jsonifier=False,
|
legacycaller=False, stringifier=False, jsonifier=False,
|
||||||
maplikeOrSetlikeOrIterable=None):
|
maplikeOrSetlikeOrIterable=None, htmlConstructor=False):
|
||||||
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
|
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
|
||||||
IDLInterfaceMember.__init__(self, location, identifier,
|
IDLInterfaceMember.__init__(self, location, identifier,
|
||||||
IDLInterfaceMember.Tags.Method)
|
IDLInterfaceMember.Tags.Method)
|
||||||
|
@ -4567,6 +4586,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
self._jsonifier = jsonifier
|
self._jsonifier = jsonifier
|
||||||
assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase)
|
assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase)
|
||||||
self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
|
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._specialType = specialType
|
||||||
self._unforgeable = False
|
self._unforgeable = False
|
||||||
self.dependsOn = "Everything"
|
self.dependsOn = "Everything"
|
||||||
|
@ -4667,6 +4690,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
self.isStringifier() or
|
self.isStringifier() or
|
||||||
self.isJsonifier())
|
self.isJsonifier())
|
||||||
|
|
||||||
|
def isHTMLConstructor(self):
|
||||||
|
return self._htmlConstructor
|
||||||
|
|
||||||
def hasOverloads(self):
|
def hasOverloads(self):
|
||||||
return self._hasOverloads
|
return self._hasOverloads
|
||||||
|
|
||||||
|
@ -4722,6 +4748,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
assert not method.isStringifier()
|
assert not method.isStringifier()
|
||||||
assert not self.isJsonifier()
|
assert not self.isJsonifier()
|
||||||
assert not method.isJsonifier()
|
assert not method.isJsonifier()
|
||||||
|
assert not self.isHTMLConstructor()
|
||||||
|
assert not method.isHTMLConstructor()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -4964,6 +4992,15 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
raise WebIDLError("[Unscopable] is only allowed on non-static "
|
raise WebIDLError("[Unscopable] is only allowed on non-static "
|
||||||
"attributes and operations",
|
"attributes and operations",
|
||||||
[attr.location, self.location])
|
[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
|
elif (identifier == "Throws" or
|
||||||
identifier == "NewObject" or
|
identifier == "NewObject" or
|
||||||
identifier == "ChromeOnly" or
|
identifier == "ChromeOnly" or
|
||||||
|
|
|
@ -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")
|
|
@ -13,7 +13,7 @@ def WebIDLTest(parser, harness):
|
||||||
def checkMethod(method, QName, name, signatures,
|
def checkMethod(method, QName, name, signatures,
|
||||||
static=True, getter=False, setter=False, creator=False,
|
static=True, getter=False, setter=False, creator=False,
|
||||||
deleter=False, legacycaller=False, stringifier=False,
|
deleter=False, legacycaller=False, stringifier=False,
|
||||||
chromeOnly=False):
|
chromeOnly=False, htmlConstructor=False):
|
||||||
harness.ok(isinstance(method, WebIDL.IDLMethod),
|
harness.ok(isinstance(method, WebIDL.IDLMethod),
|
||||||
"Should be an IDLMethod")
|
"Should be an IDLMethod")
|
||||||
harness.ok(method.isMethod(), "Method is a method")
|
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.isLegacycaller(), legacycaller, "Method has the correct legacycaller value")
|
||||||
harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier 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.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")
|
harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures")
|
||||||
|
|
||||||
sigpairs = zip(method.signatures(), signatures)
|
sigpairs = zip(method.signatures(), signatures)
|
||||||
|
@ -78,6 +79,21 @@ def WebIDLTest(parser, harness):
|
||||||
("TestConstructorOverloads (Wrapper)",
|
("TestConstructorOverloads (Wrapper)",
|
||||||
[("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])])
|
[("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])])
|
||||||
|
|
||||||
|
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 = parser.reset()
|
||||||
parser.parse("""
|
parser.parse("""
|
||||||
[ChromeConstructor()]
|
[ChromeConstructor()]
|
||||||
|
@ -107,3 +123,151 @@ def WebIDLTest(parser, harness):
|
||||||
threw = True
|
threw = True
|
||||||
|
|
||||||
harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor")
|
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")
|
|
@ -34,3 +34,36 @@ def WebIDLTest(parser, harness):
|
||||||
interface TestNamedConstructorNoInterfaceObject {
|
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.")
|
|
@ -939,6 +939,11 @@ public:
|
||||||
void NeedsCallerTypeMethod(CallerType);
|
void NeedsCallerTypeMethod(CallerType);
|
||||||
bool NeedsCallerTypeAttr(CallerType);
|
bool NeedsCallerTypeAttr(CallerType);
|
||||||
void SetNeedsCallerTypeAttr(bool, 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&);
|
int16_t LegacyCall(const JS::Value&, uint32_t, TestInterface&);
|
||||||
void PassArgsWithDefaults(JSContext*, const Optional<int32_t>&,
|
void PassArgsWithDefaults(JSContext*, const Optional<int32_t>&,
|
||||||
TestInterface*, const Dict&, double,
|
TestInterface*, const Dict&, double,
|
||||||
|
@ -1425,6 +1430,31 @@ public:
|
||||||
void SetNeedsCallerTypeAttr(bool, CallerType);
|
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 dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -947,6 +947,10 @@ interface TestInterface {
|
||||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||||
[NeedsCallerType] void needsCallerTypeMethod();
|
[NeedsCallerType] void needsCallerTypeMethod();
|
||||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
[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);
|
legacycaller short(unsigned long arg1, TestInterface arg2);
|
||||||
void passArgsWithDefaults(optional long arg1,
|
void passArgsWithDefaults(optional long arg1,
|
||||||
optional TestInterface? arg2 = null,
|
optional TestInterface? arg2 = null,
|
||||||
|
@ -1262,3 +1266,16 @@ interface TestWorkerExposedInterface {
|
||||||
[NeedsCallerType] void needsCallerTypeMethod();
|
[NeedsCallerType] void needsCallerTypeMethod();
|
||||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
[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;
|
||||||
|
};
|
||||||
|
|
|
@ -777,6 +777,10 @@ interface TestExampleInterface {
|
||||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||||
[NeedsCallerType] void needsCallerTypeMethod();
|
[NeedsCallerType] void needsCallerTypeMethod();
|
||||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
[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);
|
legacycaller short(unsigned long arg1, TestInterface arg2);
|
||||||
void passArgsWithDefaults(optional long arg1,
|
void passArgsWithDefaults(optional long arg1,
|
||||||
optional TestInterface? arg2 = null,
|
optional TestInterface? arg2 = null,
|
||||||
|
|
|
@ -794,6 +794,10 @@ interface TestJSImplInterface {
|
||||||
[Throws] attribute boolean throwingAttr;
|
[Throws] attribute boolean throwingAttr;
|
||||||
[GetterThrows] attribute boolean throwingGetterAttr;
|
[GetterThrows] attribute boolean throwingGetterAttr;
|
||||||
[SetterThrows] attribute boolean throwingSetterAttr;
|
[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
|
// NeedsSubjectPrincipal not supported on JS-implemented things for
|
||||||
// now, because we always pass in the caller principal anyway.
|
// now, because we always pass in the caller principal anyway.
|
||||||
// [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();
|
// [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();
|
||||||
|
|
|
@ -20,11 +20,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=560072
|
||||||
|
|
||||||
/** Test for Bug 560072 **/
|
/** Test for Bug 560072 **/
|
||||||
is(document.body,
|
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");
|
"Should get body out of property descriptor");
|
||||||
|
|
||||||
is(document.body,
|
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");
|
"Should get body out of property descriptor this way too");
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1087,7 +1087,10 @@ EventListenerManager::HandleEventSubType(Listener* aListener,
|
||||||
|
|
||||||
if (NS_SUCCEEDED(result)) {
|
if (NS_SUCCEEDED(result)) {
|
||||||
if (mIsMainThreadELM) {
|
if (mIsMainThreadELM) {
|
||||||
nsContentUtils::EnterMicroTask();
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->EnterMicroTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// nsIDOMEvent::currentTarget is set in EventDispatcher.
|
// nsIDOMEvent::currentTarget is set in EventDispatcher.
|
||||||
if (listenerHolder.HasWebIDLCallback()) {
|
if (listenerHolder.HasWebIDLCallback()) {
|
||||||
|
@ -1099,7 +1102,10 @@ EventListenerManager::HandleEventSubType(Listener* aListener,
|
||||||
result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent);
|
result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent);
|
||||||
}
|
}
|
||||||
if (mIsMainThreadELM) {
|
if (mIsMainThreadELM) {
|
||||||
nsContentUtils::LeaveMicroTask();
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (ccjs) {
|
||||||
|
ccjs->LeaveMicroTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "mozilla/dom/FlyWebDiscoveryManager.h"
|
#include "mozilla/dom/FlyWebDiscoveryManager.h"
|
||||||
#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
|
#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
|
||||||
|
#include "mozilla/dom/Element.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
|
@ -6,39 +6,11 @@
|
||||||
#include "mozilla/dom/HTMLDetailsElement.h"
|
#include "mozilla/dom/HTMLDetailsElement.h"
|
||||||
|
|
||||||
#include "mozilla/dom/HTMLDetailsElementBinding.h"
|
#include "mozilla/dom/HTMLDetailsElementBinding.h"
|
||||||
#include "mozilla/dom/HTMLUnknownElement.h"
|
NS_IMPL_NS_NEW_HTML_ELEMENT(Details)
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
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()
|
HTMLDetailsElement::~HTMLDetailsElement()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,6 @@ class HTMLDetailsElement final : public nsGenericHTMLElement
|
||||||
public:
|
public:
|
||||||
using NodeInfo = mozilla::dom::NodeInfo;
|
using NodeInfo = mozilla::dom::NodeInfo;
|
||||||
|
|
||||||
static bool IsDetailsEnabled();
|
|
||||||
|
|
||||||
explicit HTMLDetailsElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
explicit HTMLDetailsElement(already_AddRefed<NodeInfo>& aNodeInfo)
|
||||||
: nsGenericHTMLElement(aNodeInfo)
|
: nsGenericHTMLElement(aNodeInfo)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,3 +52,12 @@ NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||||
{
|
{
|
||||||
return new mozilla::dom::HTMLElement(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);
|
||||||
|
}
|
||||||
|
|
|
@ -14,17 +14,7 @@
|
||||||
#include "mozilla/TextEvents.h"
|
#include "mozilla/TextEvents.h"
|
||||||
#include "nsFocusManager.h"
|
#include "nsFocusManager.h"
|
||||||
|
|
||||||
// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Summary) to add pref check.
|
NS_IMPL_NS_NEW_HTML_ELEMENT(Summary)
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
|
@ -497,7 +497,7 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||||
// We need to consider a labels element is moved to another subtree
|
// We need to consider a labels element is moved to another subtree
|
||||||
// with different root, it needs to update labels list and its root
|
// with different root, it needs to update labels list and its root
|
||||||
// as well.
|
// as well.
|
||||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots && slots->mLabelsList) {
|
if (slots && slots->mLabelsList) {
|
||||||
slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
|
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,
|
// We need to consider a labels element is removed from tree,
|
||||||
// it needs to update labels list and its root as well.
|
// it needs to update labels list and its root as well.
|
||||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||||
if (slots && slots->mLabelsList) {
|
if (slots && slots->mLabelsList) {
|
||||||
slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
|
slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
|
||||||
}
|
}
|
||||||
|
@ -1730,7 +1730,7 @@ nsGenericHTMLElement::Labels()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsLabelable(),
|
MOZ_ASSERT(IsLabelable(),
|
||||||
"Labels() only allow labelable elements to use it.");
|
"Labels() only allow labelable elements to use it.");
|
||||||
nsDOMSlots* slots = DOMSlots();
|
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||||
|
|
||||||
if (!slots->mLabelsList) {
|
if (!slots->mLabelsList) {
|
||||||
slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement,
|
slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement,
|
||||||
|
|
|
@ -1588,6 +1588,15 @@ protected:
|
||||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, \
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, \
|
||||||
mNodeInfo->Equals(nsGkAtoms::_tag))
|
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.
|
* A macro to declare the NS_NewHTMLXXXElement() functions.
|
||||||
|
@ -1636,6 +1645,13 @@ nsGenericHTMLElement*
|
||||||
NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
NS_NewHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||||
mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
|
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(Shared)
|
||||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList)
|
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList)
|
||||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedObject)
|
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedObject)
|
||||||
|
|
|
@ -84,10 +84,6 @@ using namespace mozilla::dom;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
typedef nsGenericHTMLElement*
|
|
||||||
(*contentCreatorCallback)(already_AddRefed<mozilla::dom::NodeInfo>&&,
|
|
||||||
FromParser aFromParser);
|
|
||||||
|
|
||||||
nsGenericHTMLElement*
|
nsGenericHTMLElement*
|
||||||
NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||||
FromParser aFromParser)
|
FromParser aFromParser)
|
||||||
|
@ -96,14 +92,12 @@ NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element,
|
#define HTML_TAG(_tag, _classname, _interfacename) NS_NewHTML##_classname##Element,
|
||||||
#define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement,
|
|
||||||
#define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
|
#define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
|
||||||
static const contentCreatorCallback sContentCreatorCallbacks[] = {
|
static const HTMLContentCreatorFunction sHTMLContentCreatorFunctions[] = {
|
||||||
NS_NewHTMLUnknownElement,
|
NS_NewHTMLUnknownElement,
|
||||||
#include "nsHTMLTagList.h"
|
#include "nsHTMLTagList.h"
|
||||||
#undef HTML_TAG
|
#undef HTML_TAG
|
||||||
#undef HTML_HTMLELEMENT_TAG
|
|
||||||
#undef HTML_OTHER
|
#undef HTML_OTHER
|
||||||
NS_NewHTMLUnknownElement
|
NS_NewHTMLUnknownElement
|
||||||
};
|
};
|
||||||
|
@ -234,9 +228,35 @@ public:
|
||||||
int32_t mStackPos;
|
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
|
nsresult
|
||||||
NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
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;
|
*aResult = nullptr;
|
||||||
|
|
||||||
|
@ -247,16 +267,109 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
nsIAtom *name = nodeInfo->NameAtom();
|
nsIAtom *name = nodeInfo->NameAtom();
|
||||||
|
RefPtr<nsIAtom> tagAtom = nodeInfo->NameAtom();
|
||||||
|
RefPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
|
||||||
|
|
||||||
NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
|
NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
|
||||||
"Trying to HTML elements that don't have the XHTML namespace");
|
"Trying to HTML elements that don't have the XHTML namespace");
|
||||||
|
|
||||||
int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name);
|
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 &&
|
bool isCustomElementName = (tag == eHTMLTag_userdefined &&
|
||||||
nsContentUtils::IsCustomElementName(name));
|
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) {
|
if (isCustomElementName) {
|
||||||
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
|
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
|
||||||
} else {
|
} else {
|
||||||
|
@ -267,8 +380,8 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCustomElementName || aIs) {
|
if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement) {
|
||||||
nsContentUtils::SetupCustomElement(*aResult, aIs);
|
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -283,7 +396,7 @@ CreateHTMLElement(uint32_t aNodeType,
|
||||||
aNodeType == eHTMLTag_userdefined,
|
aNodeType == eHTMLTag_userdefined,
|
||||||
"aNodeType is out of bounds");
|
"aNodeType is out of bounds");
|
||||||
|
|
||||||
contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType];
|
HTMLContentCreatorFunction cb = sHTMLContentCreatorFunctions[aNodeType];
|
||||||
|
|
||||||
NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement,
|
NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement,
|
||||||
"Don't know how to construct tag element!");
|
"Don't know how to construct tag element!");
|
||||||
|
|
|
@ -1013,26 +1013,6 @@ nsHTMLDocument::SetDomain(const nsAString& aDomain, ErrorResult& rv)
|
||||||
rv = NodePrincipal()->SetDomain(newURI);
|
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
|
NS_IMETHODIMP
|
||||||
nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody)
|
nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody)
|
||||||
{
|
{
|
||||||
|
@ -1054,31 +1034,6 @@ nsHTMLDocument::SetBody(nsIDOMHTMLElement* aBody)
|
||||||
return rv.StealNSResult();
|
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
|
NS_IMETHODIMP
|
||||||
nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead)
|
nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead)
|
||||||
{
|
{
|
||||||
|
@ -1446,6 +1401,11 @@ nsHTMLDocument::Open(JSContext* cx,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShouldThrowOnDynamicMarkupInsertion()) {
|
||||||
|
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the content type for insertion
|
// Set up the content type for insertion
|
||||||
nsAutoCString contentType;
|
nsAutoCString contentType;
|
||||||
contentType.AssignLiteral("text/html");
|
contentType.AssignLiteral("text/html");
|
||||||
|
@ -1653,6 +1613,11 @@ nsHTMLDocument::Close(ErrorResult& rv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShouldThrowOnDynamicMarkupInsertion()) {
|
||||||
|
rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mParser || !mParser->IsScriptCreated()) {
|
if (!mParser || !mParser->IsScriptCreated()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1728,6 +1693,10 @@ nsHTMLDocument::WriteCommon(JSContext *cx,
|
||||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShouldThrowOnDynamicMarkupInsertion()) {
|
||||||
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
if (mParserAborted) {
|
if (mParserAborted) {
|
||||||
// Hixie says aborting the parser doesn't undefine the insertion point.
|
// Hixie says aborting the parser doesn't undefine the insertion point.
|
||||||
// However, since we null out mParser in that case, we track the
|
// However, since we null out mParser in that case, we track the
|
||||||
|
|
|
@ -175,8 +175,8 @@ public:
|
||||||
JS::MutableHandle<JSObject*> aRetval,
|
JS::MutableHandle<JSObject*> aRetval,
|
||||||
mozilla::ErrorResult& rv);
|
mozilla::ErrorResult& rv);
|
||||||
void GetSupportedNames(nsTArray<nsString>& aNames);
|
void GetSupportedNames(nsTArray<nsString>& aNames);
|
||||||
nsGenericHTMLElement *GetBody();
|
using nsIDocument::GetBody;
|
||||||
void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv);
|
using nsIDocument::SetBody;
|
||||||
mozilla::dom::HTMLSharedElement *GetHead() {
|
mozilla::dom::HTMLSharedElement *GetHead() {
|
||||||
return static_cast<mozilla::dom::HTMLSharedElement*>(GetHeadElement());
|
return static_cast<mozilla::dom::HTMLSharedElement*>(GetHeadElement());
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "nsIWritablePropertyBag2.h"
|
#include "nsIWritablePropertyBag2.h"
|
||||||
#include "nsIContentSecurityPolicy.h"
|
#include "nsIContentSecurityPolicy.h"
|
||||||
#include "nsSandboxFlags.h"
|
#include "nsSandboxFlags.h"
|
||||||
|
#include "mozilla/CycleCollectedJSContext.h"
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
#include "nsILoadInfo.h"
|
#include "nsILoadInfo.h"
|
||||||
#include "nsContentSecurityManager.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
|
// New script entry point required, due to the "Create a script" step of
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
|
// http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
|
||||||
nsAutoMicroTask mt;
|
mozilla::nsAutoMicroTask mt;
|
||||||
AutoEntryScript aes(innerGlobal, "javascript: URI", true);
|
AutoEntryScript aes(innerGlobal, "javascript: URI", true);
|
||||||
JSContext* cx = aes.cx();
|
JSContext* cx = aes.cx();
|
||||||
JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
|
JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
|
||||||
|
|
|
@ -15,31 +15,28 @@ using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
// Hash table that maps nsIAtom* SVG tags to an offset index
|
// 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;
|
static PLHashTable* sTagAtomTable = nullptr;
|
||||||
|
|
||||||
// We don't want to store 0 in the hash table as a return value of 0 from
|
// 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
|
// PL_HashTableLookupConst indicates that the value is not found
|
||||||
#define TABLE_VALUE_OFFSET 1
|
#define TABLE_VALUE_OFFSET 1
|
||||||
|
|
||||||
#define SVG_TAG(_tag, _classname) \
|
#define SVG_TAG(_tag, _classname) \
|
||||||
nsresult \
|
nsresult NS_NewSVG##_classname##Element( \
|
||||||
NS_NewSVG##_classname##Element(nsIContent** aResult, \
|
nsIContent** aResult, \
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); \
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); \
|
||||||
\
|
\
|
||||||
static inline nsresult \
|
nsresult NS_NewSVG##_classname##Element( \
|
||||||
Create##_classname##Element(nsIContent** aResult, \
|
nsIContent** aResult, \
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
|
||||||
FromParser aFromParser) \
|
FromParser aFromParser) \
|
||||||
{ \
|
{ \
|
||||||
return NS_NewSVG##_classname##Element(aResult, mozilla::Move(aNodeInfo)); \
|
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"
|
#include "SVGTagList.h"
|
||||||
#undef SVG_TAG
|
#undef SVG_TAG
|
||||||
#undef SVG_FROM_PARSER_TAG
|
#undef SVG_FROM_PARSER_TAG
|
||||||
|
@ -48,13 +45,8 @@ nsresult
|
||||||
NS_NewSVGElement(Element** aResult,
|
NS_NewSVGElement(Element** aResult,
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
||||||
|
|
||||||
typedef nsresult
|
static const SVGContentCreatorFunction sSVGContentCreatorFunctions[] = {
|
||||||
(*contentCreatorCallback)(nsIContent** aResult,
|
#define SVG_TAG(_tag, _classname) NS_NewSVG##_classname##Element,
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
|
||||||
FromParser aFromParser);
|
|
||||||
|
|
||||||
static const contentCreatorCallback sContentCreatorCallbacks[] = {
|
|
||||||
#define SVG_TAG(_tag, _classname) Create##_classname##Element,
|
|
||||||
#define SVG_FROM_PARSER_TAG(_tag, _classname) NS_NewSVG##_classname##Element,
|
#define SVG_FROM_PARSER_TAG(_tag, _classname) NS_NewSVG##_classname##Element,
|
||||||
#include "SVGTagList.h"
|
#include "SVGTagList.h"
|
||||||
#undef SVG_TAG
|
#undef SVG_TAG
|
||||||
|
@ -124,7 +116,7 @@ NS_NewSVGElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& a
|
||||||
MOZ_CRASH();
|
MOZ_CRASH();
|
||||||
}
|
}
|
||||||
|
|
||||||
contentCreatorCallback cb = sContentCreatorCallbacks[index];
|
SVGContentCreatorFunction cb = sSVGContentCreatorFunctions[index];
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> content;
|
nsCOMPtr<nsIContent> content;
|
||||||
nsresult rv = cb(getter_AddRefs(content), ni.forget(), aFromParser);
|
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:
|
// if we don't know what to create, just create a standard svg element:
|
||||||
return NS_NewSVGElement(aResult, ni.forget());
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,32 @@ public:
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef nsresult (*SVGContentCreatorFunction)(
|
||||||
|
nsIContent** aResult,
|
||||||
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||||
|
mozilla::dom::FromParser aFromParser);
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // 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 */
|
#endif /* mozilla_dom_SVGElementFactory_h */
|
||||||
|
|
|
@ -9,7 +9,14 @@
|
||||||
This file contains the list of all SVG tags.
|
This file contains the list of all SVG tags.
|
||||||
|
|
||||||
It is designed to be used as inline input to SVGElementFactory.cpp
|
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
|
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.
|
which will have cruel and unusual things done to them.
|
||||||
|
|
|
@ -14,6 +14,7 @@ EXPORTS += [
|
||||||
'SVGContentUtils.h',
|
'SVGContentUtils.h',
|
||||||
'SVGPreserveAspectRatio.h',
|
'SVGPreserveAspectRatio.h',
|
||||||
'SVGStringList.h',
|
'SVGStringList.h',
|
||||||
|
'SVGTagList.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
EXPORTS.mozilla.dom += [
|
EXPORTS.mozilla.dom += [
|
||||||
|
@ -39,6 +40,7 @@ EXPORTS.mozilla.dom += [
|
||||||
'SVGDefsElement.h',
|
'SVGDefsElement.h',
|
||||||
'SVGDescElement.h',
|
'SVGDescElement.h',
|
||||||
'SVGDocument.h',
|
'SVGDocument.h',
|
||||||
|
'SVGElementFactory.h',
|
||||||
'SVGEllipseElement.h',
|
'SVGEllipseElement.h',
|
||||||
'SVGFEBlendElement.h',
|
'SVGFEBlendElement.h',
|
||||||
'SVGFEColorMatrixElement.h',
|
'SVGFEColorMatrixElement.h',
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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();
|
||||||
|
})();
|
||||||
|
}));
|
|
@ -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();
|
||||||
|
})();
|
||||||
|
}));
|
||||||
|
});
|
|
@ -1,21 +1,28 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
inert_style.css
|
inert_style.css
|
||||||
|
dummy_page.html
|
||||||
|
|
||||||
[test_bug900724.html]
|
[test_bug900724.html]
|
||||||
[test_bug1017896.html]
|
[test_bug1017896.html]
|
||||||
[test_bug1176757.html]
|
[test_bug1176757.html]
|
||||||
[test_bug1276240.html]
|
[test_bug1276240.html]
|
||||||
[test_content_element.html]
|
[test_content_element.html]
|
||||||
[test_custom_element_adopt_callbacks.html]
|
|
||||||
[test_custom_element_callback_innerhtml.html]
|
[test_custom_element_callback_innerhtml.html]
|
||||||
[test_custom_element_clone_callbacks.html]
|
skip-if = true # disabled - See bug 1390396
|
||||||
[test_custom_element_clone_callbacks_extended.html]
|
[test_custom_element_htmlconstructor.html]
|
||||||
[test_custom_element_import_node_created_callback.html]
|
skip-if = os == 'android' # bug 1323645
|
||||||
|
support-files =
|
||||||
|
htmlconstructor_autonomous_tests.js
|
||||||
|
htmlconstructor_builtin_tests.js
|
||||||
[test_custom_element_in_shadow.html]
|
[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_register_invalid_callbacks.html]
|
||||||
|
[test_custom_element_throw_on_dynamic_markup_insertion.html]
|
||||||
[test_custom_element_get.html]
|
[test_custom_element_get.html]
|
||||||
[test_custom_element_when_defined.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_nested_content_element.html]
|
||||||
[test_dest_insertion_points.html]
|
[test_dest_insertion_points.html]
|
||||||
[test_dest_insertion_points_shadow.html]
|
[test_dest_insertion_points_shadow.html]
|
||||||
|
@ -25,10 +32,11 @@ support-files =
|
||||||
[test_document_adoptnode.html]
|
[test_document_adoptnode.html]
|
||||||
[test_document_importnode.html]
|
[test_document_importnode.html]
|
||||||
[test_document_register.html]
|
[test_document_register.html]
|
||||||
[test_document_register_base_queue.html]
|
|
||||||
[test_document_register_lifecycle.html]
|
[test_document_register_lifecycle.html]
|
||||||
|
skip-if = true # disabled - See bug 1390396
|
||||||
[test_document_register_parser.html]
|
[test_document_register_parser.html]
|
||||||
[test_document_register_stack.html]
|
[test_document_register_stack.html]
|
||||||
|
skip-if = true # disabled - See bug 1390396
|
||||||
[test_document_shared_registry.html]
|
[test_document_shared_registry.html]
|
||||||
[test_event_dispatch.html]
|
[test_event_dispatch.html]
|
||||||
[test_event_retarget.html]
|
[test_event_retarget.html]
|
||||||
|
|
|
@ -47,7 +47,7 @@ test();
|
||||||
// test with webcomponents disabled
|
// test with webcomponents disabled
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv(
|
SpecialPowers.pushPrefEnv(
|
||||||
{ 'set': [["dom.webcomponents.enabled", false]]}, runTest);
|
{ 'set': [["dom.webcomponents.customelements.enabled", false]]}, runTest);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -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>
|
|
|
@ -16,7 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1102502
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
var attachedCallbackCount = 0;
|
var connectedCallbackCount = 0;
|
||||||
|
|
||||||
var p = Object.create(HTMLElement.prototype);
|
var p = Object.create(HTMLElement.prototype);
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ p.createdCallback = function() {
|
||||||
ok(true, "createdCallback called.");
|
ok(true, "createdCallback called.");
|
||||||
};
|
};
|
||||||
|
|
||||||
p.attachedCallback = function() {
|
p.connectedCallback = function() {
|
||||||
ok(true, "attachedCallback should be called when the parser creates an element in the document.");
|
ok(true, "connectedCallback should be called when the parser creates an element in the document.");
|
||||||
attachedCallbackCount++;
|
connectedCallbackCount++;
|
||||||
// attachedCallback should be called twice, once for the element created for innerHTML and
|
// connectedCallback should be called twice, once for the element created for innerHTML and
|
||||||
// once for the element created in this document.
|
// once for the element created in this document.
|
||||||
if (attachedCallbackCount == 2) {
|
if (connectedCallbackCount == 2) {
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
|
@ -19,9 +19,6 @@ const testWindow = iframe.contentDocument.defaultView;
|
||||||
// This is for backward compatibility.
|
// This is for backward compatibility.
|
||||||
// We should do the same checks for the callbacks from v0 spec.
|
// We should do the same checks for the callbacks from v0 spec.
|
||||||
[
|
[
|
||||||
'createdCallback',
|
|
||||||
'attachedCallback',
|
|
||||||
'detachedCallback',
|
|
||||||
'attributeChangedCallback',
|
'attributeChangedCallback',
|
||||||
].forEach(callback => {
|
].forEach(callback => {
|
||||||
var c = class {};
|
var c = class {};
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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.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\"");
|
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.
|
// Custom element constructor.
|
||||||
var constructedButton = new buttonConstructor();
|
var constructedButton = new buttonConstructor();
|
||||||
is(constructedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
|
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.__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.");
|
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.
|
// Try creating an element with a custom element name, but not in the html namespace.
|
||||||
var htmlNamespaceProto = Object.create(HTMLElement.prototype);
|
var htmlNamespaceProto = Object.create(HTMLElement.prototype);
|
||||||
document.registerElement("x-in-html-namespace", { prototype: htmlNamespaceProto });
|
document.registerElement("x-in-html-namespace", { prototype: htmlNamespaceProto });
|
||||||
|
|
|
@ -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>
|
|
|
@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||||
|
|
||||||
var extendedButtonProto = Object.create(HTMLButtonElement.prototype);
|
var extendedButtonProto = Object.create(HTMLButtonElement.prototype);
|
||||||
var buttonCallbackCalled = false;
|
var buttonCallbackCalled = false;
|
||||||
extendedButtonProto.createdCallback = function() {
|
extendedButtonProto.connectedCallback = function() {
|
||||||
is(buttonCallbackCalled, false, "created callback for x-button should only be called once.");
|
is(buttonCallbackCalled, false, "created callback for x-button should only be called once.");
|
||||||
is(this.tagName, "BUTTON", "Only the <button> element should be upgraded.");
|
is(this.tagName, "BUTTON", "Only the <button> element should be upgraded.");
|
||||||
buttonCallbackCalled = true;
|
buttonCallbackCalled = true;
|
||||||
|
@ -21,7 +21,7 @@ document.registerElement("x-button", { prototype: extendedButtonProto, extends:
|
||||||
|
|
||||||
var divProto = Object.create(HTMLDivElement.prototype);
|
var divProto = Object.create(HTMLDivElement.prototype);
|
||||||
var divCallbackCalled = false;
|
var divCallbackCalled = false;
|
||||||
divProto.createdCallback = function() {
|
divProto.connectedCallback = function() {
|
||||||
is(divCallbackCalled, false, "created callback for x-div should only be called once.");
|
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(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.");
|
is(this.tagName, "X-DIV", "Only the <x-div> element should be upgraded.");
|
||||||
|
|
|
@ -28,7 +28,8 @@ function testChangeAttributeInCreatedCallback() {
|
||||||
createdCallbackCalled = true;
|
createdCallbackCalled = true;
|
||||||
is(attributeChangedCallbackCalled, false, "Attribute changed callback should not have been called prior to setting the attribute.");
|
is(attributeChangedCallbackCalled, false, "Attribute changed callback should not have been called prior to setting the attribute.");
|
||||||
this.setAttribute("foo", "bar");
|
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) {
|
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(attributeChangedCallbackCalled, false, "attributeChanged callback should only be called once in this tests.");
|
||||||
is(newValue, "bar", "The new value should be 'bar'");
|
is(newValue, "bar", "The new value should be 'bar'");
|
||||||
attributeChangedCallbackCalled = true;
|
attributeChangedCallbackCalled = true;
|
||||||
runNextTest();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
document.registerElement("x-one", { prototype: p });
|
document.registerElement("x-one", { prototype: p });
|
||||||
|
|
|
@ -14,37 +14,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||||
<script>
|
<script>
|
||||||
var container = document.getElementById("container");
|
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() {
|
function registerNoRegistryDoc() {
|
||||||
var assocDoc = document.implementation.createDocument(null, "html");
|
var assocDoc = document.implementation.createDocument(null, "html");
|
||||||
try {
|
try {
|
||||||
|
@ -65,8 +34,6 @@ function runNextTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var testFunctions = [
|
var testFunctions = [
|
||||||
createdCallbackFromMainDoc,
|
|
||||||
createdCallbackFromDocHTMLNamespace,
|
|
||||||
registerNoRegistryDoc,
|
registerNoRegistryDoc,
|
||||||
SimpleTest.finish
|
SimpleTest.finish
|
||||||
];
|
];
|
||||||
|
|
|
@ -37,6 +37,7 @@ MOCHITEST_CHROME_MANIFESTS += [
|
||||||
'mochitest/geolocation/chrome.ini',
|
'mochitest/geolocation/chrome.ini',
|
||||||
'mochitest/localstorage/chrome.ini',
|
'mochitest/localstorage/chrome.ini',
|
||||||
'mochitest/sessionstorage/chrome.ini',
|
'mochitest/sessionstorage/chrome.ini',
|
||||||
|
'mochitest/webcomponents/chrome.ini',
|
||||||
'mochitest/whatwg/chrome.ini',
|
'mochitest/whatwg/chrome.ini',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
interface Attr : Node {
|
interface Attr : Node {
|
||||||
readonly attribute DOMString localName;
|
readonly attribute DOMString localName;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString value;
|
attribute DOMString value;
|
||||||
|
|
||||||
[Constant]
|
[Constant]
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
interface CSSRule;
|
interface CSSRule;
|
||||||
|
|
||||||
interface CSSStyleDeclaration {
|
interface CSSStyleDeclaration {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString cssText;
|
attribute DOMString cssText;
|
||||||
|
|
||||||
readonly attribute unsigned long length;
|
readonly attribute unsigned long length;
|
||||||
|
@ -22,9 +22,9 @@ interface CSSStyleDeclaration {
|
||||||
[Throws]
|
[Throws]
|
||||||
CSSValue? getPropertyCSSValue(DOMString property);
|
CSSValue? getPropertyCSSValue(DOMString property);
|
||||||
DOMString getPropertyPriority(DOMString property);
|
DOMString getPropertyPriority(DOMString property);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = "");
|
void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = "");
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
DOMString removeProperty(DOMString property);
|
DOMString removeProperty(DOMString property);
|
||||||
|
|
||||||
readonly attribute CSSRule? parentRule;
|
readonly attribute CSSRule? parentRule;
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
|
|
||||||
[NoInterfaceObject]
|
[NoInterfaceObject]
|
||||||
interface ChildNode {
|
interface ChildNode {
|
||||||
[Throws, Unscopable]
|
[CEReactions, Throws, Unscopable]
|
||||||
void before((Node or DOMString)... nodes);
|
void before((Node or DOMString)... nodes);
|
||||||
[Throws, Unscopable]
|
[CEReactions, Throws, Unscopable]
|
||||||
void after((Node or DOMString)... nodes);
|
void after((Node or DOMString)... nodes);
|
||||||
[Throws, Unscopable]
|
[CEReactions, Throws, Unscopable]
|
||||||
void replaceWith((Node or DOMString)... nodes);
|
void replaceWith((Node or DOMString)... nodes);
|
||||||
[Unscopable]
|
[CEReactions, Unscopable]
|
||||||
void remove();
|
void remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// https://html.spec.whatwg.org/#dom-window-customelements
|
// https://html.spec.whatwg.org/#dom-window-customelements
|
||||||
[Func="CustomElementRegistry::IsCustomElementEnabled"]
|
[Func="CustomElementRegistry::IsCustomElementEnabled"]
|
||||||
interface CustomElementRegistry {
|
interface CustomElementRegistry {
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void define(DOMString name, Function functionConstructor,
|
void define(DOMString name, Function functionConstructor,
|
||||||
optional ElementDefinitionOptions options);
|
optional ElementDefinitionOptions options);
|
||||||
any get(DOMString name);
|
any get(DOMString name);
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
[OverrideBuiltins]
|
[OverrideBuiltins]
|
||||||
interface DOMStringMap {
|
interface DOMStringMap {
|
||||||
getter DOMString (DOMString name);
|
getter DOMString (DOMString name);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
setter creator void (DOMString name, DOMString value);
|
setter creator void (DOMString name, DOMString value);
|
||||||
|
[CEReactions]
|
||||||
deleter void (DOMString name);
|
deleter void (DOMString name);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,17 +14,17 @@ interface DOMTokenList {
|
||||||
readonly attribute unsigned long length;
|
readonly attribute unsigned long length;
|
||||||
getter DOMString? item(unsigned long index);
|
getter DOMString? item(unsigned long index);
|
||||||
boolean contains(DOMString token);
|
boolean contains(DOMString token);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void add(DOMString... tokens);
|
void add(DOMString... tokens);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void remove(DOMString... tokens);
|
void remove(DOMString... tokens);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void replace(DOMString token, DOMString newToken);
|
void replace(DOMString token, DOMString newToken);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
boolean toggle(DOMString token, optional boolean force);
|
boolean toggle(DOMString token, optional boolean force);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
boolean supports(DOMString token);
|
boolean supports(DOMString token);
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString value;
|
attribute DOMString value;
|
||||||
stringifier DOMString ();
|
stringifier DOMString ();
|
||||||
iterable<DOMString?>;
|
iterable<DOMString?>;
|
||||||
|
|
|
@ -65,9 +65,9 @@ interface Document : Node {
|
||||||
[NewObject, Throws]
|
[NewObject, Throws]
|
||||||
ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
|
ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
|
||||||
|
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
Node importNode(Node node, optional boolean deep = false);
|
Node importNode(Node node, optional boolean deep = false);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
Node adoptNode(Node node);
|
Node adoptNode(Node node);
|
||||||
|
|
||||||
[NewObject, Throws]
|
[NewObject, Throws]
|
||||||
|
@ -108,9 +108,9 @@ partial interface Document {
|
||||||
|
|
||||||
// DOM tree accessors
|
// DOM tree accessors
|
||||||
//(Not proxy yet)getter object (DOMString name);
|
//(Not proxy yet)getter object (DOMString name);
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString title;
|
attribute DOMString title;
|
||||||
[Pure]
|
[CEReactions, Pure]
|
||||||
attribute DOMString dir;
|
attribute DOMString dir;
|
||||||
//(HTML only) attribute HTMLElement? body;
|
//(HTML only) attribute HTMLElement? body;
|
||||||
//(HTML only)readonly attribute HTMLHeadElement? head;
|
//(HTML only)readonly attribute HTMLHeadElement? head;
|
||||||
|
|
|
@ -25,9 +25,9 @@ interface Element : Node {
|
||||||
[Pure]
|
[Pure]
|
||||||
readonly attribute DOMString tagName;
|
readonly attribute DOMString tagName;
|
||||||
|
|
||||||
[Pure]
|
[CEReactions, Pure]
|
||||||
attribute DOMString id;
|
attribute DOMString id;
|
||||||
[Pure]
|
[CEReactions, Pure]
|
||||||
attribute DOMString className;
|
attribute DOMString className;
|
||||||
[Constant, PutForwards=value]
|
[Constant, PutForwards=value]
|
||||||
readonly attribute DOMTokenList classList;
|
readonly attribute DOMTokenList classList;
|
||||||
|
@ -40,15 +40,15 @@ interface Element : Node {
|
||||||
DOMString? getAttribute(DOMString name);
|
DOMString? getAttribute(DOMString name);
|
||||||
[Pure]
|
[Pure]
|
||||||
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
|
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
boolean toggleAttribute(DOMString name, optional boolean force);
|
boolean toggleAttribute(DOMString name, optional boolean force);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void setAttribute(DOMString name, DOMString value);
|
void setAttribute(DOMString name, DOMString value);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
|
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void removeAttribute(DOMString name);
|
void removeAttribute(DOMString name);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void removeAttributeNS(DOMString? namespace, DOMString localName);
|
void removeAttributeNS(DOMString? namespace, DOMString localName);
|
||||||
[Pure]
|
[Pure]
|
||||||
boolean hasAttribute(DOMString name);
|
boolean hasAttribute(DOMString name);
|
||||||
|
@ -72,7 +72,7 @@ interface Element : Node {
|
||||||
[Pure]
|
[Pure]
|
||||||
HTMLCollection getElementsByClassName(DOMString classNames);
|
HTMLCollection getElementsByClassName(DOMString classNames);
|
||||||
|
|
||||||
[Throws, Pure]
|
[CEReactions, Throws, Pure]
|
||||||
Element? insertAdjacentElement(DOMString where, Element element); // historical
|
Element? insertAdjacentElement(DOMString where, Element element); // historical
|
||||||
|
|
||||||
[Throws]
|
[Throws]
|
||||||
|
@ -137,12 +137,12 @@ interface Element : Node {
|
||||||
|
|
||||||
// Obsolete methods.
|
// Obsolete methods.
|
||||||
Attr? getAttributeNode(DOMString name);
|
Attr? getAttributeNode(DOMString name);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
Attr? setAttributeNode(Attr newAttr);
|
Attr? setAttributeNode(Attr newAttr);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
Attr? removeAttributeNode(Attr oldAttr);
|
Attr? removeAttributeNode(Attr oldAttr);
|
||||||
Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
|
Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
Attr? setAttributeNodeNS(Attr newAttr);
|
Attr? setAttributeNodeNS(Attr newAttr);
|
||||||
|
|
||||||
[ChromeOnly]
|
[ChromeOnly]
|
||||||
|
@ -212,11 +212,11 @@ partial interface Element {
|
||||||
|
|
||||||
// http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
|
// http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
|
||||||
partial interface Element {
|
partial interface Element {
|
||||||
[Pure,SetterThrows,TreatNullAs=EmptyString]
|
[CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString]
|
||||||
attribute DOMString innerHTML;
|
attribute DOMString innerHTML;
|
||||||
[Pure,SetterThrows,TreatNullAs=EmptyString]
|
[CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString]
|
||||||
attribute DOMString outerHTML;
|
attribute DOMString outerHTML;
|
||||||
[Throws]
|
[CEReactions, Throws]
|
||||||
void insertAdjacentHTML(DOMString position, DOMString text);
|
void insertAdjacentHTML(DOMString position, DOMString text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,6 @@ interface GlobalEventHandlers {
|
||||||
[Pref="dom.select_events.enabled"]
|
[Pref="dom.select_events.enabled"]
|
||||||
attribute EventHandler onselectstart;
|
attribute EventHandler onselectstart;
|
||||||
|
|
||||||
[Pref="dom.details_element.enabled"]
|
|
||||||
attribute EventHandler ontoggle;
|
attribute EventHandler ontoggle;
|
||||||
|
|
||||||
// Pointer events handlers
|
// Pointer events handlers
|
||||||
|
|
|
@ -12,25 +12,26 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-a-element
|
// http://www.whatwg.org/specs/web-apps/current-work/#the-a-element
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLAnchorElement : HTMLElement {
|
interface HTMLAnchorElement : HTMLElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString target;
|
attribute DOMString target;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString download;
|
attribute DOMString download;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString ping;
|
attribute DOMString ping;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString rel;
|
attribute DOMString rel;
|
||||||
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
[CEReactions, SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
||||||
attribute DOMString referrerPolicy;
|
attribute DOMString referrerPolicy;
|
||||||
[PutForwards=value]
|
[PutForwards=value]
|
||||||
readonly attribute DOMTokenList relList;
|
readonly attribute DOMTokenList relList;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString hreflang;
|
attribute DOMString hreflang;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString type;
|
attribute DOMString type;
|
||||||
|
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString text;
|
attribute DOMString text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,14 +39,14 @@ HTMLAnchorElement implements HTMLHyperlinkElementUtils;
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
||||||
partial interface HTMLAnchorElement {
|
partial interface HTMLAnchorElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString coords;
|
attribute DOMString coords;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString charset;
|
attribute DOMString charset;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString name;
|
attribute DOMString name;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString rev;
|
attribute DOMString rev;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString shape;
|
attribute DOMString shape;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,20 +13,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-area-element
|
// http://www.whatwg.org/specs/web-apps/current-work/#the-area-element
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLAreaElement : HTMLElement {
|
interface HTMLAreaElement : HTMLElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString alt;
|
attribute DOMString alt;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString coords;
|
attribute DOMString coords;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString shape;
|
attribute DOMString shape;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString target;
|
attribute DOMString target;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString download;
|
attribute DOMString download;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString ping;
|
attribute DOMString ping;
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString rel;
|
attribute DOMString rel;
|
||||||
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
[SetterThrows, Pref="network.http.enablePerElementReferrer"]
|
||||||
attribute DOMString referrerPolicy;
|
attribute DOMString referrerPolicy;
|
||||||
|
@ -38,6 +39,6 @@ HTMLAreaElement implements HTMLHyperlinkElementUtils;
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
||||||
partial interface HTMLAreaElement {
|
partial interface HTMLAreaElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute boolean noHref;
|
attribute boolean noHref;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
* and create derivative works of this document.
|
* and create derivative works of this document.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[NamedConstructor=Audio(optional DOMString src)]
|
[HTMLConstructor, NamedConstructor=Audio(optional DOMString src)]
|
||||||
interface HTMLAudioElement : HTMLMediaElement {};
|
interface HTMLAudioElement : HTMLMediaElement {};
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-br-element
|
// http://www.whatwg.org/specs/web-apps/current-work/#the-br-element
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLBRElement : HTMLElement {};
|
interface HTMLBRElement : HTMLElement {};
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
||||||
partial interface HTMLBRElement {
|
partial interface HTMLBRElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString clear;
|
attribute DOMString clear;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-base-element
|
// http://www.whatwg.org/specs/web-apps/current-work/#the-base-element
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLBaseElement : HTMLElement {
|
interface HTMLBaseElement : HTMLElement {
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString href;
|
attribute DOMString href;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString target;
|
attribute DOMString target;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,23 @@
|
||||||
* and create derivative works of this document.
|
* and create derivative works of this document.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLBodyElement : HTMLElement {
|
interface HTMLBodyElement : HTMLElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
partial interface HTMLBodyElement {
|
partial interface HTMLBodyElement {
|
||||||
[TreatNullAs=EmptyString, SetterThrows] attribute DOMString text;
|
[CEReactions, TreatNullAs=EmptyString, SetterThrows]
|
||||||
[TreatNullAs=EmptyString, SetterThrows] attribute DOMString link;
|
attribute DOMString text;
|
||||||
[TreatNullAs=EmptyString, SetterThrows] attribute DOMString vLink;
|
[CEReactions, TreatNullAs=EmptyString, SetterThrows]
|
||||||
[TreatNullAs=EmptyString, SetterThrows] attribute DOMString aLink;
|
attribute DOMString link;
|
||||||
[TreatNullAs=EmptyString, SetterThrows] attribute DOMString bgColor;
|
[CEReactions, TreatNullAs=EmptyString, SetterThrows]
|
||||||
[SetterThrows] attribute DOMString background;
|
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;
|
HTMLBodyElement implements WindowEventHandlers;
|
||||||
|
|
|
@ -11,28 +11,29 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-button-element
|
// http://www.whatwg.org/specs/web-apps/current-work/#the-button-element
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLButtonElement : HTMLElement {
|
interface HTMLButtonElement : HTMLElement {
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute boolean autofocus;
|
attribute boolean autofocus;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute boolean disabled;
|
attribute boolean disabled;
|
||||||
[Pure]
|
[Pure]
|
||||||
readonly attribute HTMLFormElement? form;
|
readonly attribute HTMLFormElement? form;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString formAction;
|
attribute DOMString formAction;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString formEnctype;
|
attribute DOMString formEnctype;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString formMethod;
|
attribute DOMString formMethod;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute boolean formNoValidate;
|
attribute boolean formNoValidate;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString formTarget;
|
attribute DOMString formTarget;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString name;
|
attribute DOMString name;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString type;
|
attribute DOMString type;
|
||||||
[SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString value;
|
attribute DOMString value;
|
||||||
// Not yet implemented:
|
// Not yet implemented:
|
||||||
// attribute HTMLMenuElement? menu;
|
// attribute HTMLMenuElement? menu;
|
||||||
|
|
|
@ -13,10 +13,11 @@
|
||||||
interface nsISupports;
|
interface nsISupports;
|
||||||
interface Variant;
|
interface Variant;
|
||||||
|
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLCanvasElement : HTMLElement {
|
interface HTMLCanvasElement : HTMLElement {
|
||||||
[Pure, SetterThrows]
|
[CEReactions, Pure, SetterThrows]
|
||||||
attribute unsigned long width;
|
attribute unsigned long width;
|
||||||
[Pure, SetterThrows]
|
[CEReactions, Pure, SetterThrows]
|
||||||
attribute unsigned long height;
|
attribute unsigned long height;
|
||||||
|
|
||||||
[Throws]
|
[Throws]
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-dl-element
|
// http://www.whatwg.org/specs/web-apps/current-work/#the-dl-element
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLDListElement : HTMLElement {
|
interface HTMLDListElement : HTMLElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
||||||
partial interface HTMLDListElement {
|
partial interface HTMLDListElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute boolean compact;
|
attribute boolean compact;
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-data-element
|
* http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-data-element
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
[HTMLConstructor]
|
||||||
interface HTMLDataElement : HTMLElement {
|
interface HTMLDataElement : HTMLElement {
|
||||||
[SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute DOMString value;
|
attribute DOMString value;
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue