зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c996ab4fc3
Коммит
00c5b11afa
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче