зеркало из 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;
|
||||
}
|
||||
|
||||
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
|
||||
nsRootPresContext*
|
||||
nsPresContext::GetRootPresContext()
|
||||
{
|
||||
nsPresContext* pc = this;
|
||||
for (;;) {
|
||||
if (pc->mShell) {
|
||||
nsIFrame* rootFrame = pc->mShell->FrameManager()->GetRootFrame();
|
||||
if (rootFrame) {
|
||||
nsIFrame* f = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
|
||||
if (f) {
|
||||
pc = f->PresContext();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
|
||||
nsPresContext* parent = GetParentPresContext(pc);
|
||||
if (!parent)
|
||||
break;
|
||||
pc = parent;
|
||||
}
|
||||
return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2178,11 +2187,17 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
|
|||
if (aRect.IsEmpty() || !MayHavePaintEventListener())
|
||||
return;
|
||||
|
||||
if (!IsDOMPaintEventPending()) {
|
||||
// No event is pending. Dispatch one now.
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
nsPresContext* pc;
|
||||
for (pc = this; pc; pc = GetParentPresContext(pc)) {
|
||||
if (pc->mFireAfterPaintEvents)
|
||||
break;
|
||||
pc->mFireAfterPaintEvents = PR_TRUE;
|
||||
}
|
||||
if (!pc) {
|
||||
nsRootPresContext* rpc = GetRootPresContext();
|
||||
if (rpc) {
|
||||
rpc->EnsureEventualDidPaintEvent();
|
||||
}
|
||||
}
|
||||
|
||||
nsInvalidateRequestList::Request* request =
|
||||
|
@ -2194,6 +2209,39 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 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
|
||||
nsPresContext::HasCachedStyleData()
|
||||
{
|
||||
|
@ -2400,6 +2448,7 @@ nsRootPresContext::~nsRootPresContext()
|
|||
{
|
||||
NS_ASSERTION(mRegisteredPlugins.Count() == 0,
|
||||
"All plugins should have been unregistered");
|
||||
CancelDidPaintTimer();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2734,3 +2783,23 @@ nsRootPresContext::RootForgetUpdatePluginGeometryFrame(nsIFrame* aFrame)
|
|||
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();
|
||||
|
||||
void NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags);
|
||||
void NotifyDidPaintForSubtree();
|
||||
void FireDOMPaintEvent();
|
||||
|
||||
PRBool IsDOMPaintEventPending() {
|
||||
return !mInvalidateRequests.mRequests.IsEmpty();
|
||||
}
|
||||
|
||||
void ClearMozAfterPaintEvents() {
|
||||
mInvalidateRequests.mRequests.Clear();
|
||||
}
|
||||
|
@ -1157,6 +1158,7 @@ protected:
|
|||
unsigned mProcessingAnimationStyleChange : 1;
|
||||
|
||||
unsigned mContainsUpdatePluginGeometryFrame : 1;
|
||||
unsigned mFireAfterPaintEvents : 1;
|
||||
|
||||
// Cache whether we are chrome or not because it is expensive.
|
||||
// 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;
|
||||
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
|
||||
* region) so it can update its widget.
|
||||
|
@ -1276,6 +1292,7 @@ public:
|
|||
PRUint32 GetDOMGeneration() { return mDOMGeneration; }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
|
||||
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
|
||||
// if mNeedsToUpdatePluginGeometry is set, then this is the frame to
|
||||
// use as the root of the subtree to search for plugin updates, or
|
||||
|
|
|
@ -6093,13 +6093,14 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
|||
NSCoordToFloat(bounds__.YMost()));
|
||||
#endif
|
||||
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
|
||||
|
||||
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
|
||||
NS_ASSERTION(aDisplayRoot, "null view");
|
||||
NS_ASSERTION(aViewToPaint, "null view");
|
||||
NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
|
||||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
|
||||
|
||||
nsIFrame* frame = aPaintDefaultBackground
|
||||
? nsnull : static_cast<nsIFrame*>(aDisplayRoot->GetClientData());
|
||||
|
||||
|
@ -6131,6 +6132,7 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
|||
nsLayoutUtils::PAINT_WIDGET_LAYERS);
|
||||
|
||||
frame->EndDeferringInvalidatesForDisplayRoot();
|
||||
presContext->NotifyDidPaintForSubtree();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -6159,6 +6161,7 @@ PresShell::Paint(nsIView* aDisplayRoot,
|
|||
if (frame) {
|
||||
frame->EndDeferringInvalidatesForDisplayRoot();
|
||||
}
|
||||
presContext->NotifyDidPaintForSubtree();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,24 +174,24 @@ function runTest3() {
|
|||
gotScrolledOutInMainDoc = true;
|
||||
}
|
||||
|
||||
function IFRAMEListener(event) {
|
||||
if (doesRectContainListElement(
|
||||
iframe.contentDocument.getElementById("d2").getBoundingClientRect(), event.clientRects))
|
||||
gotScrolledOutInSubdoc = true;
|
||||
}
|
||||
|
||||
function check() {
|
||||
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);
|
||||
iframe.contentWindow.removeEventListener("MozAfterPaint", IFRAMEListener, false);
|
||||
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() {
|
||||
window.addEventListener("MozAfterPaint", listener, false);
|
||||
iframe.contentWindow.addEventListener("MozAfterPaint", IFRAMEListener, false);
|
||||
setTimeout(check, 100);
|
||||
flash(iframe.contentDocument, 'd2');
|
||||
}
|
||||
triggerPaint();
|
||||
|
|
Загрузка…
Ссылка в новой задаче