Bug 1609446 - Make default window-constraints always show the content. r=mats,mstange
This code is used to determine the sizes of the top-level windows. However the code doesn't cause quite desirable behavior (see the bug, and comment 15). This patch does two things: * Unifies the html / xul code-paths. This shouldn't change behavior (because GetXULMinSize returns the fixed min-* property if present anyways), but makes the patch a bit simpler. * Makes the min-width of the XUL window be the pref size instead of the min-size (for the cases where you have no explicit min-width). This looks a bit counter intuitive, but it's the only way to guarantee that the content will be shown. This matches the sizing algorithm that dialogs use by default (via calling window.sizeToContent()), while allowing to undersize the window via a fixed min-width property. This in turn makes sizeToContent() work "by default" on XUL windows, avoiding having to make JS listen to everything that possibly could change the layout of the document (like resolution changes). Differential Revision: https://phabricator.services.mozilla.com/D70209
This commit is contained in:
@@ -5,13 +5,19 @@
|
|||||||
|
|
||||||
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
|
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
|
||||||
|
|
||||||
<!-- minwidth=50 is sum width of chevron and meatball menu button. -->
|
<!--
|
||||||
|
min-width: min-content makes us have the min size of our
|
||||||
|
browser element, which is set explicitly via css in
|
||||||
|
toolbox-host-manager.js. It could be set on the window
|
||||||
|
instead and then it wouldn't be needed.
|
||||||
|
-->
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
id="devtools-toolbox-window"
|
id="devtools-toolbox-window"
|
||||||
macanimationtype="document"
|
macanimationtype="document"
|
||||||
fullscreenbutton="true"
|
fullscreenbutton="true"
|
||||||
windowtype="devtools:toolbox"
|
windowtype="devtools:toolbox"
|
||||||
width="900" height="320"
|
width="900" height="320"
|
||||||
|
style="min-width: min-content"
|
||||||
persist="screenX screenY width height sizemode">
|
persist="screenX screenY width height sizemode">
|
||||||
<tooltip id="aHTMLTooltip" page="true"/>
|
<tooltip id="aHTMLTooltip" page="true"/>
|
||||||
</window>
|
</window>
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ struct nsSize : public mozilla::gfx::BaseSize<nscoord, nsSize> {
|
|||||||
float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||||
inline mozilla::gfx::IntSize ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
inline mozilla::gfx::IntSize ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
||||||
|
|
||||||
|
inline mozilla::gfx::IntSize ScaleToOutsidePixels(
|
||||||
|
float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||||
|
inline mozilla::gfx::IntSize ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this size scaled to a different appunits per pixel (APP) ratio.
|
* Return this size scaled to a different appunits per pixel (APP) ratio.
|
||||||
* @param aFromAPP the APP to scale from
|
* @param aFromAPP the APP to scale from
|
||||||
@@ -44,11 +48,24 @@ inline mozilla::gfx::IntSize nsSize::ScaleToNearestPixels(
|
|||||||
aYScale));
|
aYScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline mozilla::gfx::IntSize nsSize::ScaleToOutsidePixels(
|
||||||
|
float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const {
|
||||||
|
return mozilla::gfx::IntSize(
|
||||||
|
NSToIntCeil(NSAppUnitsToDoublePixels(width, aAppUnitsPerPixel) * aXScale),
|
||||||
|
NSToIntCeil(NSAppUnitsToDoublePixels(height, aAppUnitsPerPixel) *
|
||||||
|
aYScale));
|
||||||
|
}
|
||||||
|
|
||||||
inline mozilla::gfx::IntSize nsSize::ToNearestPixels(
|
inline mozilla::gfx::IntSize nsSize::ToNearestPixels(
|
||||||
nscoord aAppUnitsPerPixel) const {
|
nscoord aAppUnitsPerPixel) const {
|
||||||
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline mozilla::gfx::IntSize nsSize::ToOutsidePixels(
|
||||||
|
nscoord aAppUnitsPerPixel) const {
|
||||||
|
return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||||
|
}
|
||||||
|
|
||||||
inline nsSize nsSize::ScaleToOtherAppUnits(int32_t aFromAPP,
|
inline nsSize nsSize::ScaleToOtherAppUnits(int32_t aFromAPP,
|
||||||
int32_t aToAPP) const {
|
int32_t aToAPP) const {
|
||||||
if (aFromAPP != aToAPP) {
|
if (aFromAPP != aToAPP) {
|
||||||
|
|||||||
@@ -429,6 +429,12 @@ struct LayoutDevicePixel {
|
|||||||
aRect.ToOutsidePixels(aAppUnitsPerDevPixel));
|
aRect.ToOutsidePixels(aAppUnitsPerDevPixel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LayoutDeviceIntSize FromAppUnitsToOutside(
|
||||||
|
const nsSize& aSize, nscoord aAppUnitsPerDevPixel) {
|
||||||
|
return LayoutDeviceIntSize::FromUnknownSize(
|
||||||
|
aSize.ToOutsidePixels(aAppUnitsPerDevPixel));
|
||||||
|
}
|
||||||
|
|
||||||
static LayoutDeviceIntSize FromAppUnitsRounded(const nsSize& aSize,
|
static LayoutDeviceIntSize FromAppUnitsRounded(const nsSize& aSize,
|
||||||
nscoord aAppUnitsPerDevPixel) {
|
nscoord aAppUnitsPerDevPixel) {
|
||||||
return LayoutDeviceIntSize(
|
return LayoutDeviceIntSize(
|
||||||
|
|||||||
@@ -3136,8 +3136,10 @@ nsresult nsDocumentViewer::GetContentSizeInternal(int32_t* aWidth,
|
|||||||
|
|
||||||
// Ceil instead of rounding here, so we can actually guarantee showing all the
|
// Ceil instead of rounding here, so we can actually guarantee showing all the
|
||||||
// content.
|
// content.
|
||||||
*aWidth = std::ceil(presContext->AppUnitsToFloatDevPixels(shellArea.width));
|
auto devOuterSize = LayoutDeviceIntSize::FromAppUnitsToOutside(
|
||||||
*aHeight = std::ceil(presContext->AppUnitsToFloatDevPixels(shellArea.height));
|
shellArea, presContext->AppUnitsPerDevPixel());
|
||||||
|
*aWidth = devOuterSize.width;
|
||||||
|
*aHeight = devOuterSize.height;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -551,18 +551,22 @@ static bool IsTopLevelWidget(nsIWidget* aWidget) {
|
|||||||
void nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
|
void nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
|
||||||
nsIFrame* aFrame, nsView* aView,
|
nsIFrame* aFrame, nsView* aView,
|
||||||
gfxContext* aRC, uint32_t aFlags) {
|
gfxContext* aRC, uint32_t aFlags) {
|
||||||
#ifdef MOZ_XUL
|
if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget()) {
|
||||||
if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIWidget> windowWidget =
|
nsCOMPtr<nsIWidget> windowWidget =
|
||||||
GetPresContextContainerWidget(aPresContext);
|
GetPresContextContainerWidget(aPresContext);
|
||||||
if (!windowWidget || !IsTopLevelWidget(windowWidget)) return;
|
if (!windowWidget || !IsTopLevelWidget(windowWidget)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsViewManager* vm = aView->GetViewManager();
|
nsViewManager* vm = aView->GetViewManager();
|
||||||
nsView* rootView = vm->GetRootView();
|
nsView* rootView = vm->GetRootView();
|
||||||
|
|
||||||
if (aView != rootView) return;
|
if (aView != rootView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Element* rootElement = aPresContext->Document()->GetRootElement();
|
Element* rootElement = aPresContext->Document()->GetRootElement();
|
||||||
if (!rootElement) {
|
if (!rootElement) {
|
||||||
@@ -571,7 +575,9 @@ void nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
|
|||||||
|
|
||||||
nsIFrame* rootFrame =
|
nsIFrame* rootFrame =
|
||||||
aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
|
aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
|
||||||
if (!rootFrame) return;
|
if (!rootFrame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (aFlags & SET_ASYNC) {
|
if (aFlags & SET_ASYNC) {
|
||||||
aView->SetNeedsWindowPropertiesSync();
|
aView->SetNeedsWindowPropertiesSync();
|
||||||
@@ -600,7 +606,9 @@ void nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
|
|||||||
windowWidget->SetWindowShadowStyle(shadow);
|
windowWidget->SetWindowShadowStyle(shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aRC) return;
|
if (!aRC) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!weak.IsAlive()) {
|
if (!weak.IsAlive()) {
|
||||||
return;
|
return;
|
||||||
@@ -608,36 +616,49 @@ void nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
|
|||||||
|
|
||||||
nsSize minSize(0, 0);
|
nsSize minSize(0, 0);
|
||||||
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||||
if (rootElement->IsXULElement()) {
|
|
||||||
nsBoxLayoutState aState(aPresContext, aRC);
|
const auto& pos = *rootFrame->StylePosition();
|
||||||
minSize = rootFrame->GetXULMinSize(aState);
|
#ifdef MOZ_XUL
|
||||||
maxSize = rootFrame->GetXULMaxSize(aState);
|
if (rootFrame->IsXULBoxFrame()) {
|
||||||
} else {
|
nsBoxLayoutState xulState(aPresContext, aRC);
|
||||||
auto* pos = rootFrame->StylePosition();
|
minSize = rootFrame->GetXULMinSize(xulState);
|
||||||
if (pos->mMinWidth.ConvertsToLength()) {
|
const bool isMinContent =
|
||||||
minSize.width = pos->mMinWidth.ToLength();
|
pos.mMinWidth.IsExtremumLength() &&
|
||||||
}
|
pos.mMinWidth.AsExtremumLength() == StyleExtremumLength::MinContent;
|
||||||
if (pos->mMinHeight.ConvertsToLength()) {
|
// By default we behave with min-width: max-content, to ensure that all
|
||||||
minSize.height = pos->mMinHeight.ToLength();
|
// content is shown (i.e., the GetXULPrefSize call below).
|
||||||
}
|
//
|
||||||
if (pos->mMaxWidth.ConvertsToLength()) {
|
// It can be overridden to min-content (i.e., leave GetXULMinSize()) and
|
||||||
maxSize.width = pos->mMaxWidth.ToLength();
|
// a fixed width (handled below).
|
||||||
}
|
if (!isMinContent && !pos.mMinWidth.ConvertsToLength()) {
|
||||||
if (pos->mMaxHeight.ConvertsToLength()) {
|
minSize.width = rootFrame->GetXULPrefSize(xulState).width;
|
||||||
maxSize.height = pos->mMaxHeight.ToLength();
|
|
||||||
}
|
}
|
||||||
|
maxSize = rootFrame->GetXULMaxSize(xulState);
|
||||||
}
|
}
|
||||||
SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
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,
|
void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
|
||||||
nsIWidget* aWidget,
|
nsIWidget* aWidget,
|
||||||
const nsSize& aMinSize,
|
const nsSize& aMinSize,
|
||||||
const nsSize& aMaxSize) {
|
const nsSize& aMaxSize) {
|
||||||
LayoutDeviceIntSize devMinSize(
|
auto devMinSize = LayoutDeviceIntSize::FromAppUnitsToOutside(
|
||||||
aPresContext->AppUnitsToDevPixels(aMinSize.width),
|
aMinSize, aPresContext->AppUnitsPerDevPixel());
|
||||||
aPresContext->AppUnitsToDevPixels(aMinSize.height));
|
|
||||||
LayoutDeviceIntSize devMaxSize(
|
LayoutDeviceIntSize devMaxSize(
|
||||||
aMaxSize.width == NS_UNCONSTRAINEDSIZE
|
aMaxSize.width == NS_UNCONSTRAINEDSIZE
|
||||||
? NS_MAXSIZE
|
? NS_MAXSIZE
|
||||||
@@ -647,9 +668,8 @@ void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
|
|||||||
: aPresContext->AppUnitsToDevPixels(aMaxSize.height));
|
: aPresContext->AppUnitsToDevPixels(aMaxSize.height));
|
||||||
|
|
||||||
// MinSize has a priority over MaxSize
|
// MinSize has a priority over MaxSize
|
||||||
if (devMinSize.width > devMaxSize.width) devMaxSize.width = devMinSize.width;
|
devMaxSize.width = std::max(devMinSize.width, devMaxSize.width);
|
||||||
if (devMinSize.height > devMaxSize.height)
|
devMaxSize.height = std::max(devMinSize.height, devMaxSize.height);
|
||||||
devMaxSize.height = devMinSize.height;
|
|
||||||
|
|
||||||
widget::SizeConstraints constraints(devMinSize, devMaxSize);
|
widget::SizeConstraints constraints(devMinSize, devMaxSize);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
screenY="80"
|
screenY="80"
|
||||||
height="300"
|
height="300"
|
||||||
width="300"
|
width="300"
|
||||||
|
style="min-width: 0"
|
||||||
persist="screenX screenY height width">
|
persist="screenX screenY height width">
|
||||||
|
|
||||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|||||||
Reference in New Issue
Block a user