Backed out 4 changesets (bug 1315885) for merge conflicts with bug 1377993.

Backed out changeset c6dcdfe7ac54 (bug 1315885)
Backed out changeset c8bc78492b81 (bug 1315885)
Backed out changeset 7ba49d85f30c (bug 1315885)
Backed out changeset d592ae3b61bf (bug 1315885)
This commit is contained in:
Ryan VanderMeulen 2017-07-18 12:58:46 -04:00
Родитель 5e6827da6d
Коммит f142e0a216
6 изменённых файлов: 143 добавлений и 160 удалений

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

@ -55,10 +55,6 @@ CustomElementCallback::Call()
mArgs.name, mArgs.oldValue, mArgs.newValue, rv);
break;
}
// If callbacks throw exceptions, it'll be handled and reported in
// Lifecycle*Callback::Call function.
rv.SuppressException();
}
void
@ -92,12 +88,26 @@ CustomElementData::CustomElementData(nsIAtom* aType)
CustomElementData::CustomElementData(nsIAtom* aType, State aState)
: mType(aType)
, mCurrentCallback(-1)
, mElementIsBeingCreated(false)
, mCreatedCallbackInvoked(true)
, mAssociatedMicroTask(-1)
, mState(aState)
{
}
void
CustomElementData::RunCallbackQueue()
{
// Note: It's possible to re-enter this method.
while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) {
mCallbackQueue[mCurrentCallback]->Call();
}
mCallbackQueue.Clear();
mCurrentCallback = -1;
}
//-----------------------------------------------------
// CustomElementRegistry
@ -114,7 +124,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
auto& callbacks = iter.UserData()->mCallbacks;
nsAutoPtr<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks;
if (callbacks->mAttributeChangedCallback.WasPassed()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
@ -178,6 +188,43 @@ CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject)
nsContentUtils::IsWebComponentsEnabled();
}
/* static */ void
CustomElementRegistry::ProcessTopElementQueue()
{
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
nsTArray<RefPtr<CustomElementData>>& stack = *sProcessingStack;
uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
// Callback queue may have already been processed in an earlier
// element queue or in an element queue that was popped
// off more recently.
if (stack[i]->mAssociatedMicroTask != -1) {
stack[i]->RunCallbackQueue();
stack[i]->mAssociatedMicroTask = -1;
}
}
// If this was actually the base element queue, don't bother trying to pop
// the first "queue" marker (sentinel).
if (firstQueue != 0) {
stack.SetLength(firstQueue);
} else {
// Don't pop sentinel for base element queue.
stack.SetLength(1);
}
}
/* static */ void
CustomElementRegistry::XPCOMShutdown()
{
sProcessingStack.reset();
}
/* static */ Maybe<nsTArray<RefPtr<CustomElementData>>>
CustomElementRegistry::sProcessingStack;
CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow)
, mIsCustomDefinitionRunning(false)
@ -187,6 +234,12 @@ CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
MOZ_ALWAYS_TRUE(mConstructors.init());
mozilla::HoldJSObjects(this);
if (!sProcessingStack) {
sProcessingStack.emplace();
// Add the base queue sentinel to the processing stack.
sProcessingStack->AppendElement((CustomElementData*) nullptr);
}
}
CustomElementRegistry::~CustomElementRegistry()
@ -290,15 +343,14 @@ CustomElementRegistry::SetupCustomElement(Element* aElement,
// Enqueuing the created callback will set the CustomElementData on the
// element, causing prototype swizzling to occur in Element::WrapObject.
// We make it synchronously for createElement/createElementNS in order to
// pass tests. It'll be removed when we deprecate custom elements v0.
SyncInvokeReactions(nsIDocument::eCreated, aElement, definition);
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, definition);
}
UniquePtr<CustomElementCallback>
CustomElementRegistry::CreateCustomElementCallback(
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition)
void
CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
LifecycleCallbackArgs* aArgs,
CustomElementDefinition* aDefinition)
{
RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
MOZ_ASSERT(elementData, "CustomElementData should exist");
@ -317,7 +369,7 @@ CustomElementRegistry::CreateCustomElementCallback(
if (!definition || definition->mLocalName != info->NameAtom()) {
// Trying to enqueue a callback for an element that is not
// a custom element. We are done, nothing to do.
return nullptr;
return;
}
}
@ -351,7 +403,7 @@ CustomElementRegistry::CreateCustomElementCallback(
// If there is no such callback, stop.
if (!func) {
return nullptr;
return;
}
if (aType == nsIDocument::eCreated) {
@ -359,62 +411,55 @@ CustomElementRegistry::CreateCustomElementCallback(
} else if (!elementData->mCreatedCallbackInvoked) {
// Callbacks other than created callback must not be enqueued
// until after the created callback has been invoked.
return nullptr;
return;
}
// Add CALLBACK to ELEMENT's callback queue.
auto callback =
MakeUnique<CustomElementCallback>(aCustomElement, aType, func, elementData);
CustomElementCallback* callback = new CustomElementCallback(aCustomElement,
aType,
func,
elementData);
// Ownership of callback is taken by mCallbackQueue.
elementData->mCallbackQueue.AppendElement(callback);
if (aArgs) {
callback->SetArgs(*aArgs);
}
return Move(callback);
}
if (!elementData->mElementIsBeingCreated) {
CustomElementData* lastData =
sProcessingStack->SafeLastElement(nullptr);
void
CustomElementRegistry::SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
CustomElementDefinition* aDefinition)
{
auto callback = CreateCustomElementCallback(aType, aCustomElement, nullptr,
aDefinition);
if (!callback) {
return;
// A new element queue needs to be pushed if the queue at the
// top of the stack is associated with another microtask level.
bool shouldPushElementQueue =
(!lastData || lastData->mAssociatedMicroTask <
static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
// Push a new element queue onto the processing stack when appropriate
// (when we enter a new microtask).
if (shouldPushElementQueue) {
// Push a sentinel value on the processing stack to mark the
// boundary between the element queues.
sProcessingStack->AppendElement((CustomElementData*) nullptr);
}
sProcessingStack->AppendElement(elementData);
elementData->mAssociatedMicroTask =
static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
// Add a script runner to pop and process the element queue at
// the top of the processing stack.
if (shouldPushElementQueue) {
// Lifecycle callbacks enqueued by user agent implementation
// should be invoked prior to returning control back to script.
// Create a script runner to process the top of the processing
// stack as soon as it is safe to run script.
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
"dom::CustomElementRegistry::EnqueueLifecycleCallback",
&CustomElementRegistry::ProcessTopElementQueue);
nsContentUtils::AddScriptRunner(runnable);
}
}
UniquePtr<CustomElementReaction> reaction(Move(
MakeUnique<CustomElementCallbackReaction>(this, aDefinition,
Move(callback))));
RefPtr<SyncInvokeReactionRunnable> runnable =
new SyncInvokeReactionRunnable(Move(reaction), aCustomElement);
nsContentUtils::AddScriptRunner(runnable);
}
void
CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
LifecycleCallbackArgs* aArgs,
CustomElementDefinition* aDefinition)
{
auto callback =
CreateCustomElementCallback(aType, aCustomElement, aArgs, aDefinition);
if (!callback) {
return;
}
DocGroup* docGroup = mWindow->GetDocGroup();
if (!docGroup) {
return;
}
CustomElementReactionsStack* reactionsStack =
docGroup->CustomElementReactionsStack();
reactionsStack->EnqueueCallbackReaction(this, aCustomElement, aDefinition,
Move(callback));
}
void
@ -898,16 +943,6 @@ CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegi
Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
}
void
CustomElementReactionsStack::EnqueueCallbackReaction(CustomElementRegistry* aRegistry,
Element* aElement,
CustomElementDefinition* aDefinition,
UniquePtr<CustomElementCallback> aCustomElementCallback)
{
Enqueue(aElement, new CustomElementCallbackReaction(aRegistry, aDefinition,
Move(aCustomElementCallback)));
}
void
CustomElementReactionsStack::Enqueue(Element* aElement,
CustomElementReaction* aReaction)
@ -949,7 +984,6 @@ CustomElementReactionsStack::InvokeBackupQueue()
void
CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue)
{
// Note: It's possible to re-enter this method.
for (uint32_t i = 0; i < aElementQueue.Length(); ++i) {
nsCOMPtr<Element> element = do_QueryReferent(aElementQueue[i]);
@ -960,14 +994,10 @@ CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue)
RefPtr<CustomElementData> elementData = element->GetCustomElementData();
MOZ_ASSERT(elementData, "CustomElementData should exist");
auto& reactions = elementData->mReactionQueue;
nsTArray<nsAutoPtr<CustomElementReaction>>& reactions =
elementData->mReactionQueue;
for (uint32_t j = 0; j < reactions.Length(); ++j) {
// Transfer the ownership of the entry due to reentrant invocation of
// this funciton. The entry will be removed when bug 1379573 is landed.
auto reaction(Move(reactions.ElementAt(j)));
if (reaction) {
reaction->Invoke(element);
}
reactions.ElementAt(j)->Invoke(element);
}
reactions.Clear();
}
@ -1002,14 +1032,5 @@ CustomElementUpgradeReaction::Invoke(Element* aElement)
mRegistry->Upgrade(aElement, mDefinition);
}
//-----------------------------------------------------
// CustomElementCallbackReaction
/* virtual */ void
CustomElementCallbackReaction::Invoke(Element* aElement)
{
mCustomElementCallback->Call();
}
} // namespace dom
} // namespace mozilla

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

@ -85,14 +85,23 @@ struct CustomElementData
explicit CustomElementData(nsIAtom* aType);
CustomElementData(nsIAtom* aType, State aState);
// Objects in this array are transient and empty after each microtask
// checkpoint.
nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
// Custom element type, for <button is="x-button"> or <x-button>
// this would be x-button.
nsCOMPtr<nsIAtom> mType;
// The callback that is next to be processed upon calling RunCallbackQueue.
int32_t mCurrentCallback;
// Element is being created flag as described in the custom elements spec.
bool mElementIsBeingCreated;
// Flag to determine if the created callback has been invoked, thus it
// determines if other callbacks can be enqueued.
bool mCreatedCallbackInvoked;
// The microtask level associated with the callbacks in the callback queue,
// it is used to determine if a new queue needs to be pushed onto the
// processing stack.
int32_t mAssociatedMicroTask;
// Custom element state as described in the custom element spec.
State mState;
// custom element reaction queue as described in the custom element spec.
@ -101,7 +110,10 @@ struct CustomElementData
// 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;
AutoTArray<nsAutoPtr<CustomElementReaction>, 3> mReactionQueue;
// Empties the callback queue.
void RunCallbackQueue();
private:
virtual ~CustomElementData() {}
@ -131,7 +143,7 @@ struct CustomElementDefinition
JS::Heap<JSObject *> mPrototype;
// The lifecycle callbacks to call for this custom element.
UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
nsAutoPtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
// A construction stack.
// TODO: Bug 1287348 - Implement construction stack for upgrading an element
@ -152,13 +164,10 @@ public:
: mRegistry(aRegistry)
, mDefinition(aDefinition)
{
}
};
virtual ~CustomElementReaction() = default;
virtual void Invoke(Element* aElement) = 0;
virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const
{
}
protected:
CustomElementRegistry* mRegistry;
@ -178,27 +187,6 @@ private:
virtual void Invoke(Element* aElement) override;
};
class CustomElementCallbackReaction final : public CustomElementReaction
{
public:
CustomElementCallbackReaction(CustomElementRegistry* aRegistry,
CustomElementDefinition* aDefinition,
UniquePtr<CustomElementCallback> aCustomElementCallback)
: CustomElementReaction(aRegistry, aDefinition)
, mCustomElementCallback(Move(aCustomElementCallback))
{
}
virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
{
mCustomElementCallback->Traverse(aCb);
}
private:
virtual void Invoke(Element* aElement) override;
UniquePtr<CustomElementCallback> mCustomElementCallback;
};
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions-stack
class CustomElementReactionsStack
{
@ -224,15 +212,6 @@ public:
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(CustomElementRegistry* aRegistry,
Element* aElement,
CustomElementDefinition* aDefinition,
UniquePtr<CustomElementCallback> aCustomElementCallback);
// [CEReactions] Before executing the algorithm's steps
// Push a new element queue onto the custom element reactions stack.
void CreateAndPushElementQueue();
@ -301,6 +280,10 @@ public:
static bool IsCustomElementEnabled(JSContext* aCx = nullptr,
JSObject* aObject = nullptr);
static void ProcessTopElementQueue();
static void XPCOMShutdown();
explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow);
/**
@ -333,13 +316,6 @@ public:
private:
~CustomElementRegistry();
UniquePtr<CustomElementCallback> CreateCustomElementCallback(
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition);
void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
CustomElementDefinition* aDefinition);
/**
* Registers an unresolved custom element that is a candidate for
* upgrade when the definition is registered via registerElement.
@ -386,6 +362,14 @@ private:
nsCOMPtr<nsPIDOMWindowInner> mWindow;
// Array representing the processing stack in the custom elements
// specification. The processing stack is conceptually a stack of
// element queues. Each queue is represented by a sequence of
// CustomElementData in this array, separated by nullptr that
// represent the boundaries of the items in the stack. The first
// queue in the stack is the base element queue.
static mozilla::Maybe<nsTArray<RefPtr<CustomElementData>>> sProcessingStack;
// It is used to prevent reentrant invocations of element definition.
bool mIsCustomDefinitionRunning;
@ -408,28 +392,6 @@ private:
CustomElementRegistry* mRegistry;
};
class SyncInvokeReactionRunnable : public mozilla::Runnable {
public:
SyncInvokeReactionRunnable(
UniquePtr<CustomElementReaction> aReaction, Element* aCustomElement)
: Runnable(
"dom::CustomElementRegistry::SyncInvokeReactionRunnable")
, mReaction(Move(aReaction))
, mCustomElement(aCustomElement)
{
}
NS_IMETHOD Run() override
{
mReaction->Invoke(mCustomElement);
return NS_OK;
}
private:
UniquePtr<CustomElementReaction> mReaction;
Element* mCustomElement;
};
public:
nsISupports* GetParentObject() const;

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

@ -711,10 +711,8 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb,
cb.NoteXPCOMChild(mClassList.get());
if (mCustomElementData) {
for (uint32_t i = 0; i < mCustomElementData->mReactionQueue.Length(); i++) {
if (mCustomElementData->mReactionQueue[i]) {
mCustomElementData->mReactionQueue[i]->Traverse(cb);
}
for (uint32_t i = 0; i < mCustomElementData->mCallbackQueue.Length(); i++) {
mCustomElementData->mCallbackQueue[i]->Traverse(cb);
}
}

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

@ -28,8 +28,7 @@ function testChangeAttributeInCreatedCallback() {
createdCallbackCalled = true;
is(attributeChangedCallbackCalled, false, "Attribute changed callback should not have been called prior to setting the attribute.");
this.setAttribute("foo", "bar");
is(attributeChangedCallbackCalled, true, "While element is being created, element should be added to the current element callback queue.");
runNextTest();
is(attributeChangedCallbackCalled, false, "While element is being created, element should not be added to the current element callback queue.");
};
p.attributeChangedCallback = function(name, oldValue, newValue) {
@ -37,6 +36,7 @@ function testChangeAttributeInCreatedCallback() {
is(attributeChangedCallbackCalled, false, "attributeChanged callback should only be called once in this tests.");
is(newValue, "bar", "The new value should be 'bar'");
attributeChangedCallbackCalled = true;
runNextTest();
};
document.registerElement("x-one", { prototype: p });

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

@ -17,7 +17,7 @@ interface ShadowRoot : DocumentFragment
HTMLCollection getElementsByTagName(DOMString localName);
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString classNames);
[CEReactions, SetterThrows, TreatNullAs=EmptyString]
[SetterThrows,TreatNullAs=EmptyString]
attribute DOMString innerHTML;
readonly attribute Element host;
readonly attribute ShadowRoot? olderShadowRoot;

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

@ -434,6 +434,8 @@ nsLayoutStatics::Shutdown()
DisplayItemClip::Shutdown();
CustomElementRegistry::XPCOMShutdown();
CacheObserver::Shutdown();
PromiseDebugging::Shutdown();