Stabilize and align Intersection Observers

- Fixes several crashes
- Aligns the feature with the W3C WD spec

Tag #249
This commit is contained in:
wolfbeast 2018-06-27 16:00:53 +02:00 committed by Roy Tam
commit 5af4107852
9 changed files with 111 additions and 64 deletions

View file

@ -3912,44 +3912,55 @@ Element::ClearDataset()
slots->mDataset = nullptr;
}
nsTArray<Element::nsDOMSlots::IntersectionObserverRegistration>*
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>*
Element::RegisteredIntersectionObservers()
{
nsDOMSlots* slots = DOMSlots();
return &slots->mRegisteredIntersectionObservers;
}
enum nsPreviousIntersectionThreshold {
eUninitialized = -2,
eNonIntersecting = -1
};
void
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
RegisteredIntersectionObservers()->AppendElement(
nsDOMSlots::IntersectionObserverRegistration { aObserver, -1 });
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
if (observers->Contains(aObserver)) {
return;
}
// Value can be:
// -2: Makes sure next calculated threshold always differs, leading to a
// notification task being scheduled.
// -1: Non-intersecting.
// >= 0: Intersecting, valid index of aObserver->mThresholds.
RegisteredIntersectionObservers()->Put(aObserver, eUninitialized);
}
void
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
for (uint32_t i = 0; i < observers->Length(); ++i) {
nsDOMSlots::IntersectionObserverRegistration reg = observers->ElementAt(i);
if (reg.observer == aObserver) {
observers->RemoveElementAt(i);
break;
}
}
observers->Remove(aObserver);
}
bool
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
{
nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
for (auto& reg : *observers) {
if (reg.observer == aObserver && reg.previousThreshold != aThreshold) {
reg.previousThreshold = aThreshold;
return true;
}
if (!observers->Contains(aObserver)) {
return false;
}
int32_t previousThreshold = observers->Get(aObserver);
if (previousThreshold != aThreshold) {
observers->Put(aObserver, aThreshold);
return true;
}
return false;
}