Bug 1183461 part 7 - Add EventInfoComparator and sort events; r=heycam

This patch also reworks the dispatch of events in nsRefreshDriver. Previously
the refresh driver would dispatch the transition events for all subdocuments
then the animation events. This arrangement is complicated and not obviously
necessary. This patch simplifies this arrangement by dispatching transition
events and animation events for each document before proceeding to
subdocuments.
This commit is contained in:
Brian Birtles 2015-09-15 14:05:49 +09:00
parent 0a45589b29
commit 8304eb03e5
5 changed files with 71 additions and 42 deletions

View File

@ -1319,44 +1319,32 @@ nsRefreshDriver::DispatchPendingEvents()
}
}
namespace {
enum class AnimationEventType {
CSSAnimations,
CSSTransitions
};
struct DispatchAnimationEventParams {
AnimationEventType mEventType;
nsRefreshDriver* mRefreshDriver;
};
}
static bool
DispatchAnimationEventsOnSubDocuments(nsIDocument* aDocument,
void* aParams)
void* aRefreshDriver)
{
MOZ_ASSERT(aParams, "Animation event parameters should be set");
auto params = static_cast<DispatchAnimationEventParams*>(aParams);
nsIPresShell* shell = aDocument->GetShell();
if (!shell) {
return true;
}
nsPresContext* context = shell->GetPresContext();
if (!context || context->RefreshDriver() != params->mRefreshDriver) {
if (!context || context->RefreshDriver() != aRefreshDriver) {
return true;
}
nsCOMPtr<nsIDocument> kungFuDeathGrip(aDocument);
if (params->mEventType == AnimationEventType::CSSAnimations) {
context->AnimationManager()->DispatchEvents();
} else {
context->TransitionManager()->DispatchEvents();
}
context->TransitionManager()->SortEvents();
context->AnimationManager()->SortEvents();
// Dispatch transition events first since transitions conceptually sit
// below animations in terms of compositing order.
context->TransitionManager()->DispatchEvents();
context->AnimationManager()->DispatchEvents();
aDocument->EnumerateSubDocuments(DispatchAnimationEventsOnSubDocuments,
aParams);
aRefreshDriver);
return true;
}
@ -1368,19 +1356,7 @@ nsRefreshDriver::DispatchAnimationEvents()
return;
}
nsIDocument* doc = mPresContext->Document();
// Dispatch transition events first since transitions conceptually sit
// below animations in terms of compositing order.
DispatchAnimationEventParams params { AnimationEventType::CSSTransitions,
this };
DispatchAnimationEventsOnSubDocuments(doc, &params);
if (!mPresContext) {
return;
}
params.mEventType = AnimationEventType::CSSAnimations;
DispatchAnimationEventsOnSubDocuments(doc, &params);
DispatchAnimationEventsOnSubDocuments(mPresContext->Document(), this);
}
void

View File

@ -373,7 +373,7 @@ CommonAnimationManager::FlushAnimations()
MOZ_ASSERT(collection->mElement->GetComposedDoc() ==
mPresContext->Document(),
"Should not have a transition/animations collection for an "
"Should not have a transition/animation collection for an "
"element that is not part of the document tree");
collection->RequestRestyle(AnimationCollection::RestyleType::Standard);

View File

@ -6,12 +6,14 @@
#ifndef mozilla_css_AnimationCommon_h
#define mozilla_css_AnimationCommon_h
#include <algorithm> // For <std::stable_sort>
#include "nsIStyleRuleProcessor.h"
#include "nsIStyleRule.h"
#include "nsRefreshDriver.h"
#include "nsChangeHint.h"
#include "nsCSSProperty.h"
#include "nsDisplayList.h" // For nsDisplayItem::Type
#include "mozilla/AnimationComparator.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h"
@ -502,23 +504,49 @@ template <class EventInfo>
class DelayedEventDispatcher
{
public:
DelayedEventDispatcher() : mIsSorted(true) { }
void QueueEvent(EventInfo&& aEventInfo)
{
mPendingEvents.AppendElement(mozilla::Forward<EventInfo>(aEventInfo));
mPendingEvents.AppendElement(Forward<EventInfo>(aEventInfo));
mIsSorted = false;
}
// This is exposed as a separate method so that when we are dispatching
// *both* transition events and animation events we can sort both lists
// once using the current state of the document before beginning any
// dispatch.
void SortEvents()
{
if (mIsSorted) {
return;
}
// FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
// fixed.
std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),
EventInfoLessThan());
mIsSorted = true;
}
// Takes a reference to the owning manager's pres context so it can
// detect if the pres context is destroyed while dispatching one of
// the events.
//
// This will call SortEvents automatically if it has not already been
// called.
void DispatchEvents(nsPresContext* const & aPresContext)
{
if (!aPresContext || mPendingEvents.IsEmpty()) {
return;
}
SortEvents();
EventArray events;
mPendingEvents.SwapElements(events);
// FIXME: Sort events here in timeline order, then document order
// mIsSorted will be set to true by SortEvents above, and we leave it
// that way since mPendingEvents is now empty
for (EventInfo& info : events) {
EventDispatcher::Dispatch(info.mElement, aPresContext, &info.mEvent);
@ -528,7 +556,11 @@ public:
}
}
void ClearEventQueue() { mPendingEvents.Clear(); }
void ClearEventQueue()
{
mPendingEvents.Clear();
mIsSorted = true;
}
bool HasQueuedEvents() const { return !mPendingEvents.IsEmpty(); }
// Methods for supporting cycle-collection
@ -540,12 +572,31 @@ public:
ImplCycleCollectionTraverse(*aCallback, info.mAnimation, aName);
}
}
void Unlink() { mPendingEvents.Clear(); }
void Unlink() { ClearEventQueue(); }
protected:
typedef nsTArray<EventInfo> EventArray;
class EventInfoLessThan
{
public:
bool operator()(const EventInfo& a, const EventInfo& b) const
{
if (a.mTimeStamp != b.mTimeStamp) {
// Null timestamps sort first
if (a.mTimeStamp.IsNull() || b.mTimeStamp.IsNull()) {
return a.mTimeStamp.IsNull();
} else {
return a.mTimeStamp < b.mTimeStamp;
}
}
AnimationPtrComparator<nsRefPtr<dom::Animation>> comparator;
return comparator.LessThan(a.mAnimation, b.mAnimation);
}
};
typedef nsTArray<EventInfo> EventArray;
EventArray mPendingEvents;
bool mIsSorted;
};
template <class EventInfo>

View File

@ -330,6 +330,7 @@ public:
* contexts are created.
*/
void DispatchEvents() { mEventDispatcher.DispatchEvents(mPresContext); }
void SortEvents() { mEventDispatcher.SortEvents(); }
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
// Stop animations on the element. This method takes the real element

View File

@ -304,6 +304,7 @@ public:
}
void DispatchEvents() { mEventDispatcher.DispatchEvents(mPresContext); }
void SortEvents() { mEventDispatcher.SortEvents(); }
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
protected: