bug 1483963, cache the index of a child node when ordering animations for event dispatch, r=hiro,ehsan

--HG--
extra : rebase_source : f98586625b199e7b2d0eb7db8dc9c1c5235289fe
This commit is contained in:
Olli Pettay 2018-09-05 00:31:57 +03:00
parent 017918778d
commit 57b81277a0
9 changed files with 74 additions and 10 deletions

View File

@ -61,6 +61,7 @@ public:
: DOMEventTargetHelper(aGlobal)
, mPlaybackRate(1.0)
, mAnimationIndex(sNextAnimationIndex++)
, mCachedChildIndex(-1)
, mPendingState(PendingState::NotPending)
, mFinishedAtLastComposeStyle(false)
, mIsRelevant(false)
@ -405,6 +406,8 @@ public:
*/
virtual void MaybeQueueCancelEvent(const StickyTimeDuration& aActiveTime) {};
int32_t& CachedChildIndexRef() { return mCachedChildIndex; }
protected:
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void CancelNoUpdate();
@ -579,6 +582,10 @@ protected:
// possible for two different objects to have the same index.
uint64_t mAnimationIndex;
// While ordering Animation objects for event dispatch, the index of the
// target node in its parent may be cached in mCachedChildIndex.
int32_t mCachedChildIndex;
// Indicates if the animation is in the pending state (and what state it is
// waiting to enter when it finished pending). We use this rather than
// checking if this animation is tracked by a PendingAnimationTracker because

View File

@ -247,6 +247,10 @@ private:
return;
}
for (auto& pending : mPendingEvents) {
pending.mAnimation->CachedChildIndexRef() = -1;
}
// FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
// fixed.
std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),

View File

@ -2654,9 +2654,12 @@ nsContentUtils::GetCommonFlattenedTreeAncestorForStyle(Element* aElement1,
/* static */
bool
nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2)
nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2,
int32_t* aNode1Index,
int32_t* aNode2Index)
{
return (aNode2->CompareDocumentPosition(*aNode1) &
// Note, CompareDocumentPosition takes the latter params in different order.
return (aNode2->CompareDocumentPosition(*aNode1, aNode2Index, aNode1Index) &
(Node_Binding::DOCUMENT_POSITION_PRECEDING |
Node_Binding::DOCUMENT_POSITION_DISCONNECTED)) ==
Node_Binding::DOCUMENT_POSITION_PRECEDING;

View File

@ -434,8 +434,14 @@ public:
/**
* Returns true if aNode1 is before aNode2 in the same connected
* tree.
* aNode1Index and aNode2Index are in/out arguments. If non-null, and value is
* not -1, that value is used instead of calling slow ComputeIndexOf on the
* parent node. If value is -1, the value will be set to the return value of
* ComputeIndexOf.
*/
static bool PositionIsBefore(nsINode* aNode1, nsINode* aNode2);
static bool PositionIsBefore(nsINode* aNode1, nsINode* aNode2,
int32_t* aNode1Index = nullptr,
int32_t* aNode2Index = nullptr);
/**
* Utility routine to compare two "points", where a point is a

View File

@ -752,7 +752,9 @@ nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix)
}
uint16_t
nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
nsINode::CompareDocumentPosition(nsINode& aOtherNode,
int32_t* aThisIndex,
int32_t* aOtherIndex) const
{
if (this == &aOtherNode) {
return 0;
@ -852,9 +854,38 @@ nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
// child1 or child2 can be an attribute here. This will work fine since
// ComputeIndexOf will return -1 for the attribute making the
// attribute be considered before any child.
return parent->ComputeIndexOf(child1) < parent->ComputeIndexOf(child2) ?
int32_t child1Index;
bool cachedChild1Index = false;
if (&aOtherNode == child1 && aOtherIndex) {
cachedChild1Index = true;
child1Index = *aOtherIndex != -1 ?
*aOtherIndex : parent->ComputeIndexOf(child1);
} else {
child1Index = parent->ComputeIndexOf(child1);
}
int32_t child2Index;
bool cachedChild2Index = false;
if (this == child2 && aThisIndex) {
cachedChild2Index = true;
child2Index = *aThisIndex != -1 ?
*aThisIndex : parent->ComputeIndexOf(child2);
} else {
child2Index = parent->ComputeIndexOf(child2);
}
uint16_t retVal = child1Index < child2Index ?
Node_Binding::DOCUMENT_POSITION_PRECEDING :
Node_Binding::DOCUMENT_POSITION_FOLLOWING;
if (cachedChild1Index) {
*aOtherIndex = child1Index;
}
if (cachedChild2Index) {
*aThisIndex = child2Index;
}
return retVal;
}
parent = child1;
}

View File

@ -1769,7 +1769,11 @@ public:
{
return HasChildren();
}
uint16_t CompareDocumentPosition(nsINode& aOther) const;
// See nsContentUtils::PositionIsBefore for aThisIndex and aOtherIndex usage.
uint16_t CompareDocumentPosition(nsINode& aOther,
int32_t* aThisIndex = nullptr,
int32_t* aOtherIndex = nullptr) const;
void GetNodeValue(nsAString& aNodeValue)
{
GetNodeValueInternal(aNodeValue);

View File

@ -122,14 +122,17 @@ public:
return mTarget == aOther.mTarget;
}
bool LessThan(const OwningElementRef& aOther) const
bool LessThan(int32_t& aChildIndex, const OwningElementRef& aOther,
int32_t& aOtherChildIndex) const
{
MOZ_ASSERT(mTarget.mElement && aOther.mTarget.mElement,
"Elements to compare should not be null");
if (mTarget.mElement != aOther.mTarget.mElement) {
return nsContentUtils::PositionIsBefore(mTarget.mElement,
aOther.mTarget.mElement);
aOther.mTarget.mElement,
&aChildIndex,
&aOtherChildIndex);
}
return mTarget.mPseudoType == CSSPseudoElementType::NotPseudo ||

View File

@ -155,7 +155,10 @@ CSSAnimation::HasLowerCompositeOrderThan(const CSSAnimation& aOther) const
// 1. Sort by document order
if (!mOwningElement.Equals(aOther.mOwningElement)) {
return mOwningElement.LessThan(aOther.mOwningElement);
return mOwningElement.LessThan(
const_cast<CSSAnimation*>(this)->CachedChildIndexRef(),
aOther.mOwningElement,
const_cast<CSSAnimation*>(&aOther)->CachedChildIndexRef());
}
// 2. (Same element and pseudo): Sort by position in animation-name

View File

@ -362,7 +362,10 @@ CSSTransition::HasLowerCompositeOrderThan(const CSSTransition& aOther) const
// 1. Sort by document order
if (!mOwningElement.Equals(aOther.mOwningElement)) {
return mOwningElement.LessThan(aOther.mOwningElement);
return mOwningElement.LessThan(
const_cast<CSSTransition*>(this)->CachedChildIndexRef(),
aOther.mOwningElement,
const_cast<CSSTransition*>(&aOther)->CachedChildIndexRef());
}
// 2. (Same element and pseudo): Sort by transition generation