Bug 1445392: Make HTMLSlotElement slot change event stuff not linear. r=smaug

Also fix refcount churn in nsDOMMutationObserver and such.

MozReview-Commit-ID: GwEB0LZY7Ss
This commit is contained in:
Emilio Cobos Álvarez 2018-05-07 19:09:19 +02:00
Родитель 21cb54ff16
Коммит bc958c264f
5 изменённых файлов: 47 добавлений и 35 удалений

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

@ -159,13 +159,10 @@ DocGroup::GetValidAccessPtr()
}
void
DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
DocGroup::SignalSlotChange(HTMLSlotElement& aSlot)
{
if (mSignalSlotList.Contains(aSlot)) {
return;
}
mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
MOZ_ASSERT(!mSignalSlotList.Contains(&aSlot));
mSignalSlotList.AppendElement(&aSlot);
if (!sPendingDocGroups) {
// Queue a mutation observer compound microtask.
@ -176,5 +173,16 @@ DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
sPendingDocGroups->AppendElement(this);
}
void
DocGroup::MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest)
{
aDest.SetCapacity(aDest.Length() + mSignalSlotList.Length());
for (RefPtr<HTMLSlotElement>& slot : mSignalSlotList) {
slot->RemovedFromSignalSlotList();
aDest.AppendElement(Move(slot));
}
mSignalSlotList.Clear();
}
}
}

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

@ -113,19 +113,11 @@ public:
// DocGroup.
bool* GetValidAccessPtr();
// Append aSlot to the list of signal slot list, if it's not in it already
// list, and queue a mutation observer microtask.
void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
// Append aSlot to the list of signal slot list, and queue a mutation observer
// microtask.
void SignalSlotChange(HTMLSlotElement& aSlot);
const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
{
return mSignalSlotList;
}
void ClearSignalSlotList()
{
mSignalSlotList.Clear();
}
void MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest);
// List of DocGroups that has non-empty signal slot list.
static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;

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

@ -900,17 +900,15 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
{
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
// Let signalList be a copy of unit of related similar-origin browsing
// contexts' signal slot list.
// This loop implements:
// * Let signalList be a copy of unit of related similar-origin browsing
// contexts' signal slot list.
// * Empty unit of related similar-origin browsing contexts' signal slot
// list.
nsTArray<RefPtr<HTMLSlotElement>> signalList;
if (DocGroup::sPendingDocGroups) {
for (uint32_t i = 0; i < DocGroup::sPendingDocGroups->Length(); ++i) {
DocGroup* docGroup = DocGroup::sPendingDocGroups->ElementAt(i);
signalList.AppendElements(docGroup->SignalSlotList());
// Empty unit of related similar-origin browsing contexts' signal slot
// list.
docGroup->ClearSignalSlotList();
for (DocGroup* docGroup : *DocGroup::sPendingDocGroups) {
docGroup->MoveSignalSlotListTo(signalList);
}
delete DocGroup::sPendingDocGroups;
DocGroup::sPendingDocGroups = nullptr;

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

@ -34,9 +34,7 @@ HTMLSlotElement::HTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>& aNode
{
}
HTMLSlotElement::~HTMLSlotElement()
{
}
HTMLSlotElement::~HTMLSlotElement() = default;
NS_IMPL_ADDREF_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
NS_IMPL_RELEASE_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
@ -216,14 +214,19 @@ HTMLSlotElement::ClearAssignedNodes()
}
void
HTMLSlotElement::EnqueueSlotChangeEvent() const
HTMLSlotElement::EnqueueSlotChangeEvent()
{
if (mInSignalSlotList) {
return;
}
DocGroup* docGroup = OwnerDoc()->GetDocGroup();
if (!docGroup) {
return;
}
docGroup->SignalSlotChange(this);
mInSignalSlotList = true;
docGroup->SignalSlotChange(*this);
}
void

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

@ -63,15 +63,26 @@ public:
void RemoveAssignedNode(nsINode* aNode);
void ClearAssignedNodes();
void EnqueueSlotChangeEvent() const;
void EnqueueSlotChangeEvent();
void RemovedFromSignalSlotList()
{
MOZ_ASSERT(mInSignalSlotList);
mInSignalSlotList = false;
}
void FireSlotChangeEvent();
protected:
virtual ~HTMLSlotElement();
virtual JSObject*
WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
nsTArray<RefPtr<nsINode>> mAssignedNodes;
// Whether we're in the signal slot list of our unit of related similar-origin
// browsing contexts.
//
// https://dom.spec.whatwg.org/#signal-slot-list
bool mInSignalSlotList = false;
};
} // namespace dom