Skip to content

Commit

Permalink
Bug 1813960 - Move nsContainerFrame::SyncWindowProperties to PresShel…
Browse files Browse the repository at this point in the history
…l. r=smaug

It's a more natural place for it to live, since it concerns only the
root view.

Clean up a bit while at it, and factor out the window size constraints,
which we're going to use momentarily.

Differential Revision: https://phabricator.services.mozilla.com/D168461
  • Loading branch information
emilio committed Feb 2, 2023
1 parent 05e026f commit 2e7a582
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 157 deletions.
137 changes: 122 additions & 15 deletions layout/base/PresShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "mozilla/Unused.h"
#include "mozilla/ViewportUtils.h"
#include "mozilla/gfx/Types.h"
#include "nsBoxLayoutState.h"
#include <algorithm>

#ifdef XP_WIN
Expand Down Expand Up @@ -9668,16 +9669,17 @@ bool PresShell::DoReflow(nsIFrame* target, bool aInterruptible,

target->SetSize(boundsRelativeToTarget.Size());

// Always use boundsRelativeToTarget here, not
// desiredSize.InkOverflowRect(), because for root frames (where they
// could be different, since root frames are allowed to have overflow) the
// root view bounds need to match the viewport bounds; the view manager
// "window dimensions" code depends on it.
nsContainerFrame::SyncFrameViewAfterReflow(
mPresContext, target, target->GetView(), boundsRelativeToTarget);
nsContainerFrame::SyncWindowProperties(mPresContext, target,
target->GetView(), rcx,
nsContainerFrame::SET_ASYNC);
// Always use boundsRelativeToTarget here, not desiredSize.InkOverflowRect(),
// because for root frames (where they could be different, since root frames
// are allowed to have overflow) the root view bounds need to match the
// viewport bounds; the view manager "window dimensions" code depends on it.
if (target->HasView()) {
nsContainerFrame::SyncFrameViewAfterReflow(
mPresContext, target, target->GetView(), boundsRelativeToTarget);
if (target->IsViewportFrame()) {
SyncWindowProperties(/* aSync = */ false);
}
}

target->DidReflow(mPresContext, nullptr);
if (target->IsInScrollAnchorChain()) {
Expand Down Expand Up @@ -11520,13 +11522,118 @@ bool PresShell::DetermineFontSizeInflationState() {
return true;
}

void PresShell::SyncWindowProperties(nsView* aView) {
nsIFrame* frame = aView->GetFrame();
if (frame && mPresContext) {
// CreateReferenceRenderingContext can return nullptr
static nsIWidget* GetPresContextContainerWidget(nsPresContext* aPresContext) {
nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
if (!baseWindow) {
return nullptr;
}

nsCOMPtr<nsIWidget> mainWidget;
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
return mainWidget;
}

static bool IsTopLevelWidget(nsIWidget* aWidget) {
using WindowType = mozilla::widget::WindowType;

auto windowType = aWidget->GetWindowType();
return windowType == WindowType::TopLevel ||
windowType == WindowType::Dialog || windowType == WindowType::Popup ||
windowType == WindowType::Sheet;
}

PresShell::WindowSizeConstraints PresShell::GetWindowSizeConstraints() {
nsSize minSize(0, 0);
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
nsIFrame* rootFrame = FrameConstructor()->GetRootElementStyleFrame();
if (!rootFrame || !mPresContext) {
return {minSize, maxSize};
}
if (rootFrame->IsXULBoxFrame()) {
RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
nsContainerFrame::SyncWindowProperties(mPresContext, frame, aView, rcx, 0);
if (!rcx) {
return {minSize, maxSize};
}
nsBoxLayoutState state(mPresContext, rcx);
minSize = rootFrame->GetXULMinSize(state);
maxSize = rootFrame->GetXULMaxSize(state);
} else {
const auto* pos = rootFrame->StylePosition();
if (pos->mMinWidth.ConvertsToLength()) {
minSize.width = pos->mMinWidth.ToLength();
}
if (pos->mMinHeight.ConvertsToLength()) {
minSize.height = pos->mMinHeight.ToLength();
}
if (pos->mMaxWidth.ConvertsToLength()) {
maxSize.width = pos->mMaxWidth.ToLength();
}
if (pos->mMaxHeight.ConvertsToLength()) {
maxSize.height = pos->mMaxHeight.ToLength();
}
}
return {minSize, maxSize};
}

void PresShell::SyncWindowProperties(bool aSync) {
nsView* view = mViewManager->GetRootView();
if (!view || !view->HasWidget()) {
return;
}
RefPtr pc = mPresContext;
if (!pc) {
return;
}

nsCOMPtr<nsIWidget> windowWidget = GetPresContextContainerWidget(pc);
if (!windowWidget || !IsTopLevelWidget(windowWidget)) {
return;
}

nsIFrame* rootFrame = FrameConstructor()->GetRootElementStyleFrame();
if (!rootFrame) {
return;
}

if (!aSync) {
view->SetNeedsWindowPropertiesSync();
return;
}

AutoWeakFrame weak(rootFrame);
if (!GetRootScrollFrame()) {
// Scrollframes use native widgets which don't work well with
// translucent windows, at least in Windows XP. So if the document
// has a root scrollrame it's useless to try to make it transparent,
// we'll just get something broken.
// We can change this to allow translucent toplevel HTML documents
// (e.g. to do something like Dashboard widgets), once we
// have broad support for translucent scrolled documents, but be
// careful because apparently some Firefox extensions expect
// openDialog("something.html") to produce an opaque window
// even if the HTML doesn't have a background-color set.
auto* canvas = GetCanvasFrame();
widget::TransparencyMode mode = nsLayoutUtils::GetFrameTransparency(
canvas ? canvas : rootFrame, rootFrame);
StyleWindowShadow shadow = rootFrame->StyleUIReset()->mWindowShadow;
nsCOMPtr<nsIWidget> viewWidget = view->GetWidget();
viewWidget->SetTransparencyMode(mode);
windowWidget->SetWindowShadowStyle(shadow);

// For macOS, apply color scheme overrides to the top level window widget.
if (auto scheme = pc->GetOverriddenOrEmbedderColorScheme()) {
windowWidget->SetColorScheme(scheme);
}
}

if (!weak.IsAlive()) {
return;
}

const auto& constraints = GetWindowSizeConstraints();
nsContainerFrame::SetSizeConstraints(pc, windowWidget, constraints.mMinSize,
constraints.mMaxSize);
}

nsresult PresShell::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
Expand Down
7 changes: 6 additions & 1 deletion layout/base/PresShell.h
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,12 @@ class PresShell final : public nsStubDocumentObserver,
return mObservingLayoutFlushes || mReflowContinueTimer;
}

void SyncWindowProperties(nsView* aView);
void SyncWindowProperties(bool aSync);
struct WindowSizeConstraints {
nsSize mMinSize;
nsSize mMaxSize;
};
WindowSizeConstraints GetWindowSizeConstraints();

Document* GetPrimaryContentDocument();

Expand Down
12 changes: 5 additions & 7 deletions layout/base/nsCSSFrameConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2636,13 +2636,11 @@ nsIFrame* nsCSSFrameConstructor::ConstructRootFrame() {
viewportFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);

// Bind the viewport frame to the root view
nsView* rootView = mPresShell->GetViewManager()->GetRootView();
viewportFrame->SetView(rootView);

viewportFrame->SyncFrameViewProperties(rootView);
nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(),
viewportFrame, rootView, nullptr,
nsContainerFrame::SET_ASYNC);
if (nsView* rootView = mPresShell->GetViewManager()->GetRootView()) {
viewportFrame->SetView(rootView);
viewportFrame->SyncFrameViewProperties(rootView);
rootView->SetNeedsWindowPropertiesSync();
}

// Make it an absolute container for fixed-pos elements
viewportFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
Expand Down
122 changes: 0 additions & 122 deletions layout/generic/nsContainerFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -719,128 +719,6 @@ void nsContainerFrame::ReparentFrames(nsFrameList& aFrameList,
}
}

static nsIWidget* GetPresContextContainerWidget(nsPresContext* aPresContext) {
nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
if (!baseWindow) return nullptr;

nsCOMPtr<nsIWidget> mainWidget;
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
return mainWidget;
}

static bool IsTopLevelWidget(nsIWidget* aWidget) {
using WindowType = mozilla::widget::WindowType;

auto windowType = aWidget->GetWindowType();
return windowType == WindowType::TopLevel ||
windowType == WindowType::Dialog || windowType == WindowType::Popup ||
windowType == WindowType::Sheet;
}

void nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
nsIFrame* aFrame, nsView* aView,
gfxContext* aRC, uint32_t aFlags) {
if (!aView || !aView->HasWidget()) {
return;
}

{
const bool isValid = aFrame->IsCanvasFrame() || aFrame->IsViewportFrame();
if (!isValid) {
return;
}
}

nsCOMPtr<nsIWidget> windowWidget =
GetPresContextContainerWidget(aPresContext);
if (!windowWidget || !IsTopLevelWidget(windowWidget)) {
return;
}

nsViewManager* vm = aView->GetViewManager();
nsView* rootView = vm->GetRootView();

if (aView != rootView) {
return;
}

Element* rootElement = aPresContext->Document()->GetRootElement();
if (!rootElement) {
return;
}

nsIFrame* rootFrame =
aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
if (!rootFrame) {
return;
}

if (aFlags & SET_ASYNC) {
aView->SetNeedsWindowPropertiesSync();
return;
}

RefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
AutoWeakFrame weak(rootFrame);

if (!aPresContext->PresShell()->GetRootScrollFrame()) {
// Scrollframes use native widgets which don't work well with
// translucent windows, at least in Windows XP. So if the document
// has a root scrollrame it's useless to try to make it transparent,
// we'll just get something broken.
// We can change this to allow translucent toplevel HTML documents
// (e.g. to do something like Dashboard widgets), once we
// have broad support for translucent scrolled documents, but be
// careful because apparently some Firefox extensions expect
// openDialog("something.html") to produce an opaque window
// even if the HTML doesn't have a background-color set.
auto* canvas = aPresContext->PresShell()->GetCanvasFrame();
widget::TransparencyMode mode = nsLayoutUtils::GetFrameTransparency(
canvas ? canvas : aFrame, rootFrame);
StyleWindowShadow shadow = rootFrame->StyleUIReset()->mWindowShadow;
nsCOMPtr<nsIWidget> viewWidget = aView->GetWidget();
viewWidget->SetTransparencyMode(mode);
windowWidget->SetWindowShadowStyle(shadow);

// For macOS, apply color scheme overrides to the top level window widget.
if (auto scheme = aPresContext->GetOverriddenOrEmbedderColorScheme()) {
windowWidget->SetColorScheme(scheme);
}
}

if (!aRC) {
return;
}

if (!weak.IsAlive()) {
return;
}

nsSize minSize(0, 0);
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
if (rootFrame->IsXULBoxFrame()) {
nsBoxLayoutState aState(aPresContext, aRC);
minSize = rootFrame->GetXULMinSize(aState);
maxSize = rootFrame->GetXULMaxSize(aState);
} else {
auto* pos = rootFrame->StylePosition();
if (pos->mMinWidth.ConvertsToLength()) {
minSize.width = pos->mMinWidth.ToLength();
}
if (pos->mMinHeight.ConvertsToLength()) {
minSize.height = pos->mMinHeight.ToLength();
}
if (pos->mMaxWidth.ConvertsToLength()) {
maxSize.width = pos->mMaxWidth.ToLength();
}
if (pos->mMaxHeight.ConvertsToLength()) {
maxSize.height = pos->mMaxHeight.ToLength();
}
}
SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
}

void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
nsIWidget* aWidget,
const nsSize& aMinSize,
Expand Down
11 changes: 0 additions & 11 deletions layout/generic/nsContainerFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,6 @@ class nsContainerFrame : public nsSplittableFrame {
const nsRect& aInkOverflowArea,
ReflowChildFlags aFlags = ReflowChildFlags::Default);

// 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,
gfxContext* aRC, uint32_t aFlags);

/**
* Converts the minimum and maximum sizes given in inner window app units to
* outer window device pixel sizes and assigns these constraints to the
Expand Down
2 changes: 1 addition & 1 deletion view/nsViewManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
view->mNeedsWindowPropertiesSync = false;
if (nsViewManager* vm = view->GetViewManager()) {
if (PresShell* presShell = vm->GetPresShell()) {
presShell->SyncWindowProperties(view);
presShell->SyncWindowProperties(/* aSync */ true);
}
}
}
Expand Down

0 comments on commit 2e7a582

Please sign in to comment.