зеркало из https://github.com/mozilla/gecko-dev.git
Bug 612190. Make MozAfterPaint actually fire after paint. r=dbaron,a=me (blocks a blocker)
This commit is contained in:
Родитель
7193a092f0
Коммит
785dc45b3a
|
@ -1103,24 +1103,33 @@ nsPresContext::Observe(nsISupports* aSubject,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsPresContext*
|
||||||
|
GetParentPresContext(nsPresContext* aPresContext)
|
||||||
|
{
|
||||||
|
nsIPresShell* shell = aPresContext->GetPresShell();
|
||||||
|
if (shell) {
|
||||||
|
nsIFrame* rootFrame = shell->FrameManager()->GetRootFrame();
|
||||||
|
if (rootFrame) {
|
||||||
|
nsIFrame* f = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
|
||||||
|
if (f)
|
||||||
|
return f->PresContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
// We may want to replace this with something faster, maybe caching the root prescontext
|
// We may want to replace this with something faster, maybe caching the root prescontext
|
||||||
nsRootPresContext*
|
nsRootPresContext*
|
||||||
nsPresContext::GetRootPresContext()
|
nsPresContext::GetRootPresContext()
|
||||||
{
|
{
|
||||||
nsPresContext* pc = this;
|
nsPresContext* pc = this;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pc->mShell) {
|
nsPresContext* parent = GetParentPresContext(pc);
|
||||||
nsIFrame* rootFrame = pc->mShell->FrameManager()->GetRootFrame();
|
if (!parent)
|
||||||
if (rootFrame) {
|
break;
|
||||||
nsIFrame* f = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
|
pc = parent;
|
||||||
if (f) {
|
|
||||||
pc = f->PresContext();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
|
|
||||||
}
|
}
|
||||||
|
return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2178,11 +2187,17 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
|
||||||
if (aRect.IsEmpty() || !MayHavePaintEventListener())
|
if (aRect.IsEmpty() || !MayHavePaintEventListener())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!IsDOMPaintEventPending()) {
|
nsPresContext* pc;
|
||||||
// No event is pending. Dispatch one now.
|
for (pc = this; pc; pc = GetParentPresContext(pc)) {
|
||||||
nsCOMPtr<nsIRunnable> ev =
|
if (pc->mFireAfterPaintEvents)
|
||||||
NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
|
break;
|
||||||
NS_DispatchToCurrentThread(ev);
|
pc->mFireAfterPaintEvents = PR_TRUE;
|
||||||
|
}
|
||||||
|
if (!pc) {
|
||||||
|
nsRootPresContext* rpc = GetRootPresContext();
|
||||||
|
if (rpc) {
|
||||||
|
rpc->EnsureEventualDidPaintEvent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsInvalidateRequestList::Request* request =
|
nsInvalidateRequestList::Request* request =
|
||||||
|
@ -2194,6 +2209,39 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
|
||||||
request->mFlags = aFlags;
|
request->mFlags = aFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PRBool
|
||||||
|
NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
|
||||||
|
{
|
||||||
|
nsIPresShell* shell = aDocument->GetShell();
|
||||||
|
if (shell) {
|
||||||
|
nsPresContext* pc = shell->GetPresContext();
|
||||||
|
if (pc) {
|
||||||
|
pc->NotifyDidPaintForSubtree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsPresContext::NotifyDidPaintForSubtree()
|
||||||
|
{
|
||||||
|
if (!mFireAfterPaintEvents)
|
||||||
|
return;
|
||||||
|
mFireAfterPaintEvents = PR_FALSE;
|
||||||
|
|
||||||
|
if (IsRoot()) {
|
||||||
|
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mInvalidateRequests.mRequests.IsEmpty()) {
|
||||||
|
nsCOMPtr<nsIRunnable> ev =
|
||||||
|
NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
|
||||||
|
nsContentUtils::AddScriptRunner(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
nsPresContext::HasCachedStyleData()
|
nsPresContext::HasCachedStyleData()
|
||||||
{
|
{
|
||||||
|
@ -2400,6 +2448,7 @@ nsRootPresContext::~nsRootPresContext()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mRegisteredPlugins.Count() == 0,
|
NS_ASSERTION(mRegisteredPlugins.Count() == 0,
|
||||||
"All plugins should have been unregistered");
|
"All plugins should have been unregistered");
|
||||||
|
CancelDidPaintTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2734,3 +2783,23 @@ nsRootPresContext::RootForgetUpdatePluginGeometryFrame(nsIFrame* aFrame)
|
||||||
mUpdatePluginGeometryForFrame = nsnull;
|
mUpdatePluginGeometryForFrame = nsnull;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
|
||||||
|
{
|
||||||
|
nsPresContext* presContext = (nsPresContext*)aClosure;
|
||||||
|
nsAutoScriptBlocker blockScripts;
|
||||||
|
presContext->NotifyDidPaintForSubtree();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsRootPresContext::EnsureEventualDidPaintEvent()
|
||||||
|
{
|
||||||
|
if (mNotifyDidPaintTimer)
|
||||||
|
return;
|
||||||
|
mNotifyDidPaintTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||||
|
if (!mNotifyDidPaintTimer)
|
||||||
|
return;
|
||||||
|
mNotifyDidPaintTimer->InitWithFuncCallback(NotifyDidPaintForSubtreeCallback,
|
||||||
|
(void*)this, 100, nsITimer::TYPE_ONE_SHOT);
|
||||||
|
}
|
||||||
|
|
|
@ -862,11 +862,12 @@ public:
|
||||||
PRBool EnsureSafeToHandOutCSSRules();
|
PRBool EnsureSafeToHandOutCSSRules();
|
||||||
|
|
||||||
void NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags);
|
void NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags);
|
||||||
|
void NotifyDidPaintForSubtree();
|
||||||
void FireDOMPaintEvent();
|
void FireDOMPaintEvent();
|
||||||
|
|
||||||
PRBool IsDOMPaintEventPending() {
|
PRBool IsDOMPaintEventPending() {
|
||||||
return !mInvalidateRequests.mRequests.IsEmpty();
|
return !mInvalidateRequests.mRequests.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearMozAfterPaintEvents() {
|
void ClearMozAfterPaintEvents() {
|
||||||
mInvalidateRequests.mRequests.Clear();
|
mInvalidateRequests.mRequests.Clear();
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1158,7 @@ protected:
|
||||||
unsigned mProcessingAnimationStyleChange : 1;
|
unsigned mProcessingAnimationStyleChange : 1;
|
||||||
|
|
||||||
unsigned mContainsUpdatePluginGeometryFrame : 1;
|
unsigned mContainsUpdatePluginGeometryFrame : 1;
|
||||||
|
unsigned mFireAfterPaintEvents : 1;
|
||||||
|
|
||||||
// Cache whether we are chrome or not because it is expensive.
|
// Cache whether we are chrome or not because it is expensive.
|
||||||
// mIsChromeIsCached tells us if mIsChrome is valid or we need to get the
|
// mIsChromeIsCached tells us if mIsChrome is valid or we need to get the
|
||||||
|
@ -1202,6 +1204,20 @@ public:
|
||||||
nsRootPresContext(nsIDocument* aDocument, nsPresContextType aType) NS_HIDDEN;
|
nsRootPresContext(nsIDocument* aDocument, nsPresContextType aType) NS_HIDDEN;
|
||||||
virtual ~nsRootPresContext();
|
virtual ~nsRootPresContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that NotifyDidPaintForSubtree is eventually called on this
|
||||||
|
* object after a timeout.
|
||||||
|
*/
|
||||||
|
void EnsureEventualDidPaintEvent();
|
||||||
|
|
||||||
|
void CancelDidPaintTimer()
|
||||||
|
{
|
||||||
|
if (mNotifyDidPaintTimer) {
|
||||||
|
mNotifyDidPaintTimer->Cancel();
|
||||||
|
mNotifyDidPaintTimer = nsnull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a plugin to receive geometry updates (position and clip
|
* Registers a plugin to receive geometry updates (position and clip
|
||||||
* region) so it can update its widget.
|
* region) so it can update its widget.
|
||||||
|
@ -1276,6 +1292,7 @@ public:
|
||||||
PRUint32 GetDOMGeneration() { return mDOMGeneration; }
|
PRUint32 GetDOMGeneration() { return mDOMGeneration; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
|
||||||
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
|
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
|
||||||
// if mNeedsToUpdatePluginGeometry is set, then this is the frame to
|
// if mNeedsToUpdatePluginGeometry is set, then this is the frame to
|
||||||
// use as the root of the subtree to search for plugin updates, or
|
// use as the root of the subtree to search for plugin updates, or
|
||||||
|
|
|
@ -6093,13 +6093,14 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
||||||
NSCoordToFloat(bounds__.YMost()));
|
NSCoordToFloat(bounds__.YMost()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
|
|
||||||
|
|
||||||
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
|
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
|
||||||
NS_ASSERTION(aDisplayRoot, "null view");
|
NS_ASSERTION(aDisplayRoot, "null view");
|
||||||
NS_ASSERTION(aViewToPaint, "null view");
|
NS_ASSERTION(aViewToPaint, "null view");
|
||||||
NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
|
NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
|
||||||
|
|
||||||
|
nsPresContext* presContext = GetPresContext();
|
||||||
|
AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
|
||||||
|
|
||||||
nsIFrame* frame = aPaintDefaultBackground
|
nsIFrame* frame = aPaintDefaultBackground
|
||||||
? nsnull : static_cast<nsIFrame*>(aDisplayRoot->GetClientData());
|
? nsnull : static_cast<nsIFrame*>(aDisplayRoot->GetClientData());
|
||||||
|
|
||||||
|
@ -6131,6 +6132,7 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
||||||
nsLayoutUtils::PAINT_WIDGET_LAYERS);
|
nsLayoutUtils::PAINT_WIDGET_LAYERS);
|
||||||
|
|
||||||
frame->EndDeferringInvalidatesForDisplayRoot();
|
frame->EndDeferringInvalidatesForDisplayRoot();
|
||||||
|
presContext->NotifyDidPaintForSubtree();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6159,6 +6161,7 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
||||||
if (frame) {
|
if (frame) {
|
||||||
frame->EndDeferringInvalidatesForDisplayRoot();
|
frame->EndDeferringInvalidatesForDisplayRoot();
|
||||||
}
|
}
|
||||||
|
presContext->NotifyDidPaintForSubtree();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,24 +174,24 @@ function runTest3() {
|
||||||
gotScrolledOutInMainDoc = true;
|
gotScrolledOutInMainDoc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function IFRAMEListener(event) {
|
|
||||||
if (doesRectContainListElement(
|
|
||||||
iframe.contentDocument.getElementById("d2").getBoundingClientRect(), event.clientRects))
|
|
||||||
gotScrolledOutInSubdoc = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function check() {
|
function check() {
|
||||||
ok(!gotScrolledOutInMainDoc, "scrolled-out invalidation should not propagate to main doc");
|
ok(!gotScrolledOutInMainDoc, "scrolled-out invalidation should not propagate to main doc");
|
||||||
ok(gotScrolledOutInSubdoc, "scrolled-out invalidation should notify in subdoc");
|
|
||||||
window.removeEventListener("MozAfterPaint", listener, false);
|
window.removeEventListener("MozAfterPaint", listener, false);
|
||||||
iframe.contentWindow.removeEventListener("MozAfterPaint", IFRAMEListener, false);
|
iframe.contentWindow.removeEventListener("MozAfterPaint", IFRAMEListener, false);
|
||||||
runNext();
|
runNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function IFRAMEListener(event) {
|
||||||
|
if (doesRectContainListElement(
|
||||||
|
iframe.contentDocument.getElementById("d2").getBoundingClientRect(), event.clientRects)) {
|
||||||
|
ok(true, "scrolled-out invalidation should notify in subdoc");
|
||||||
|
setTimeout(check, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function triggerPaint() {
|
function triggerPaint() {
|
||||||
window.addEventListener("MozAfterPaint", listener, false);
|
window.addEventListener("MozAfterPaint", listener, false);
|
||||||
iframe.contentWindow.addEventListener("MozAfterPaint", IFRAMEListener, false);
|
iframe.contentWindow.addEventListener("MozAfterPaint", IFRAMEListener, false);
|
||||||
setTimeout(check, 100);
|
|
||||||
flash(iframe.contentDocument, 'd2');
|
flash(iframe.contentDocument, 'd2');
|
||||||
}
|
}
|
||||||
triggerPaint();
|
triggerPaint();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче