Bug 564991. Part 27: Make plugin geometry changes asynchronous and make them happen as close to the final paint as possible. r=matspal,sr=vlad

This commit is contained in:
Robert O'Callahan 2010-07-16 09:08:08 +12:00
Родитель c996ab4fc3
Коммит 00c5b11afa
14 изменённых файлов: 258 добавлений и 58 удалений

Просмотреть файл

@ -7980,7 +7980,7 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
nsIFrame* rootFrame = mPresShell->FrameManager()->GetRootFrame();
nsRootPresContext* rootPC = presContext->GetRootPresContext();
if (rootPC) {
rootPC->UpdatePluginGeometry(rootFrame);
rootPC->RequestUpdatePluginGeometry(rootFrame);
}
}

Просмотреть файл

@ -2365,10 +2365,12 @@ nsPresContext::CheckForInterrupt(nsIFrame* aFrame)
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
nsPresContextType aType)
: nsPresContext(aDocument, aType)
: nsPresContext(aDocument, aType),
mUpdatePluginGeometryForFrame(nsnull),
mNeedsToUpdatePluginGeometry(PR_FALSE)
{
mRegisteredPlugins.Init();
}
}
nsRootPresContext::~nsRootPresContext()
{
@ -2525,10 +2527,23 @@ nsRootPresContext::GetPluginGeometryUpdates(nsIFrame* aChangedSubtree,
}
void
nsRootPresContext::UpdatePluginGeometry(nsIFrame* aChangedSubtree)
nsRootPresContext::UpdatePluginGeometry()
{
if (!mNeedsToUpdatePluginGeometry)
return;
mNeedsToUpdatePluginGeometry = PR_FALSE;
nsIFrame* f = mUpdatePluginGeometryForFrame;
if (f) {
mUpdatePluginGeometryForFrame->PresContext()->
SetContainsUpdatePluginGeometryFrame(PR_FALSE);
mUpdatePluginGeometryForFrame = nsnull;
} else {
f = FrameManager()->GetRootFrame();
}
nsTArray<nsIWidget::Configuration> configurations;
GetPluginGeometryUpdates(aChangedSubtree, &configurations);
GetPluginGeometryUpdates(f, &configurations);
if (configurations.IsEmpty())
return;
nsIWidget* widget = FrameManager()->GetRootFrame()->GetNearestWidget();
@ -2537,6 +2552,57 @@ nsRootPresContext::UpdatePluginGeometry(nsIFrame* aChangedSubtree)
DidApplyPluginGeometryUpdates();
}
void
nsRootPresContext::ForcePluginGeometryUpdate()
{
// Force synchronous paint
nsIPresShell* shell = GetPresShell();
if (!shell)
return;
nsIFrame* rootFrame = shell->GetRootFrame();
if (!rootFrame)
return;
nsCOMPtr<nsIWidget> widget = rootFrame->GetNearestWidget();
if (!widget)
return;
// Force synchronous paint of a single pixel, just to force plugin
// updates to be flushed. Doing plugin updates during paint is the best
// way to ensure that plugin updates are in sync with our content.
widget->Invalidate(nsIntRect(0,0,1,1), PR_TRUE);
// Update plugin geometry just in case that invalidate didn't work
// (e.g. if none of the widget is visible, it might not have processed
// a paint event). Normally this won't need to do anything.
UpdatePluginGeometry();
}
void
nsRootPresContext::RequestUpdatePluginGeometry(nsIFrame* aFrame)
{
if (mRegisteredPlugins.Count() == 0)
return;
if (!mNeedsToUpdatePluginGeometry) {
// Dispatch a Gecko event to ensure plugin geometry gets updated
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsRootPresContext::ForcePluginGeometryUpdate);
NS_DispatchToMainThread(event);
}
mNeedsToUpdatePluginGeometry = PR_TRUE;
if (aFrame == mUpdatePluginGeometryForFrame)
return;
if (!mUpdatePluginGeometryForFrame) {
mUpdatePluginGeometryForFrame = aFrame;
mUpdatePluginGeometryForFrame->PresContext()->
SetContainsUpdatePluginGeometryFrame(PR_TRUE);
} else {
mUpdatePluginGeometryForFrame->PresContext()->
SetContainsUpdatePluginGeometryFrame(PR_FALSE);
mUpdatePluginGeometryForFrame = nsnull;
}
}
static PLDHashOperator
PluginDidSetGeometryEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
{
@ -2550,3 +2616,13 @@ nsRootPresContext::DidApplyPluginGeometryUpdates()
{
mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nsnull);
}
void
nsRootPresContext::RootForgetUpdatePluginGeometryFrame(nsIFrame* aFrame)
{
if (aFrame == mUpdatePluginGeometryForFrame) {
mUpdatePluginGeometryForFrame->PresContext()->
SetContainsUpdatePluginGeometryFrame(PR_FALSE);
mUpdatePluginGeometryForFrame = nsnull;
}
}

Просмотреть файл

@ -960,6 +960,17 @@ public:
return nsnull;
}
void NotifyDestroyingFrame(nsIFrame* aFrame)
{
PropertyTable()->DeleteAllFor(aFrame);
}
inline void ForgetUpdatePluginGeometryFrame(nsIFrame* aFrame);
void SetContainsUpdatePluginGeometryFrame(PRBool aValue)
{
mContainsUpdatePluginGeometryFrame = aValue;
}
PRBool MayHaveFixedBackgroundFrames() { return mMayHaveFixedBackgroundFrames; }
void SetHasFixedBackgroundFrame() { mMayHaveFixedBackgroundFrames = PR_TRUE; }
@ -1147,6 +1158,8 @@ protected:
unsigned mProcessingRestyles : 1;
unsigned mProcessingAnimationStyleChange : 1;
unsigned mContainsUpdatePluginGeometryFrame : 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
// value the slow way.
@ -1208,10 +1221,9 @@ public:
/**
* Iterate through all plugins that are registered for geometry updates
* and update their position and clip region to match the current frame
* tree. Only frames at or under aChangedRoot can have changed their
* geometry.
* tree.
*/
void UpdatePluginGeometry(nsIFrame* aChangedRoot);
void UpdatePluginGeometry();
/**
* Iterate through all plugins that are registered for geometry updates
@ -1232,10 +1244,44 @@ public:
virtual PRBool IsRoot() { return PR_TRUE; }
/**
* This method is called off an event to force the plugin geometry to
* be updated. First we try to paint, since updating plugin geometry
* during paint is best for keeping plugins in sync with content.
* But we also force geometry updates in case painting doesn't work.
*/
void ForcePluginGeometryUpdate();
/**
* Call this after reflow and scrolling to ensure that the geometry
* of any windowed plugins is updated. aFrame is the root of the
* frame subtree whose geometry has changed.
*/
void RequestUpdatePluginGeometry(nsIFrame* aFrame);
/**
* Call this when a frame is being destroyed and
* mContainsUpdatePluginGeometryFrame is set in the frame's prescontext.
*/
void RootForgetUpdatePluginGeometryFrame(nsIFrame* aFrame);
private:
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
nsIFrame* mUpdatePluginGeometryForFrame;
PRPackedBool mNeedsToUpdatePluginGeometry;
};
inline void
nsPresContext::ForgetUpdatePluginGeometryFrame(nsIFrame* aFrame)
{
if (mContainsUpdatePluginGeometryFrame) {
nsRootPresContext* rootPC = GetRootPresContext();
if (rootPC) {
rootPC->RootForgetUpdatePluginGeometryFrame(aFrame);
}
}
}
#ifdef DEBUG
struct nsAutoLayoutPhase {

Просмотреть файл

@ -817,7 +817,8 @@ public:
nsIView* aViewToPaint,
nsIWidget* aWidget,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground);
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint);
NS_IMETHOD HandleEvent(nsIView* aView,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus);
@ -829,7 +830,8 @@ public:
nsEventStatus* aStatus);
NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
NS_IMETHOD_(PRBool) IsVisible();
NS_IMETHOD_(void) WillPaint();
NS_IMETHOD_(void) WillPaint(PRBool aWillSendDidPaint);
NS_IMETHOD_(void) DidPaint();
NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
PRBool aFlushOnHoverChange);
NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView);
@ -2853,6 +2855,8 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
{
NS_TIME_FUNCTION_MIN(1.0);
mPresContext->ForgetUpdatePluginGeometryFrame(aFrame);
if (!mIgnoreFrameDestruction) {
mPresContext->StopImagesFor(aFrame);
@ -2869,7 +2873,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
FrameManager()->NotifyDestroyingFrame(aFrame);
// Remove frame properties
mPresContext->PropertyTable()->DeleteAllFor(aFrame);
mPresContext->NotifyDestroyingFrame(aFrame);
if (aFrame == mCurrentEventFrame) {
mCurrentEventContent = aFrame->GetContent();
@ -4548,7 +4552,7 @@ PresShell::UnsuppressAndInvalidate()
nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
if (rootPC) {
rootPC->UpdatePluginGeometry(rootFrame);
rootPC->RequestUpdatePluginGeometry(rootFrame);
}
}
@ -4818,6 +4822,16 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
}
}
if (aType >= Flush_Layout) {
// Flush plugin geometry. Don't flush plugin geometry for
// interruptible layouts, since WillPaint does an interruptible
// layout.
nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
if (rootPresContext) {
rootPresContext->UpdatePluginGeometry();
}
}
PRUint32 updateFlags = NS_VMREFRESH_NO_SYNC;
if (aType >= Flush_Display) {
// Flushing paints, so perform the invalidates and drawing
@ -5830,7 +5844,8 @@ PresShell::Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground)
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint)
{
#ifdef NS_FUNCTION_TIMER
NS_TIME_FUNCTION_DECLARE_DOCURL;
@ -7085,14 +7100,24 @@ PresShell::IsVisible()
}
NS_IMETHODIMP_(void)
PresShell::WillPaint()
PresShell::WillPaint(PRBool aWillSendDidPaint)
{
// Don't bother reflowing if some viewmanager in our tree is painting while
// we still have painting suppressed.
// Don't bother doing anything if some viewmanager in our tree is
// painting while we still have painting suppressed.
if (mPaintingSuppressed) {
return;
}
if (!aWillSendDidPaint) {
nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
if (!rootPresContext) {
return;
}
if (rootPresContext == mPresContext) {
rootPresContext->UpdatePluginGeometry();
}
}
// Process reflows, if we have them, to reduce flicker due to invalidates and
// reflow being interspersed. Note that we _do_ allow this to be
// interruptible; if we can't do all the reflows it's better to flicker a bit
@ -7100,6 +7125,18 @@ PresShell::WillPaint()
FlushPendingNotifications(Flush_InterruptibleLayout);
}
NS_IMETHODIMP_(void)
PresShell::DidPaint()
{
nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
if (!rootPresContext) {
return;
}
if (rootPresContext == mPresContext) {
rootPresContext->UpdatePluginGeometry();
}
}
nsresult
PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
{
@ -7494,7 +7531,7 @@ PresShell::DoReflow(nsIFrame* target, PRBool aInterruptible)
nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
if (rootPC) {
rootPC->UpdatePluginGeometry(target);
rootPC->RequestUpdatePluginGeometry(target);
}
return !interrupted;

Просмотреть файл

@ -1627,32 +1627,13 @@ void nsGfxScrollFrameInner::MarkActive()
void nsGfxScrollFrameInner::ScrollVisual(nsIntPoint aPixDelta)
{
nsRootPresContext* rootPresContext =
mOuter->PresContext()->GetRootPresContext();
nsRootPresContext* rootPresContext = mOuter->PresContext()->GetRootPresContext();
if (!rootPresContext) {
return;
}
nsPoint offsetToView;
nsPoint offsetToWidget;
nsIWidget* nearestWidget =
mOuter->GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
nsPoint nearestWidgetOffset = offsetToView + offsetToWidget;
rootPresContext->RequestUpdatePluginGeometry(mOuter);
nsTArray<nsIWidget::Configuration> configurations;
// Only update plugin configurations if we're going to scroll the
// root widget. Otherwise we must be in a popup or some other situation
// where we don't actually support windows plugins.
if (rootPresContext->FrameManager()->GetRootFrame()->GetNearestWidget() ==
nearestWidget) {
rootPresContext->GetPluginGeometryUpdates(mOuter, &configurations);
}
// Just invalidate the frame and adjust child widgets
// Recall that our widget's origin is at our bounds' top-left
if (nearestWidget) {
nearestWidget->ConfigureChildren(configurations);
}
AdjustViewsAndWidgets(mScrolledFrame, PR_FALSE);
// We need to call this after fixing up the widget and view positions
// to be consistent with the view and frame hierarchy.

Просмотреть файл

@ -769,7 +769,7 @@ nsObjectFrame::CreateWidget(nscoord aWidth,
if (mWidget) {
rpc->RegisterPluginForGeometryUpdates(this);
rpc->UpdatePluginGeometry(this);
rpc->RequestUpdatePluginGeometry(this);
// Here we set the background color for this widget because some plugins will use
// the child window background color when painting. If it's not set, it may default to gray

Просмотреть файл

@ -47,8 +47,8 @@ class nsIRenderingContext;
class nsGUIEvent;
#define NS_IVIEWOBSERVER_IID \
{ 0xac43a985, 0xcae6, 0x499d, \
{ 0xae, 0x8f, 0x9c, 0x92, 0xec, 0x6f, 0x2c, 0x47 } }
{ 0x8e69db48, 0x9d01, 0x4c0a, \
{ 0xb9, 0xea, 0xa4, 0x4b, 0xc5, 0x89, 0xc8, 0x63 } }
class nsIViewObserver : public nsISupports
{
@ -75,7 +75,8 @@ public:
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground) = 0;
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint) = 0;
/* called when the observer needs to handle an event
* @param aView - where to start processing the event; the root view,
@ -111,7 +112,14 @@ public:
* gives the observer a chance to make some last-minute invalidates
* and geometry changes if it wants to.
*/
NS_IMETHOD_(void) WillPaint() = 0;
NS_IMETHOD_(void) WillPaint(PRBool aWillSendDidPaint) = 0;
/**
* Notify the observer that we finished painting. This
* gives the observer a chance to make some last-minute invalidates
* and geometry changes if it wants to.
*/
NS_IMETHOD_(void) DidPaint() = 0;
/**
* Dispatch the given synthesized mouse move event, and if

Просмотреть файл

@ -439,7 +439,7 @@ void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
}
if (mObserver) {
mObserver->Paint(displayRoot, aView, aWidget, aRegion, PR_FALSE);
mObserver->Paint(displayRoot, aView, aWidget, aRegion, PR_FALSE, PR_FALSE);
}
}
@ -806,7 +806,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
// We should really sort out the rules on our synch painting
// api....
UpdateViewBatch batch(this);
rootVM->CallWillPaintOnObservers();
rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
// Get the view pointer again since the code above might have
@ -830,7 +830,8 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
// draw something so we don't get blank areas,
// unless there's no widget or it's transparent.
nsRegion rgn = ConvertDeviceRegionToAppRegion(event->region, mContext);
mObserver->Paint(aView, aView, event->widget, rgn, PR_TRUE);
mObserver->Paint(aView, aView, event->widget, rgn, PR_TRUE,
event->willSendDidPaint);
// Clients like the editor can trigger multiple
// reflows during what the user perceives as a single
@ -862,6 +863,12 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
break;
}
case NS_DID_PAINT: {
nsRefPtr<nsViewManager> rootVM = RootViewManager();
rootVM->CallDidPaintOnObservers();
break;
}
case NS_CREATE:
case NS_DESTROY:
case NS_SETZLEVEL:
@ -1520,7 +1527,7 @@ nsViewManager::IsPainting(PRBool& aIsPainting)
void
nsViewManager::FlushPendingInvalidates()
{
NS_ASSERTION(IsRootVM(), "Must be root VM for this to be called!\n");
NS_ASSERTION(IsRootVM(), "Must be root VM for this to be called!");
NS_ASSERTION(mUpdateBatchCnt == 0, "Must not be in an update batch!");
// XXXbz this is probably not quite OK yet, if callers can explicitly
// DisableRefresh while we have an event posted.
@ -1537,7 +1544,7 @@ nsViewManager::FlushPendingInvalidates()
// BeginUpdateViewBatch/EndUpdateViewBatch, since that would reenter this
// exact code, but we want the effect of a single big update batch.
++mUpdateBatchCnt;
CallWillPaintOnObservers();
CallWillPaintOnObservers(PR_FALSE);
--mUpdateBatchCnt;
if (mHasPendingUpdates) {
@ -1547,9 +1554,9 @@ nsViewManager::FlushPendingInvalidates()
}
void
nsViewManager::CallWillPaintOnObservers()
nsViewManager::CallWillPaintOnObservers(PRBool aWillSendDidPaint)
{
NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!\n");
NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
NS_PRECONDITION(mUpdateBatchCnt > 0, "Must be in an update batch!");
#ifdef DEBUG
@ -1562,7 +1569,7 @@ nsViewManager::CallWillPaintOnObservers()
// One of our kids.
nsCOMPtr<nsIViewObserver> obs = vm->GetViewObserver();
if (obs) {
obs->WillPaint();
obs->WillPaint(aWillSendDidPaint);
NS_ASSERTION(mUpdateBatchCnt == savedUpdateBatchCnt,
"Observer did not end view batch?");
}
@ -1570,6 +1577,24 @@ nsViewManager::CallWillPaintOnObservers()
}
}
void
nsViewManager::CallDidPaintOnObservers()
{
NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
PRInt32 index;
for (index = 0; index < mVMCount; index++) {
nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
if (vm->RootViewManager() == this) {
// One of our kids.
nsCOMPtr<nsIViewObserver> obs = vm->GetViewObserver();
if (obs) {
obs->DidPaint();
}
}
}
}
void
nsViewManager::ProcessInvalidateEvent()
{

Просмотреть файл

@ -172,7 +172,8 @@ private:
/**
* Call WillPaint() on all view observers under this vm root.
*/
void CallWillPaintOnObservers();
void CallWillPaintOnObservers(PRBool aWillSendDidPaint);
void CallDidPaintOnObservers();
void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
void ReparentWidgets(nsIView* aView, nsIView *aParent);
void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,

Просмотреть файл

@ -173,6 +173,9 @@ class nsHashKey;
#define NS_DEACTIVATE (NS_WINDOW_START + 8)
// top-level window z-level change request
#define NS_SETZLEVEL (NS_WINDOW_START + 9)
// Widget was repainted (dispatched when it's safe to move widgets, but
// only on some platforms (including GTK2 and Windows))
#define NS_DID_PAINT (NS_WINDOW_START + 28)
// Widget will need to be painted
#define NS_WILL_PAINT (NS_WINDOW_START + 29)
// Widget needs to be repainted
@ -638,12 +641,14 @@ class nsPaintEvent : public nsGUIEvent
{
public:
nsPaintEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
: nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT)
: nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT),
willSendDidPaint(PR_FALSE)
{
}
// area that needs repainting
nsIntRegion region;
PRPackedBool willSendDidPaint;
};
/**

Просмотреть файл

@ -2323,6 +2323,7 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.refPoint.x = aEvent->area.x;
event.refPoint.y = aEvent->area.y;
event.willSendDidPaint = PR_TRUE;
GdkRectangle *rects;
gint nrects;
@ -2575,6 +2576,17 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
g_free(rects);
nsPaintEvent didPaintEvent(PR_TRUE, NS_DID_PAINT, this);
DispatchEvent(&didPaintEvent, status);
// Synchronously flush any new dirty areas
GdkRegion* dirtyArea = gdk_window_get_update_area(mGdkWindow);
if (dirtyArea) {
gdk_window_invalidate_region(mGdkWindow, dirtyArea, PR_FALSE);
gdk_region_destroy(dirtyArea);
gdk_window_process_updates(mGdkWindow, PR_FALSE);
}
// check the return value!
return TRUE;
}

Просмотреть файл

@ -4633,13 +4633,13 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
break;
case WM_PAINT:
*aRetValue = (int) OnPaint();
*aRetValue = (int) OnPaint(NULL, 0);
result = PR_TRUE;
break;
#ifndef WINCE
case WM_PRINTCLIENT:
result = OnPaint((HDC) wParam);
result = OnPaint((HDC) wParam, 0);
break;
#endif

Просмотреть файл

@ -352,7 +352,7 @@ protected:
PRBool OnHotKey(WPARAM wParam, LPARAM lParam);
BOOL OnInputLangChange(HKL aHKL);
void OnSettingsChange(WPARAM wParam, LPARAM lParam);
virtual PRBool OnPaint(HDC aDC = nsnull);
PRBool OnPaint(HDC aDC, PRUint32 aNestingLevel);
void OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult);
#if defined(CAIRO_HAS_DDRAW_SURFACE)
PRBool OnPaintImageDDraw16();

Просмотреть файл

@ -300,7 +300,7 @@ EnsureSharedSurfaceSize(gfxIntSize size)
return (sSharedSurfaceData != nsnull);
}
PRBool nsWindow::OnPaint(HDC aDC)
PRBool nsWindow::OnPaint(HDC aDC, PRUint32 aNestingLevel)
{
#ifdef MOZ_IPC
// We never have reentrant paint events, except when we're running our RPC
@ -348,6 +348,7 @@ PRBool nsWindow::OnPaint(HDC aDC)
#endif
nsPaintEvent willPaintEvent(PR_TRUE, NS_WILL_PAINT, this);
willPaintEvent.willSendDidPaint = PR_TRUE;
DispatchWindowEvent(&willPaintEvent);
#ifdef CAIRO_HAS_DDRAW_SURFACE
@ -405,6 +406,7 @@ PRBool nsWindow::OnPaint(HDC aDC)
PRBool forceRepaint = NULL != aDC;
#endif
event.region = GetRegionToPaint(forceRepaint, ps, hDC);
event.willSendDidPaint = PR_TRUE;
if (!event.region.IsEmpty() && mEventCallback)
{
@ -739,6 +741,13 @@ DDRAW_FAILED:
mPainting = PR_FALSE;
nsPaintEvent didPaintEvent(PR_TRUE, NS_DID_PAINT, this);
DispatchWindowEvent(&didPaintEvent);
if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, NULL, PR_FALSE)) {
OnPaint(aDC, 1);
}
return result;
}