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