зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1302071 - Part 5: Bucket PresContext invalidations by transaction ID, and only deliver them when the associated composite has completed. r=tnikkel
This patch does a few things: * Buckets invalidations by transaction ID, and sends MozAfterPaints events for them when the associated composite completes. * Creates a separate EventualDidPaint timer for each transaction ID we have invalidations for rather than just using one. * Removes NotifyDidPaintForSubtree(PAINT_LAYERS), as it was only necessary for the existing bucketing mechanism. MozReview-Commit-ID: JERMsgxhPQd --HG-- extra : rebase_source : aad23cb4e77afe12ddf4ebf21db36ae6edec9692
This commit is contained in:
Родитель
f23fe59b03
Коммит
4be7d40139
|
@ -6288,7 +6288,9 @@ public:
|
|||
}
|
||||
~nsAutoNotifyDidPaint()
|
||||
{
|
||||
mShell->GetPresContext()->NotifyDidPaintForSubtree(mFlags);
|
||||
if (mFlags & nsIPresShell::PAINT_COMPOSITE) {
|
||||
mShell->GetPresContext()->NotifyDidPaintForSubtree();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
#include "mozilla/dom/PerformanceTiming.h"
|
||||
#include "mozilla/layers/APZThreadUtils.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
|
||||
|
@ -400,7 +401,7 @@ void
|
|||
nsPresContext::LastRelease()
|
||||
{
|
||||
if (IsRoot()) {
|
||||
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
|
||||
static_cast<nsRootPresContext*>(this)->CancelAllDidPaintTimers();
|
||||
}
|
||||
if (mMissingFonts) {
|
||||
mMissingFonts->Clear();
|
||||
|
@ -1037,7 +1038,7 @@ nsPresContext::DetachShell()
|
|||
thisRoot->CancelApplyPluginGeometryTimer();
|
||||
|
||||
// The did-paint timer also depends on a non-null pres shell.
|
||||
thisRoot->CancelDidPaintTimer();
|
||||
thisRoot->CancelAllDidPaintTimers();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2485,11 +2486,23 @@ nsPresContext::NotifyInvalidation(uint64_t aTransactionId, const nsRect& aRect)
|
|||
if (!pc) {
|
||||
nsRootPresContext* rpc = GetRootPresContext();
|
||||
if (rpc) {
|
||||
rpc->EnsureEventualDidPaintEvent();
|
||||
rpc->EnsureEventualDidPaintEvent(aTransactionId);
|
||||
}
|
||||
}
|
||||
|
||||
mInvalidateRequestsSinceLastPaint.AppendElement(aRect);
|
||||
TransactionInvalidations* transaction = nullptr;
|
||||
for (TransactionInvalidations& t : mTransactions) {
|
||||
if (t.mTransactionId == aTransactionId) {
|
||||
transaction = &t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!transaction) {
|
||||
transaction = mTransactions.AppendElement();
|
||||
transaction->mTransactionId = aTransactionId;
|
||||
}
|
||||
|
||||
transaction->mInvalidations.AppendElement(aRect);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
@ -2530,13 +2543,12 @@ nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
|
|||
}
|
||||
|
||||
struct NotifyDidPaintSubdocumentCallbackClosure {
|
||||
uint32_t mFlags;
|
||||
uint64_t mTransactionId;
|
||||
const mozilla::TimeStamp& mTimeStamp;
|
||||
bool mNeedsAnotherDidPaintNotification;
|
||||
};
|
||||
static bool
|
||||
NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
|
||||
/* static */ bool
|
||||
nsPresContext::NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
|
||||
{
|
||||
NotifyDidPaintSubdocumentCallbackClosure* closure =
|
||||
static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
|
||||
|
@ -2544,9 +2556,9 @@ NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
|
|||
if (shell) {
|
||||
nsPresContext* pc = shell->GetPresContext();
|
||||
if (pc) {
|
||||
pc->NotifyDidPaintForSubtree(closure->mFlags, closure->mTransactionId,
|
||||
pc->NotifyDidPaintForSubtree(closure->mTransactionId,
|
||||
closure->mTimeStamp);
|
||||
if (pc->IsDOMPaintEventPending()) {
|
||||
if (pc->mFireAfterPaintEvents) {
|
||||
closure->mNeedsAnotherDidPaintNotification = true;
|
||||
}
|
||||
}
|
||||
|
@ -2585,11 +2597,11 @@ public:
|
|||
};
|
||||
|
||||
void
|
||||
nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags, uint64_t aTransactionId,
|
||||
nsPresContext::NotifyDidPaintForSubtree(uint64_t aTransactionId,
|
||||
const mozilla::TimeStamp& aTimeStamp)
|
||||
{
|
||||
if (IsRoot()) {
|
||||
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
|
||||
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimers(aTransactionId);
|
||||
|
||||
if (!mFireAfterPaintEvents) {
|
||||
return;
|
||||
|
@ -2606,28 +2618,36 @@ nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags, uint64_t aTransactionId
|
|||
// every subdocument (which would require putting every subdocument in its
|
||||
// own layer).
|
||||
|
||||
if (aFlags & nsIPresShell::PAINT_LAYERS) {
|
||||
mUndeliveredInvalidateRequestsBeforeLastPaint.AppendElements(mozilla::Move(mInvalidateRequestsSinceLastPaint));
|
||||
bool sent = false;
|
||||
uint32_t i = 0;
|
||||
while (i < mTransactions.Length()) {
|
||||
if (mTransactions[i].mTransactionId <= aTransactionId) {
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new DelayedFireDOMPaintEvent(this, &mTransactions[i].mInvalidations,
|
||||
mTransactions[i].mTransactionId, aTimeStamp);
|
||||
nsContentUtils::AddScriptRunner(ev);
|
||||
sent = true;
|
||||
mTransactions.RemoveElementAt(i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (aFlags & nsIPresShell::PAINT_COMPOSITE) {
|
||||
|
||||
if (!sent) {
|
||||
nsTArray<nsRect> dummy;
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint,
|
||||
new DelayedFireDOMPaintEvent(this, &dummy,
|
||||
aTransactionId, aTimeStamp);
|
||||
nsContentUtils::AddScriptRunner(ev);
|
||||
}
|
||||
|
||||
NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, aTransactionId, aTimeStamp, false };
|
||||
mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, &closure);
|
||||
NotifyDidPaintSubdocumentCallbackClosure closure = { aTransactionId, aTimeStamp, false };
|
||||
mDocument->EnumerateSubDocuments(nsPresContext::NotifyDidPaintSubdocumentCallback, &closure);
|
||||
|
||||
if (!closure.mNeedsAnotherDidPaintNotification &&
|
||||
mInvalidateRequestsSinceLastPaint.IsEmpty() &&
|
||||
mUndeliveredInvalidateRequestsBeforeLastPaint.IsEmpty()) {
|
||||
mTransactions.IsEmpty()) {
|
||||
// Nothing more to do for the moment.
|
||||
mFireAfterPaintEvents = false;
|
||||
} else {
|
||||
if (IsRoot()) {
|
||||
static_cast<nsRootPresContext*>(this)->EnsureEventualDidPaintEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2975,14 +2995,14 @@ nsRootPresContext::~nsRootPresContext()
|
|||
{
|
||||
NS_ASSERTION(mRegisteredPlugins.Count() == 0,
|
||||
"All plugins should have been unregistered");
|
||||
CancelDidPaintTimer();
|
||||
CancelAllDidPaintTimers();
|
||||
CancelApplyPluginGeometryTimer();
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsRootPresContext::Detach()
|
||||
{
|
||||
CancelDidPaintTimer();
|
||||
CancelAllDidPaintTimers();
|
||||
// XXXmats maybe also CancelApplyPluginGeometryTimer(); ?
|
||||
nsPresContext::Detach();
|
||||
}
|
||||
|
@ -3237,26 +3257,51 @@ nsRootPresContext::CollectPluginGeometryUpdates(LayerManager* aLayerManager)
|
|||
#endif // #ifndef XP_MACOSX
|
||||
}
|
||||
|
||||
static void
|
||||
NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
|
||||
void
|
||||
nsRootPresContext::EnsureEventualDidPaintEvent(uint64_t aTransactionId)
|
||||
{
|
||||
nsPresContext* presContext = (nsPresContext*)aClosure;
|
||||
nsAutoScriptBlocker blockScripts;
|
||||
// This is a fallback if we don't get paint events for some reason
|
||||
// so we'll just pretend both layer painting and compositing happened.
|
||||
presContext->NotifyDidPaintForSubtree(
|
||||
nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_COMPOSITE);
|
||||
for (NotifyDidPaintTimer& t : mNotifyDidPaintTimers) {
|
||||
if (t.mTransactionId == aTransactionId) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (timer) {
|
||||
nsresult rv = timer->InitWithCallback(NewTimerCallback([=](){
|
||||
nsAutoScriptBlocker blockScripts;
|
||||
this->NotifyDidPaintForSubtree(aTransactionId);
|
||||
}), 100, nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NotifyDidPaintTimer* t = mNotifyDidPaintTimers.AppendElement();
|
||||
t->mTransactionId = aTransactionId;
|
||||
t->mTimer = timer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsRootPresContext::EnsureEventualDidPaintEvent()
|
||||
nsRootPresContext::CancelDidPaintTimers(uint64_t aTransactionId)
|
||||
{
|
||||
if (mNotifyDidPaintTimer)
|
||||
return;
|
||||
uint32_t i = 0;
|
||||
while (i < mNotifyDidPaintTimers.Length()) {
|
||||
if (mNotifyDidPaintTimers[i].mTransactionId <= aTransactionId) {
|
||||
mNotifyDidPaintTimers[i].mTimer->Cancel();
|
||||
mNotifyDidPaintTimers.RemoveElementAt(i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mNotifyDidPaintTimer = CreateTimer(NotifyDidPaintForSubtreeCallback,
|
||||
"NotifyDidPaintForSubtreeCallback",
|
||||
100);
|
||||
void
|
||||
nsRootPresContext::CancelAllDidPaintTimers()
|
||||
{
|
||||
for (uint32_t i = 0; i < mNotifyDidPaintTimers.Length(); i++) {
|
||||
mNotifyDidPaintTimers[i].mTimer->Cancel();
|
||||
}
|
||||
mNotifyDidPaintTimers.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -962,8 +962,7 @@ public:
|
|||
void NotifyInvalidation(uint64_t aTransactionId, const nsRect& aRect);
|
||||
// aRect is in device pixels
|
||||
void NotifyInvalidation(uint64_t aTransactionId, const nsIntRect& aRect);
|
||||
// aFlags are nsIPresShell::PAINT_ flags
|
||||
void NotifyDidPaintForSubtree(uint32_t aFlags, uint64_t aTransactionId = 0,
|
||||
void NotifyDidPaintForSubtree(uint64_t aTransactionId = 0,
|
||||
const mozilla::TimeStamp& aTimeStamp = mozilla::TimeStamp());
|
||||
void FireDOMPaintEvent(nsTArray<nsRect>* aList, uint64_t aTransactionId,
|
||||
mozilla::TimeStamp aTimeStamp = mozilla::TimeStamp());
|
||||
|
@ -1180,6 +1179,8 @@ protected:
|
|||
|
||||
void UpdateCharSet(const nsCString& aCharSet);
|
||||
|
||||
static bool NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData);
|
||||
|
||||
public:
|
||||
void DoChangeCharSet(const nsCString& aCharSet);
|
||||
|
||||
|
@ -1291,8 +1292,11 @@ protected:
|
|||
|
||||
FramePropertyTable mPropertyTable;
|
||||
|
||||
nsTArray<nsRect> mInvalidateRequestsSinceLastPaint;
|
||||
nsTArray<nsRect> mUndeliveredInvalidateRequestsBeforeLastPaint;
|
||||
struct TransactionInvalidations {
|
||||
uint64_t mTransactionId;
|
||||
nsTArray<nsRect> mInvalidations;
|
||||
};
|
||||
AutoTArray<TransactionInvalidations, 4> mTransactions;
|
||||
|
||||
// text performance metrics
|
||||
nsAutoPtr<gfxTextPerfMetrics> mTextPerf;
|
||||
|
@ -1469,15 +1473,18 @@ public:
|
|||
* Ensure that NotifyDidPaintForSubtree is eventually called on this
|
||||
* object after a timeout.
|
||||
*/
|
||||
void EnsureEventualDidPaintEvent();
|
||||
void EnsureEventualDidPaintEvent(uint64_t aTransactionId);
|
||||
|
||||
void CancelDidPaintTimer()
|
||||
{
|
||||
if (mNotifyDidPaintTimer) {
|
||||
mNotifyDidPaintTimer->Cancel();
|
||||
mNotifyDidPaintTimer = nullptr;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Cancels any pending eventual did paint timer for transaction
|
||||
* ids up to and including aTransactionId.
|
||||
*/
|
||||
void CancelDidPaintTimers(uint64_t aTransactionId);
|
||||
|
||||
/**
|
||||
* Cancel all pending eventual did paint timers.
|
||||
*/
|
||||
void CancelAllDidPaintTimers();
|
||||
|
||||
/**
|
||||
* Registers a plugin to receive geometry updates (position and clip
|
||||
|
@ -1582,7 +1589,12 @@ protected:
|
|||
|
||||
friend class nsPresContext;
|
||||
|
||||
nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
|
||||
struct NotifyDidPaintTimer {
|
||||
uint64_t mTransactionId;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
};
|
||||
AutoTArray<NotifyDidPaintTimer, 4> mNotifyDidPaintTimers;
|
||||
|
||||
nsCOMPtr<nsITimer> mApplyPluginGeometryTimer;
|
||||
nsTHashtable<nsRefPtrHashKey<nsIContent> > mRegisteredPlugins;
|
||||
nsTArray<nsCOMPtr<nsIRunnable> > mWillPaintObservers;
|
||||
|
|
|
@ -1083,8 +1083,7 @@ nsView::DidCompositeWindow(uint64_t aTransactionId,
|
|||
nsPresContext* context = presShell->GetPresContext();
|
||||
nsRootPresContext* rootContext = context->GetRootPresContext();
|
||||
MOZ_ASSERT(rootContext, "rootContext must be valid.");
|
||||
rootContext->NotifyDidPaintForSubtree(nsIPresShell::PAINT_COMPOSITE, aTransactionId,
|
||||
aCompositeEnd);
|
||||
rootContext->NotifyDidPaintForSubtree(aTransactionId, aCompositeEnd);
|
||||
|
||||
// If the two timestamps are identical, this was likely a fake composite
|
||||
// event which wouldn't be terribly useful to display.
|
||||
|
|
Загрузка…
Ссылка в новой задаче