fix: use Chromium's way to compute min/max sizes (#38974)

This commit is contained in:
Cheng Zhao 2023-07-06 00:02:05 +09:00 committed by GitHub
parent 52fe76ca28
commit 3fa15ebb7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 397 deletions

View file

@ -316,47 +316,65 @@ bool NativeWindow::IsNormal() {
void NativeWindow::SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) {
extensions::SizeConstraints content_constraints(GetContentSizeConstraints());
if (window_constraints.HasMaximumSize()) {
gfx::Rect max_bounds = WindowBoundsToContentBounds(
gfx::Rect(window_constraints.GetMaximumSize()));
content_constraints.set_maximum_size(max_bounds.size());
}
if (window_constraints.HasMinimumSize()) {
gfx::Rect min_bounds = WindowBoundsToContentBounds(
gfx::Rect(window_constraints.GetMinimumSize()));
content_constraints.set_minimum_size(min_bounds.size());
}
SetContentSizeConstraints(content_constraints);
size_constraints_ = window_constraints;
content_size_constraints_.reset();
}
extensions::SizeConstraints NativeWindow::GetSizeConstraints() const {
extensions::SizeConstraints content_constraints = GetContentSizeConstraints();
extensions::SizeConstraints window_constraints;
if (content_constraints.HasMaximumSize()) {
if (size_constraints_)
return *size_constraints_;
if (!content_size_constraints_)
return extensions::SizeConstraints();
// Convert content size constraints to window size constraints.
extensions::SizeConstraints constraints;
if (content_size_constraints_->HasMaximumSize()) {
gfx::Rect max_bounds = ContentBoundsToWindowBounds(
gfx::Rect(content_constraints.GetMaximumSize()));
window_constraints.set_maximum_size(max_bounds.size());
gfx::Rect(content_size_constraints_->GetMaximumSize()));
constraints.set_maximum_size(max_bounds.size());
}
if (content_constraints.HasMinimumSize()) {
if (content_size_constraints_->HasMinimumSize()) {
gfx::Rect min_bounds = ContentBoundsToWindowBounds(
gfx::Rect(content_constraints.GetMinimumSize()));
window_constraints.set_minimum_size(min_bounds.size());
gfx::Rect(content_size_constraints_->GetMinimumSize()));
constraints.set_minimum_size(min_bounds.size());
}
return window_constraints;
return constraints;
}
void NativeWindow::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
size_constraints_ = size_constraints;
content_size_constraints_ = size_constraints;
size_constraints_.reset();
}
// The return value of GetContentSizeConstraints will be passed to Chromium
// to set min/max sizes of window. Note that we are returning content size
// instead of window size because that is what Chromium expects, see the
// comment of |WidgetSizeIsClientSize| in Chromium's codebase to learn more.
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() const {
return size_constraints_;
if (content_size_constraints_)
return *content_size_constraints_;
if (!size_constraints_)
return extensions::SizeConstraints();
// Convert window size constraints to content size constraints.
// Note that we are not caching the results, because Chromium reccalculates
// window frame size everytime when min/max sizes are passed, and we must
// do the same otherwise the resulting size with frame included will be wrong.
extensions::SizeConstraints constraints;
if (size_constraints_->HasMaximumSize()) {
gfx::Rect max_bounds = WindowBoundsToContentBounds(
gfx::Rect(size_constraints_->GetMaximumSize()));
constraints.set_maximum_size(max_bounds.size());
}
if (size_constraints_->HasMinimumSize()) {
gfx::Rect min_bounds = WindowBoundsToContentBounds(
gfx::Rect(size_constraints_->GetMinimumSize()));
constraints.set_minimum_size(min_bounds.size());
}
return constraints;
}
void NativeWindow::SetMinimumSize(const gfx::Size& size) {
extensions::SizeConstraints size_constraints;
extensions::SizeConstraints size_constraints = GetSizeConstraints();
size_constraints.set_minimum_size(size);
SetSizeConstraints(size_constraints);
}
@ -366,7 +384,7 @@ gfx::Size NativeWindow::GetMinimumSize() const {
}
void NativeWindow::SetMaximumSize(const gfx::Size& size) {
extensions::SizeConstraints size_constraints;
extensions::SizeConstraints size_constraints = GetSizeConstraints();
size_constraints.set_maximum_size(size);
SetSizeConstraints(size_constraints);
}

View file

@ -423,6 +423,13 @@ class NativeWindow : public base::SupportsUserData,
// The "titleBarStyle" option.
TitleBarStyle title_bar_style_ = TitleBarStyle::kNormal;
// Minimum and maximum size.
absl::optional<extensions::SizeConstraints> size_constraints_;
// Same as above but stored as content size, we are storing 2 types of size
// constraints beacause converting between them will cause rounding errors
// on HiDPI displays on some environments.
absl::optional<extensions::SizeConstraints> content_size_constraints_;
std::queue<bool> pending_transitions_;
FullScreenTransitionState fullscreen_transition_state_ =
FullScreenTransitionState::kNone;
@ -450,9 +457,6 @@ class NativeWindow : public base::SupportsUserData,
// Whether window is transparent.
bool transparent_ = false;
// Minimum and maximum size, stored as content size.
extensions::SizeConstraints size_constraints_;
// Whether window can be resized larger than screen.
bool enable_larger_than_screen_ = false;

View file

@ -78,6 +78,7 @@
#include "ui/display/screen.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/win/msg_util.h"
#endif
namespace electron {
@ -138,6 +139,25 @@ gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
return screen_rect;
}
// Chromium uses a buggy implementation that converts content rect to window
// rect when calculating min/max size, we should use the same implementation
// when passing min/max size so we can get correct results.
gfx::Size WindowSizeToContentSizeBuggy(HWND hwnd, const gfx::Size& size) {
// Calculate the size of window frame, using same code with the
// HWNDMessageHandler::OnGetMinMaxInfo method.
// The pitfall is, when window is minimized the calculated window frame size
// will be different from other states.
RECT client_rect, rect;
GetClientRect(hwnd, &client_rect);
GetWindowRect(hwnd, &rect);
CR_DEFLATE_RECT(&rect, &client_rect);
// Convert DIP size to pixel size, do calculation and then return DIP size.
gfx::Rect screen_rect = DIPToScreenRect(hwnd, gfx::Rect(size));
gfx::Size screen_client_size(screen_rect.width() - (rect.right - rect.left),
screen_rect.height() - (rect.bottom - rect.top));
return ScreenToDIPRect(hwnd, gfx::Rect(screen_client_size)).size();
}
#endif
#if defined(USE_OZONE)
@ -812,6 +832,29 @@ void NativeWindowViews::SetContentSizeConstraints(
old_size_constraints_ = size_constraints;
}
#if BUILDFLAG(IS_WIN)
// This override does almost the same with its parent, except that it uses
// the WindowSizeToContentSizeBuggy method to convert window size to content
// size. See the comment of the method for the reason behind this.
extensions::SizeConstraints NativeWindowViews::GetContentSizeConstraints()
const {
if (content_size_constraints_)
return *content_size_constraints_;
if (!size_constraints_)
return extensions::SizeConstraints();
extensions::SizeConstraints constraints;
if (size_constraints_->HasMaximumSize()) {
constraints.set_maximum_size(WindowSizeToContentSizeBuggy(
GetAcceleratedWidget(), size_constraints_->GetMaximumSize()));
}
if (size_constraints_->HasMinimumSize()) {
constraints.set_minimum_size(WindowSizeToContentSizeBuggy(
GetAcceleratedWidget(), size_constraints_->GetMinimumSize()));
}
return constraints;
}
#endif
void NativeWindowViews::SetResizable(bool resizable) {
if (resizable != resizable_) {
// On Linux there is no "resizable" property of a window, we have to set

View file

@ -78,6 +78,9 @@ class NativeWindowViews : public NativeWindow,
SkColor GetBackgroundColor() override;
void SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) override;
#if BUILDFLAG(IS_WIN)
extensions::SizeConstraints GetContentSizeConstraints() const override;
#endif
void SetResizable(bool resizable) override;
bool MoveAbove(const std::string& sourceId) override;
void MoveTop() override;