summarylogtreecommitdiffstats
path: root/0009-Fixed-positioning-and-sizes-of-menus-when-the-scale-.patch
blob: 2e153cf2ff0c7005f15d734ba1c7c03edfa3bb3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
From 6077336fd2b3a5402ef07e980ebcd46106d8074e Mon Sep 17 00:00:00 2001
From: Alexander Dunaev <adunaev@igalia.com>
Date: Wed, 17 Jul 2019 05:26:49 +0000
Subject: [PATCH 09/11] Fixed positioning and sizes of menus when the scale
 factor is forced.

When --force-device-scale-factor command line flag is present, the UI scale
is replaced with the value passed with the flag, which should be taken into
account when positioning and sizing the menus.

R=msisov@igalia.com, rjkroege@chromium.org

Bug: 910797
Change-Id: I7880472c29fdaa33e20e2a896e48f922c20680ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1692578
Auto-Submit: Alexander Dunaev <adunaev@igalia.com>
Reviewed-by: Maksim Sisov <msisov@igalia.com>
Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
Commit-Queue: Maksim Sisov <msisov@igalia.com>
Cr-Commit-Position: refs/heads/master@{#678151}
---
 .../wayland/host/wayland_connection.cc        |  2 +-
 .../platform/wayland/host/wayland_screen.cc   |  2 +-
 .../wayland/host/wayland_screen_unittest.cc   | 38 +++++++++++++--
 .../platform/wayland/host/wayland_window.cc   | 46 ++++++++++---------
 .../platform/wayland/host/wayland_window.h    | 37 +++++++++------
 5 files changed, 81 insertions(+), 44 deletions(-)

diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index 72617b5f37a3..a949baf5a934 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -164,7 +164,7 @@ std::vector<WaylandWindow*> WaylandConnection::GetWindowsOnOutput(
     uint32_t output_id) {
   std::vector<WaylandWindow*> result;
   for (auto entry : window_map_) {
-    if (entry.second->GetEnteredOutputsIds().count(output_id) > 0)
+    if (entry.second->entered_outputs_ids().count(output_id) > 0)
       result.push_back(entry.second);
   }
   return result;
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index 694c13f4e4d2..ef372ad794d3 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -107,7 +107,7 @@ display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
     return GetPrimaryDisplay();
 
   const auto* parent_window = window->parent_window();
-  const std::set<uint32_t> entered_outputs_ids = window->GetEnteredOutputsIds();
+  const auto entered_outputs_ids = window->entered_outputs_ids();
   // Although spec says a surface receives enter/leave surface events on
   // create/move/resize actions, this might be called right after a window is
   // created, but it has not been configured by a Wayland compositor and it has
diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index f93ac20d51e0..0a18b8366cae 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -5,8 +5,11 @@
 #include <wayland-server.h>
 #include <memory>
 
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_command_line.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display_observer.h"
+#include "ui/display/display_switches.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
 #include "ui/ozone/platform/wayland/host/wayland_screen.h"
@@ -586,14 +589,39 @@ TEST_P(WaylandScreenTest, SetBufferScale) {
   wl_surface_send_enter(surface_->resource(), output_->resource());
 
   // Change the scale of the output.  Windows looking into that output must get
-  // the new scale and update scale of their buffers.
-  const int32_t kNewScale = 3;
-  EXPECT_CALL(*surface_, SetBufferScale(kNewScale));
-  output_->SetScale(kNewScale);
+  // the new scale and update scale of their buffers.  The default UI scale
+  // equals the output scale.
+  const int32_t kTripleScale = 3;
+  EXPECT_CALL(*surface_, SetBufferScale(kTripleScale));
+  output_->SetScale(kTripleScale);
 
   Sync();
 
-  EXPECT_EQ(window_->buffer_scale(), kNewScale);
+  EXPECT_EQ(window_->buffer_scale(), kTripleScale);
+  EXPECT_EQ(window_->ui_scale_, kTripleScale);
+
+  // Now simulate the --force-device-scale-factor=1.5
+  const float kForcedUIScale = 1.5;
+  base::test::ScopedCommandLine command_line;
+  command_line.GetProcessCommandLine()->AppendSwitchASCII(
+      switches::kForceDeviceScaleFactor,
+      base::StringPrintf("%.1f", kForcedUIScale));
+  display::Display::ResetForceDeviceScaleFactorForTesting();
+
+  // Change the scale of the output again.  Windows must update scale of
+  // their buffers but the UI scale must get the forced value.
+  const int32_t kDoubleScale = 2;
+  // Question ourselves before questioning others!
+  EXPECT_NE(kForcedUIScale, kDoubleScale);
+  EXPECT_CALL(*surface_, SetBufferScale(kDoubleScale));
+  output_->SetScale(kDoubleScale);
+
+  Sync();
+
+  EXPECT_EQ(window_->buffer_scale(), kDoubleScale);
+  EXPECT_EQ(window_->ui_scale_, kForcedUIScale);
+
+  display::Display::ResetForceDeviceScaleFactorForTesting();
 }
 
 INSTANTIATE_TEST_SUITE_P(XdgVersionV5Test,
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index eb79b91892f9..9afed0cc87fb 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -147,6 +147,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
       // Popups need to know their scale earlier to position themselves.
       DCHECK(parent_window_);
       SetBufferScale(parent_window_->buffer_scale_, false);
+      ui_scale_ = parent_window_->ui_scale_;
 
       // TODO(msisov, jkim): Handle notification windows, which are marked
       // as popup windows as well. Those are the windows that do not have
@@ -184,15 +185,19 @@ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
   int32_t new_scale = 0;
   if (parent_window_) {
     new_scale = parent_window_->buffer_scale_;
-  } else if (widget == gfx::kNullAcceleratedWidget) {
-    new_scale = screen->GetPrimaryDisplay().device_scale_factor();
+    ui_scale_ = parent_window_->ui_scale_;
   } else {
-    // This is the main window that is fully set up so we can ask which display
-    // we are at currently.
-    new_scale =
-        connection_->wayland_output_manager()
-            ->GetOutput(screen->GetDisplayForAcceleratedWidget(widget).id())
-            ->scale_factor();
+    const auto display = (widget == gfx::kNullAcceleratedWidget)
+                             ? screen->GetPrimaryDisplay()
+                             : screen->GetDisplayForAcceleratedWidget(widget);
+    new_scale = connection_->wayland_output_manager()
+                    ->GetOutput(display.id())
+                    ->scale_factor();
+
+    if (display::Display::HasForceDeviceScaleFactor())
+      ui_scale_ = display::Display::GetForcedDeviceScaleFactor();
+    else
+      ui_scale_ = display.device_scale_factor();
   }
   SetBufferScale(new_scale, update_bounds);
 }
@@ -203,10 +208,6 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
   return surface_.id();
 }
 
-std::set<uint32_t> WaylandWindow::GetEnteredOutputsIds() const {
-  return entered_outputs_ids_;
-}
-
 void WaylandWindow::CreateXdgPopup() {
   if (bounds_px_.IsEmpty())
     return;
@@ -333,7 +334,7 @@ void WaylandWindow::Show() {
     // bounds.  This makes a difference against the normal flow when the
     // window is created (see |Initialize|).  To equalize things, rescale
     // |bounds_px_| to DIP.  It will be adjusted while creating the popup.
-    bounds_px_ = gfx::ScaleToRoundedRect(bounds_px_, 1.0 / buffer_scale_);
+    bounds_px_ = gfx::ScaleToRoundedRect(bounds_px_, 1.0 / ui_scale_);
     CreateXdgPopup();
     connection_->ScheduleFlush();
   }
@@ -916,13 +917,14 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
                             : parent_window_;
   DCHECK(parent_window);
   DCHECK(buffer_scale_ == parent_window->buffer_scale_);
+  DCHECK(ui_scale_ == parent_window->ui_scale_);
 
   // Chromium positions windows in screen coordinates, but Wayland requires them
   // to be in local surface coordinates aka relative to parent window.
-  const gfx::Rect parent_bounds_px =
-      gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / buffer_scale_);
-  gfx::Rect new_bounds =
-      TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_px);
+  const gfx::Rect parent_bounds_dip =
+      gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / ui_scale_);
+  gfx::Rect new_bounds_dip =
+      TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip);
 
   // Chromium may decide to position nested menu windows on the left side
   // instead of the right side of parent menu windows when the size of the
@@ -942,16 +944,16 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
       !parent_window_->parent_window_->IsMaximized()) {
     auto* top_level_window = parent_window_->parent_window_;
     DCHECK(top_level_window && !top_level_window->xdg_popup());
-    if (new_bounds.x() <= 0 && !top_level_window->IsMaximized()) {
+    if (new_bounds_dip.x() <= 0 && !top_level_window->IsMaximized()) {
       // Position the child menu window on the right side of the parent window
       // and let the Wayland compositor decide how to do constraint
       // adjustements.
-      int new_x =
-          parent_bounds_px.width() - (new_bounds.width() + new_bounds.x());
-      new_bounds.set_x(new_x);
+      int new_x = parent_bounds_dip.width() -
+                  (new_bounds_dip.width() + new_bounds_dip.x());
+      new_bounds_dip.set_x(new_x);
     }
   }
-  return new_bounds;
+  return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_);
 }
 
 WaylandWindow* WaylandWindow::GetTopLevelWindow() {
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 8fcf28fde934..d21e5f48e8ff 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -10,6 +10,8 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/flat_set.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/rect.h"
@@ -52,10 +54,10 @@ class WaylandWindow : public PlatformWindow,
   bool Initialize(PlatformWindowInitProperties properties);
 
   // Updates the surface buffer scale of the window.  Top level windows take
-  // scale according to the scale of their current display or the primary one if
-  // their widget is not yet created, children inherit scale from their parent.
-  // The method recalculates window bounds appropriately if asked to do so
-  // (this is not needed upon window initialization).
+  // scale from the output attached to either their current display or the
+  // primary one if their widget is not yet created, children inherit scale from
+  // their parent.  The method recalculates window bounds appropriately if asked
+  // to do so (this is not needed upon window initialization).
   void UpdateBufferScale(bool update_bounds);
 
   wl_surface* surface() const { return surface_.get(); }
@@ -66,13 +68,6 @@ class WaylandWindow : public PlatformWindow,
 
   gfx::AcceleratedWidget GetWidget() const;
 
-  // Returns the list of wl_outputs aka displays, which this window occupies.
-  // The window can be shown on one or more displays at the same time. An empty
-  // vector can also be returned if the window is not configured on the
-  // compositor side or it has been moved due to unplug action (check the
-  // comment in RemoveEnteredOutputId).
-  std::set<uint32_t> GetEnteredOutputsIds() const;
-
   // Apply the bounds specified in the most recent configure event. This should
   // be called after processing all pending events in the wayland connection.
   void ApplyPendingBounds();
@@ -102,6 +97,10 @@ class WaylandWindow : public PlatformWindow,
 
   bool is_active() const { return is_active_; }
 
+  const base::flat_set<uint32_t>& entered_outputs_ids() const {
+    return entered_outputs_ids_;
+  }
+
   // WmMoveResizeHandler
   void DispatchHostWindowDragMovement(
       int hittest,
@@ -162,6 +161,8 @@ class WaylandWindow : public PlatformWindow,
   void OnDragSessionClose(uint32_t dnd_action);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale);
+
   void SetBoundsDip(const gfx::Rect& bounds_dip);
   void SetBufferScale(int32_t scale, bool update_bounds);
 
@@ -252,7 +253,13 @@ class WaylandWindow : public PlatformWindow,
   bool has_keyboard_focus_ = false;
   bool has_touch_focus_ = false;
   bool has_implicit_grab_ = false;
+  // Wayland's scale factor for the output that this window currently belongs
+  // to.
   int32_t buffer_scale_ = 1;
+  // The UI scale may be forced through the command line, which means that it
+  // replaces the default value that is equal to the natural device scale.
+  // We need it to place and size the menus properly.
+  float ui_scale_ = 1.0;
 
   // Stores current states of the window.
   ui::PlatformWindowState state_;
@@ -268,15 +275,15 @@ class WaylandWindow : public PlatformWindow,
 
   bool is_tooltip_ = false;
 
-  // For top level window, stores the list of entered outputs that the window
-  // is currently in.
+  // For top level window, stores IDs of outputs that the window is currently
+  // rendered at.
   //
   // Not used by popups.  When sub-menus are hidden and shown again, Wayland
-  // 'repositions' sub-menus to wrong outputs by sending them leave and enter
+  // 'repositions' them to wrong outputs by sending them leave and enter
   // events so their list of entered outputs becomes meaningless after they have
   // been hidden at least once.  To determine which output the popup belongs to,
   // we ask its parent.
-  std::set<uint32_t> entered_outputs_ids_;
+  base::flat_set<uint32_t> entered_outputs_ids_;
 
   DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
 };
-- 
2.22.0