зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1700148, add an appearance type that forces a dropshadow on menus on Windows, and uses SetWindowRgn to clip the popup to the border radius, r=tnikkel
Differential Revision: https://phabricator.services.mozilla.com/D109833
This commit is contained in:
Родитель
b540936658
Коммит
f625b71d78
|
@ -6658,6 +6658,27 @@ bool nsLayoutUtils::HasNonZeroCornerOnSide(const BorderRadius& aCorners,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
LayoutDeviceIntSize nsLayoutUtils::GetBorderRadiusForMenuDropShadow(
|
||||
const nsIFrame* aFrame) {
|
||||
if (aFrame->StyleUIReset()->mWindowShadow == StyleWindowShadow::Cliprounded) {
|
||||
const auto& corners = aFrame->StyleBorder()->mBorderRadius;
|
||||
|
||||
// Get the width and height of the top-left corner.
|
||||
const LengthPercentage& cornerX = corners.Get(eCornerTopLeftX);
|
||||
const LengthPercentage& cornerY = corners.Get(eCornerTopLeftY);
|
||||
nscoord lengthX = (cornerX.IsLength() ? cornerX.ToLength() : 0);
|
||||
nscoord lengthY = (cornerY.IsLength() ? cornerY.ToLength() : 0);
|
||||
if (lengthX || lengthY) {
|
||||
const nsPresContext* presContext = aFrame->PresContext();
|
||||
return LayoutDeviceIntSize(presContext->AppUnitsToDevPixels(lengthX),
|
||||
presContext->AppUnitsToDevPixels(lengthY));
|
||||
}
|
||||
}
|
||||
|
||||
return LayoutDeviceIntSize();
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsTransparencyMode nsLayoutUtils::GetFrameTransparency(
|
||||
nsIFrame* aBackgroundFrame, nsIFrame* aCSSRootFrame) {
|
||||
|
|
|
@ -2011,6 +2011,15 @@ class nsLayoutUtils {
|
|||
static bool HasNonZeroCornerOnSide(const mozilla::BorderRadius& aCorners,
|
||||
mozilla::Side aSide);
|
||||
|
||||
/**
|
||||
* Return the border radius size (width, height) based only on the top-left
|
||||
* corner. This is a special case used for drawing the Windows 10 drop-shadow,
|
||||
* and only supports a specified length (not percentages) on the top-left
|
||||
* corner.
|
||||
*/
|
||||
static LayoutDeviceIntSize GetBorderRadiusForMenuDropShadow(
|
||||
const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Determine if a widget is likely to require transparency or translucency.
|
||||
* @param aBackgroundFrame The frame that the background is set on. For
|
||||
|
|
|
@ -640,6 +640,7 @@ enum class StyleWindowShadow : uint8_t {
|
|||
Menu,
|
||||
Tooltip,
|
||||
Sheet,
|
||||
Cliprounded, // clip border to popup border-radius
|
||||
};
|
||||
|
||||
// dominant-baseline
|
||||
|
|
|
@ -12943,7 +12943,7 @@ if (false) {
|
|||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: ["default"],
|
||||
other_values: ["none", "menu", "tooltip", "sheet"],
|
||||
other_values: ["none", "menu", "tooltip", "sheet", "cliprounded"],
|
||||
invalid_values: [],
|
||||
};
|
||||
|
||||
|
|
|
@ -315,10 +315,14 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
|
|||
tag = parentContent->NodeInfo()->NameAtom();
|
||||
widgetData.mHasRemoteContent = remote;
|
||||
widgetData.mSupportTranslucency = mode == eTransparencyTransparent;
|
||||
widgetData.mDropShadow =
|
||||
!(mode == eTransparencyTransparent || tag == nsGkAtoms::menulist);
|
||||
widgetData.mPopupLevel = PopupLevel(widgetData.mNoAutoHide);
|
||||
|
||||
// The special cases are menulists and handling the Windows 10
|
||||
// drop-shadow on menus with rounded borders.
|
||||
widgetData.mDropShadow =
|
||||
!(mode == eTransparencyTransparent || tag == nsGkAtoms::menulist) ||
|
||||
StyleUIReset()->mWindowShadow == StyleWindowShadow::Cliprounded;
|
||||
|
||||
// panels which have a parent level need a parent widget. This allows them to
|
||||
// always appear in front of the parent window but behind other windows that
|
||||
// should be in front of it.
|
||||
|
|
|
@ -53,7 +53,7 @@ ${helpers.single_keyword(
|
|||
|
||||
${helpers.single_keyword(
|
||||
"-moz-window-shadow",
|
||||
"default none menu tooltip sheet",
|
||||
"default none menu tooltip sheet cliprounded",
|
||||
engines="gecko",
|
||||
gecko_ffi_name="mWindowShadow",
|
||||
gecko_enum_prefix="StyleWindowShadow",
|
||||
|
|
|
@ -3899,6 +3899,7 @@ static const NSUInteger kWindowShadowOptionsTooltipMojaveOrLater = 4;
|
|||
case StyleWindowShadow::Default: // we treat "default" as "default panel"
|
||||
case StyleWindowShadow::Menu:
|
||||
case StyleWindowShadow::Sheet:
|
||||
case StyleWindowShadow::Cliprounded: // this is a Windows-only value.
|
||||
return kWindowShadowOptionsMenu;
|
||||
|
||||
case StyleWindowShadow::Tooltip:
|
||||
|
|
|
@ -1757,28 +1757,60 @@ bool nsWindow::IsVisible() const { return mIsVisible; }
|
|||
*
|
||||
**************************************************************/
|
||||
|
||||
static bool ShouldHaveRoundedMenuDropShadow(nsWindow* aWindow) {
|
||||
nsView* view = nsView::GetViewFor(aWindow);
|
||||
return view && view->GetFrame() &&
|
||||
view->GetFrame()->StyleUIReset()->mWindowShadow ==
|
||||
StyleWindowShadow::Cliprounded;
|
||||
}
|
||||
|
||||
// XP and Vista visual styles sometimes require window clipping regions to be
|
||||
// applied for proper transparency. These routines are called on size and move
|
||||
// operations.
|
||||
// XXX this is apparently still needed in Windows 7 and later
|
||||
void nsWindow::ClearThemeRegion() {
|
||||
if (!HasGlass() &&
|
||||
(mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
|
||||
(mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
|
||||
if (mWindowType == eWindowType_popup && mPopupType == ePopupTypeMenu &&
|
||||
ShouldHaveRoundedMenuDropShadow(this)) {
|
||||
SetWindowRgn(mWnd, nullptr, false);
|
||||
} else if (!HasGlass() &&
|
||||
(mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
|
||||
(mPopupType == ePopupTypeTooltip ||
|
||||
mPopupType == ePopupTypePanel))) {
|
||||
SetWindowRgn(mWnd, nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
void nsWindow::SetThemeRegion() {
|
||||
// Clip the window to the rounded rect area of the popup if needed.
|
||||
if (mWindowType == eWindowType_popup && mPopupType == ePopupTypeMenu) {
|
||||
nsView* view = nsView::GetViewFor(this);
|
||||
if (view) {
|
||||
LayoutDeviceIntSize size =
|
||||
nsLayoutUtils::GetBorderRadiusForMenuDropShadow(view->GetFrame());
|
||||
if (size.width || size.height) {
|
||||
int32_t width =
|
||||
NSToIntRound(size.width * GetDesktopToDeviceScale().scale);
|
||||
int32_t height =
|
||||
NSToIntRound(size.height * GetDesktopToDeviceScale().scale);
|
||||
HRGN region = CreateRoundRectRgn(0, 0, mBounds.Width(),
|
||||
mBounds.Height(), width, height);
|
||||
if (!SetWindowRgn(mWnd, region, false)) {
|
||||
DeleteObject(region); // region setting failed so delete the region.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Popup types that have a visual styles region applied (bug 376408). This can
|
||||
// be expanded for other window types as needed. The regions are applied
|
||||
// generically to the base window so default constants are used for part and
|
||||
// state. At some point we might need part and state values from
|
||||
// nsNativeThemeWin's GetThemePartAndState, but currently windows that change
|
||||
// shape based on state haven't come up.
|
||||
if (!HasGlass() &&
|
||||
(mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
|
||||
(mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
|
||||
else if (!HasGlass() &&
|
||||
(mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
|
||||
(mPopupType == ePopupTypeTooltip ||
|
||||
mPopupType == ePopupTypePanel))) {
|
||||
HRGN hRgn = nullptr;
|
||||
RECT rect = {0, 0, mBounds.Width(), mBounds.Height()};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче