Bug 1159772. Don't let nsContainerFrame::SyncWindowProperties make widget calls that can result in synchronous painting during reflow or frame construction. r=mats

Specifically on Windows nsIWidget::SetTransparencyMode can result in sync painting.

So we give nsContainerFrame::SyncWindowProperties a sync or async option and use the view manager post pending update infrastructure to flush SyncWindowProperties calls async.
This commit is contained in:
Timothy Nikkel 2015-05-04 14:29:19 -05:00
parent fbdca54511
commit 2b812da207
8 changed files with 69 additions and 12 deletions

View File

@ -2688,7 +2688,7 @@ nsCSSFrameConstructor::ConstructRootFrame()
nsContainerFrame::SyncFrameViewProperties(mPresShell->GetPresContext(), viewportFrame,
viewportPseudoStyle, rootView);
nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
rootView);
rootView, nullptr, nsContainerFrame::SET_ASYNC);
// Make it an absolute container for fixed-pos elements
viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);

View File

@ -140,8 +140,8 @@ typedef struct CapturingContentInfo {
// d910f009-d209-74c1-6b04-30c83c051c78
#define NS_IPRESSHELL_IID \
{ 0xd910f009, 0xd209, 0x74c1, \
{ 0x6b, 0x04, 0x30, 0xc8, 0x3c, 0x05, 0x1c, 0x78 } }
{ 0x025264c6, 0x0b12, 0x4804, \
{ 0xa3, 0x3e, 0xb7, 0x73, 0xf2, 0x19, 0x48, 0x90 } }
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -1661,6 +1661,8 @@ public:
bool HasPendingReflow() const
{ return mReflowScheduled || mReflowContinueTimer; }
void SyncWindowProperties(nsView* aView);
protected:
friend class nsRefreshDriver;

View File

@ -9245,7 +9245,8 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
target->GetView(),
boundsRelativeToTarget);
nsContainerFrame::SyncWindowProperties(mPresContext, target,
target->GetView(), &rcx);
target->GetView(), &rcx,
nsContainerFrame::SET_ASYNC);
target->DidReflow(mPresContext, nullptr, nsDidReflowStatus::FINISHED);
if (target == rootFrame && size.BSize(wm) == NS_UNCONSTRAINEDSIZE) {
@ -11081,3 +11082,13 @@ PresShell::ResumePainting()
mPaintingIsFrozen = false;
GetPresContext()->RefreshDriver()->Thaw();
}
void
nsIPresShell::SyncWindowProperties(nsView* aView)
{
nsIFrame* frame = aView->GetFrame();
if (frame && mPresContext) {
nsRenderingContext rcx(CreateReferenceRenderingContext());
nsContainerFrame::SyncWindowProperties(mPresContext, frame, aView, &rcx, 0);
}
}

View File

@ -609,14 +609,15 @@ IsTopLevelWidget(nsIWidget* aWidget)
void
nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
nsIFrame* aFrame,
nsView* aView,
nsRenderingContext* aRC)
nsView* aView,
nsRenderingContext* aRC,
uint32_t aFlags)
{
#ifdef MOZ_XUL
if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
return;
nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
nsCOMPtr<nsIWidget> windowWidget = GetPresContextContainerWidget(aPresContext);
if (!windowWidget || !IsTopLevelWidget(windowWidget))
return;
@ -650,14 +651,27 @@ nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
if (!rootFrame)
return;
if (aFlags & SET_ASYNC) {
aView->SetNeedsWindowPropertiesSync();
return;
}
nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
nsWeakFrame weak(rootFrame);
nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
nsIWidget* viewWidget = aView->GetWidget();
int32_t shadow = rootFrame->StyleUIReset()->mWindowShadow;
nsCOMPtr<nsIWidget> viewWidget = aView->GetWidget();
viewWidget->SetTransparencyMode(mode);
windowWidget->SetWindowShadowStyle(rootFrame->StyleUIReset()->mWindowShadow);
windowWidget->SetWindowShadowStyle(shadow);
if (!aRC)
return;
if (!weak.IsAlive()) {
return;
}
nsBoxLayoutState aState(aPresContext, aRC);
nsSize minSize = rootFrame->GetMinSize(aState);
nsSize maxSize = rootFrame->GetMaxSize(aState);

View File

@ -180,10 +180,16 @@ public:
// Syncs properties to the top level view and window, like transparency and
// shadow.
// The SET_ASYNC indicates that the actual nsIWidget calls to sync the window
// properties should be done async.
enum {
SET_ASYNC = 0x01,
};
static void SyncWindowProperties(nsPresContext* aPresContext,
nsIFrame* aFrame,
nsView* aView,
nsRenderingContext* aRC = nullptr);
nsView* aView,
nsRenderingContext* aRC,
uint32_t aFlags);
// Sets the view's attributes from the frame style.
// - visibility

View File

@ -673,6 +673,16 @@ nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility)
}
}
void
nsView::SetNeedsWindowPropertiesSync()
{
mNeedsWindowPropertiesSync = true;
if (mViewManager) {
mViewManager->PostPendingUpdate();
}
}
// Attach to a top level widget and start receiving mirrored events.
nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget)
{

View File

@ -290,6 +290,8 @@ public:
mForcedRepaint = aForceRepaint;
}
void SetNeedsWindowPropertiesSync();
/**
* Make aWidget direct its events to this view.
* The caller must call DetachWidgetEventHandler before this view
@ -463,6 +465,7 @@ private:
uint32_t mVFlags;
bool mWidgetIsTopLevel;
bool mForcedRepaint;
bool mNeedsWindowPropertiesSync;
};
#endif

View File

@ -367,6 +367,17 @@ nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
aView->GetViewManager()->ProcessPendingUpdatesRecurse(aView, widgets);
for (uint32_t i = 0; i < widgets.Length(); ++i) {
nsView* view = nsView::GetViewFor(widgets[i]);
if (view) {
if (view->mNeedsWindowPropertiesSync) {
view->mNeedsWindowPropertiesSync = false;
if (nsViewManager* vm = view->GetViewManager()) {
if (nsIPresShell* ps = vm->GetPresShell()) {
ps->SyncWindowProperties(view);
}
}
}
}
view = nsView::GetViewFor(widgets[i]);
if (view) {
view->ResetWidgetBounds(false, true);
}