summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Playfair Cal2019-05-05 02:57:37 +1000
committerDaniel Playfair Cal2019-05-05 02:58:13 +1000
commit0c4b33aa7facd84433b0e35676fb3c70ac86e310 (patch)
treeba3cbf9c37e7cbb1ee4f52bb1585ae06154ef8bf
parent373a8c11a0332d2add5dde61fdaa57f39a49946f (diff)
downloadaur-0c4b33aa7facd84433b0e35676fb3c70ac86e310.tar.gz
73.0.3683.86-4
-rw-r--r--.SRCINFO4
-rw-r--r--PKGBUILD7
-rw-r--r--chromium-ozone-scale.patch1541
3 files changed, 1550 insertions, 2 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 271e71e81472..5fd0920b0687 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,7 +1,7 @@
pkgbase = chromium-ozone
pkgdesc = Chromium built with patches for wayland support via Ozone
pkgver = 73.0.3683.86
- pkgrel = 3
+ pkgrel = 4
url = https://www.chromium.org/Home
install = chromium.install
arch = x86_64
@@ -66,6 +66,7 @@ pkgbase = chromium-ozone
source = chromium-widevine.patch
source = chromium-skia-harmony.patch
source = chromium-ozone-wayland.patch::https://github.com/mirror/chromium/compare/5fe448ea2471245e64adf805d93b358dd9478fa2...Igalia:9acc2112d690af6caf4c5b8d4152b5724a760639.patch
+ source = chromium-ozone-scale.patch
source = chromium-algorithm-header.patch::https://github.com/chromium/chromium/commit/6c0254a78043e32441dbc2e6d4893590dd0d1953.patch
source = chromium-vaapi-build.patch::https://github.com/Igalia/chromium/commit/cdb2e638d4488936c80a2c1b506eecf95ffbee02.patch
sha256sums = 9ebb731576d25901cee5505f3458cf7780b0a39243743d7779f66514716bbfa3
@@ -79,6 +80,7 @@ pkgbase = chromium-ozone
sha256sums = d081f2ef8793544685aad35dea75a7e6264a2cb987ff3541e6377f4a3650a28b
sha256sums = 5887f78b55c4ecbbcba5930f3f0bb7bc0117c2a41c2f761805fcf7f46f1ca2b3
sha256sums = fcb58a760e2dc6c4b2746c12832edd8dfe54dc37113e01b3b5bc108fbeec4c8a
+ sha256sums = 814b441cbb922e895e39b801776e2ee38bd42f6f476887c8b0fd1f6bde34e6b2
sha256sums = 97b9662947460343dd208779e4bb33b3ad955edd4bc84c4fd87edd51e6064e86
sha256sums = 4ed0ac74fef8b63fa5dfd0de02a02cc4a7667898a90ec5365651645777934c14
diff --git a/PKGBUILD b/PKGBUILD
index 05bf64bcebd7..491e35147847 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -6,7 +6,7 @@
pkgname=chromium-ozone
pkgver=73.0.3683.86
-pkgrel=3
+pkgrel=4
_launcher_ver=6
_release_sha=5fe448ea2471245e64adf805d93b358dd9478fa2
_igalia_sha=9acc2112d690af6caf4c5b8d4152b5724a760639
@@ -37,6 +37,7 @@ source=(https://commondatastorage.googleapis.com/chromium-browser-official/chrom
chromium-widevine.patch
chromium-skia-harmony.patch
chromium-ozone-wayland.patch::https://github.com/mirror/chromium/compare/${_release_sha}...Igalia:${_igalia_sha}.patch
+ chromium-ozone-scale.patch
chromium-algorithm-header.patch::https://github.com/chromium/chromium/commit/6c0254a78043e32441dbc2e6d4893590dd0d1953.patch
chromium-vaapi-build.patch::https://github.com/Igalia/chromium/commit/cdb2e638d4488936c80a2c1b506eecf95ffbee02.patch)
sha256sums=('9ebb731576d25901cee5505f3458cf7780b0a39243743d7779f66514716bbfa3'
@@ -50,6 +51,7 @@ sha256sums=('9ebb731576d25901cee5505f3458cf7780b0a39243743d7779f66514716bbfa3'
'd081f2ef8793544685aad35dea75a7e6264a2cb987ff3541e6377f4a3650a28b'
'5887f78b55c4ecbbcba5930f3f0bb7bc0117c2a41c2f761805fcf7f46f1ca2b3'
'fcb58a760e2dc6c4b2746c12832edd8dfe54dc37113e01b3b5bc108fbeec4c8a'
+ '814b441cbb922e895e39b801776e2ee38bd42f6f476887c8b0fd1f6bde34e6b2'
'97b9662947460343dd208779e4bb33b3ad955edd4bc84c4fd87edd51e6064e86'
'4ed0ac74fef8b63fa5dfd0de02a02cc4a7667898a90ec5365651645777934c14')
@@ -125,6 +127,9 @@ prepare() {
# https://github.com/mirror/chromium/compare/36f8ce7e1dc05b379a1de75320ebd5d50bdc2fab...Igalia:ozone-wayland-stable/72.0.3626.81.patch
patch -Np1 -i ../chromium-ozone-wayland.patch
+ # https://chromium-review.googlesource.com/c/chromium/src/+/1472617
+ patch -Np1 -i ../chromium-ozone-scale.patch
+
# https://chromium-review.googlesource.com/c/chromium/src/+/1454356
patch -Np1 -i ../chromium-algorithm-header.patch
diff --git a/chromium-ozone-scale.patch b/chromium-ozone-scale.patch
new file mode 100644
index 000000000000..2291787d3d76
--- /dev/null
+++ b/chromium-ozone-scale.patch
@@ -0,0 +1,1541 @@
+commit f2f7f4d81479a69a34ed9227eceb9eb8b6f6ceac
+Author: Alexander Dunaev <adunaev@igalia.com>
+Date: Fri May 3 17:12:15 2019 +0000
+
+ [ozone/wayland] Fixed some issues related to scaling on HiDPI screens.
+
+ There are two independent scale factors that were not used properly, which
+ caused incorrect scaling behaviour on HiDPI screens.
+
+ The first scale factor is property of the window manager (Wayland); it is
+ integral and expected to be used as scale of buffers that back the window
+ surface (see wl_surface_set_buffer_scale). This value is provided by
+ the window manager, and neither user nor browser can affect it directly.
+ I will refer to this value as 'platform scale'.
+
+ The second scale factor defines how much the browser UI should be scaled.
+ This value is real (floating point), and it can be set via the aforementioned
+ --force-device-scale-factor command line flag. The default base scale is
+ equal to the platform scale, which results in UI that looks more or less
+ the same size as other applications. This scale is set in display::Display,
+ and I will refer to it as 'UI scale'.
+
+ So here is what this CL fixes.
+
+ 1. The platform scale had been forwarded to the UI scale with no regard to
+ the forcing flag, which caused issue 910797 (the flag did not have any
+ effect).
+ 2. The platform scale had not been used to scale the backing buffers, which
+ caused the issue 929871 (blurry contents of windows on HDPI screens).
+ 3. The coordinate-aware events (mouse and touch) and window sizing logic
+ were not aware of the buffer scaling.
+ 4. Both parameters had been named 'device scale factors' which was confusing.
+
+ There are some issues that will be fixed in consequent CLs. The forced
+ device scale factor is not propagated properly through display::Display.
+ For fixing that, https://crbug.com/950313 is filed.
+
+ Bug: 910797
+ Change-Id: I51a95e7218306295e3ab1f90d4b088b8bee93951
+ Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1472617
+ Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
+ Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
+ Reviewed-by: Bret Sepulveda <bsep@chromium.org>
+ Reviewed-by: Maksim Sisov <msisov@igalia.com>
+ Reviewed-by: Malay Keshav <malaykeshav@chromium.org>
+ Reviewed-by: Dominick Ng <dominickn@chromium.org>
+ Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
+ Commit-Queue: Alexander Dunaev <adunaev@igalia.com>
+ Auto-Submit: Alexander Dunaev <adunaev@igalia.com>
+ Cr-Commit-Position: refs/heads/master@{#656423}
+
+diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
+index 0817b4eca4f4..07b3e1a6fab8 100644
+--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
++++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
+@@ -166,7 +166,7 @@ void BrowserCompositorMac::UpdateSurfaceFromChild(
+ const viz::LocalSurfaceIdAllocation& child_local_surface_id_allocation) {
+ if (dfh_local_surface_id_allocator_.UpdateFromChild(
+ child_local_surface_id_allocation)) {
+- dfh_display_.set_device_scale_factor(new_device_scale_factor);
++ dfh_display_.SetDeviceScaleFactor(new_device_scale_factor);
+ dfh_size_dip_ = gfx::ConvertSizeToDIP(dfh_display_.device_scale_factor(),
+ new_size_in_pixels);
+ dfh_size_pixels_ = new_size_in_pixels;
+@@ -400,7 +400,7 @@ void BrowserCompositorMac::SetParentUiLayer(ui::Layer* new_parent_ui_layer) {
+
+ bool BrowserCompositorMac::ForceNewSurfaceForTesting() {
+ display::Display new_display(dfh_display_);
+- new_display.set_device_scale_factor(new_display.device_scale_factor() * 2.0f);
++ new_display.SetDeviceScaleFactor(new_display.device_scale_factor() * 2.0f);
+ return UpdateSurfaceFromNSView(dfh_size_dip_, new_display);
+ }
+
+diff --git a/content/common/cursors/webcursor_unittest.cc b/content/common/cursors/webcursor_unittest.cc
+index d5454d35332c..855aff061cb5 100644
+--- a/content/common/cursors/webcursor_unittest.cc
++++ b/content/common/cursors/webcursor_unittest.cc
+@@ -258,7 +258,7 @@ TEST(WebCursorTest, AlphaConversion) {
+ #if defined(USE_AURA)
+ TEST(WebCursorTest, CursorScaleFactor) {
+ display::Display display;
+- display.set_device_scale_factor(80.2f);
++ display.SetDeviceScaleFactor(4.2f);
+
+ CursorInfo info;
+ info.type = WebCursorInfo::kTypeCustom;
+@@ -325,7 +325,7 @@ namespace {
+
+ void ScaleCursor(float scale_factor, int hotspot_x, int hotspot_y) {
+ display::Display display;
+- display.set_device_scale_factor(scale_factor);
++ display.SetDeviceScaleFactor(scale_factor);
+
+ CursorInfo info;
+ info.type = WebCursorInfo::kTypeCustom;
+diff --git a/ui/android/display_android_manager.cc b/ui/android/display_android_manager.cc
+index 7352daa7127f..746680acbc55 100644
+--- a/ui/android/display_android_manager.cc
++++ b/ui/android/display_android_manager.cc
+@@ -69,6 +69,30 @@ Display DisplayAndroidManager::GetDisplayMatching(
+ return GetPrimaryDisplay();
+ }
+
++void DisplayAndroidManager::DoUpdateDisplay(display::Display* display,
++ gfx::Size size_in_pixels,
++ float dipScale,
++ int rotationDegrees,
++ int bitsPerPixel,
++ int bitsPerComponent,
++ bool isWideColorGamut) {
++ if (!Display::HasForceDeviceScaleFactor())
++ display->SetDeviceScaleFactor(dipScale);
++ if (!Display::HasForceDisplayColorProfile()) {
++ if (isWideColorGamut) {
++ display->set_color_space(gfx::ColorSpace::CreateDisplayP3D65());
++ } else {
++ display->set_color_space(gfx::ColorSpace::CreateSRGB());
++ }
++ }
++
++ display->set_size_in_pixels(size_in_pixels);
++ display->SetRotationAsDegree(rotationDegrees);
++ display->set_color_depth(bitsPerPixel);
++ display->set_depth_per_component(bitsPerComponent);
++ display->set_is_monochrome(bitsPerComponent == 0);
++}
++
+ // Methods called from Java
+
+ void DisplayAndroidManager::UpdateDisplay(
+diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
+index 08ffa5e729bf..5c6b9c5dc01a 100644
+--- a/ui/aura/window_tree_host.cc
++++ b/ui/aura/window_tree_host.cc
+@@ -28,7 +28,6 @@
+ #include "ui/compositor/compositor_switches.h"
+ #include "ui/compositor/dip_util.h"
+ #include "ui/compositor/layer.h"
+-#include "ui/display/display.h"
+ #include "ui/display/screen.h"
+ #include "ui/events/keycodes/dom/dom_code.h"
+ #include "ui/gfx/geometry/insets.h"
+@@ -114,9 +113,7 @@ WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget(
+ }
+
+ void WindowTreeHost::InitHost() {
+- display::Display display =
+- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+- device_scale_factor_ = display.device_scale_factor();
++ device_scale_factor_ = GetDisplay().device_scale_factor();
+
+ UpdateRootWindowSizeInPixels();
+ InitCompositor();
+@@ -283,7 +280,7 @@ ui::EventSink* WindowTreeHost::GetEventSink() {
+ }
+
+ int64_t WindowTreeHost::GetDisplayId() {
+- return display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id();
++ return GetDisplay().id();
+ }
+
+ void WindowTreeHost::Show() {
+@@ -356,8 +353,11 @@ WindowTreeHost::WindowTreeHost(std::unique_ptr<Window> window)
+ if (!window_)
+ window_ = new Window(nullptr);
+ display::Screen::GetScreen()->AddObserver(this);
+- auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+- device_scale_factor_ = display.device_scale_factor();
++ device_scale_factor_ = GetDisplay().device_scale_factor();
++}
++
++display::Display WindowTreeHost::GetDisplay() const {
++ return display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+ }
+
+ void WindowTreeHost::IntializeDeviceScaleFactor(float device_scale_factor) {
+@@ -384,7 +384,7 @@ void WindowTreeHost::DestroyDispatcher() {
+ // ~Window, but by that time any calls to virtual methods overriden here (such
+ // as GetRootWindow()) result in Window's implementation. By destroying here
+ // we ensure GetRootWindow() still returns this.
+- //window()->RemoveOrDestroyChildren();
++ // window()->RemoveOrDestroyChildren();
+ }
+
+ void WindowTreeHost::CreateCompositor(
+@@ -425,8 +425,7 @@ void WindowTreeHost::InitCompositor() {
+ window()->GetLocalSurfaceIdAllocation());
+ compositor_->SetRootLayer(window()->layer());
+
+- display::Display display =
+- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
++ display::Display display = GetDisplay();
+ compositor_->SetDisplayColorSpace(display.color_space());
+ }
+
+@@ -450,9 +449,7 @@ void WindowTreeHost::OnHostResizedInPixels(
+ const viz::LocalSurfaceIdAllocation& new_local_surface_id_allocation) {
+ // TODO(jonross) Unify all OnHostResizedInPixels to have both
+ // viz::LocalSurfaceId and allocation time as optional parameters.
+- display::Display display =
+- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+- device_scale_factor_ = display.device_scale_factor();
++ device_scale_factor_ = GetDisplay().device_scale_factor();
+ UpdateRootWindowSizeInPixels();
+
+ // Allocate a new LocalSurfaceId for the new state.
+@@ -479,8 +476,7 @@ void WindowTreeHost::OnHostWorkspaceChanged() {
+ void WindowTreeHost::OnHostDisplayChanged() {
+ if (!compositor_)
+ return;
+- display::Display display =
+- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
++ display::Display display = GetDisplay();
+ compositor_->SetDisplayColorSpace(display.color_space());
+ }
+
+@@ -529,11 +525,8 @@ void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location,
+ last_cursor_request_position_in_host_ = host_location;
+ MoveCursorToScreenLocationInPixels(host_location);
+ client::CursorClient* cursor_client = client::GetCursorClient(window());
+- if (cursor_client) {
+- const display::Display& display =
+- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
+- cursor_client->SetDisplay(display);
+- }
++ if (cursor_client)
++ cursor_client->SetDisplay(GetDisplay());
+ dispatcher()->OnCursorMovedToRootLocation(root_location);
+ }
+
+diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
+index 7730ef6a58a7..4629aa61f9d7 100644
+--- a/ui/aura/window_tree_host.h
++++ b/ui/aura/window_tree_host.h
+@@ -24,6 +24,7 @@
+ #include "ui/base/cursor/cursor.h"
+ #include "ui/base/ime/input_method_delegate.h"
+ #include "ui/compositor/compositor_observer.h"
++#include "ui/display/display.h"
+ #include "ui/display/display_observer.h"
+ #include "ui/events/event_source.h"
+ #include "ui/events/platform_event.h"
+@@ -34,7 +35,7 @@ class Point;
+ class Rect;
+ class Size;
+ class Transform;
+-}
++} // namespace gfx
+
+ namespace ui {
+ class Compositor;
+@@ -43,7 +44,7 @@ class EventSink;
+ class InputMethod;
+ class ViewProp;
+ struct PlatformWindowInitProperties;
+-}
++} // namespace ui
+
+ namespace aura {
+
+@@ -254,6 +255,9 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
+
+ explicit WindowTreeHost(std::unique_ptr<Window> window = nullptr);
+
++ // Gets the display that this window tree host resides at.
++ display::Display GetDisplay() const;
++
+ // Set the cached display device scale factor. This should only be called
+ // during subclass initialization, when the value is needed before InitHost().
+ void IntializeDeviceScaleFactor(float device_scale_factor);
+diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc
+index 99159327dd48..d839420eb361 100644
+--- a/ui/aura/window_tree_host_platform.cc
++++ b/ui/aura/window_tree_host_platform.cc
+@@ -272,7 +272,6 @@ void WindowTreeHostPlatform::OnAcceleratedWidgetDestroyed() {
+ widget_ = gfx::kNullAcceleratedWidget;
+ }
+
+-void WindowTreeHostPlatform::OnActivationChanged(bool active) {
+-}
++void WindowTreeHostPlatform::OnActivationChanged(bool active) {}
+
+ } // namespace aura
+diff --git a/ui/display/display.cc b/ui/display/display.cc
+index 68a5b3a9cc2d..187af470dedf 100644
+--- a/ui/display/display.cc
++++ b/ui/display/display.cc
+@@ -230,6 +230,12 @@ Display Display::GetDefaultDisplay() {
+ return Display(kDefaultDisplayId, gfx::Rect(0, 0, 1920, 1080));
+ }
+
++void Display::SetDeviceScaleFactor(float scale) {
++ if (HasForceDeviceScaleFactor())
++ return;
++ device_scale_factor_ = scale;
++}
++
+ int Display::RotationAsDegree() const {
+ switch (rotation_) {
+ case ROTATE_0:
+diff --git a/ui/display/display.h b/ui/display/display.h
+index 53f3e95c8243..5e316dfec472 100644
+--- a/ui/display/display.h
++++ b/ui/display/display.h
+@@ -148,12 +148,12 @@ class DISPLAY_EXPORT Display final {
+ const gfx::Rect& work_area() const { return work_area_; }
+ void set_work_area(const gfx::Rect& work_area) { work_area_ = work_area; }
+
+- // Output device's pixel scale factor. This specifies how much the
+- // UI should be scaled when the actual output has more pixels than
+- // standard displays (which is around 100~120dpi.) The potential return
+- // values depend on each platforms.
++ // Pixel scale factor. This specifies how much the UI should be scaled when
++ // rendering on the actual output. This is needed when the latter has more
++ // pixels than standard displays (which is around 100~120dpi). The potential
++ // return values depend on each platforms.
+ float device_scale_factor() const { return device_scale_factor_; }
+- void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
++ void SetDeviceScaleFactor(float scale);
+
+ Rotation rotation() const { return rotation_; }
+ void set_rotation(Rotation rotation) { rotation_ = rotation; }
+@@ -178,7 +178,7 @@ class DISPLAY_EXPORT Display final {
+ gfx::Insets GetWorkAreaInsets() const;
+
+ // Sets the device scale factor and display bounds in pixel. This
+- // updates the work are using the same insets between old bounds and
++ // updates the work area using the same insets between old bounds and
+ // work area.
+ void SetScaleAndBounds(float device_scale_factor,
+ const gfx::Rect& bounds_in_pixel);
+@@ -187,7 +187,7 @@ class DISPLAY_EXPORT Display final {
+ // between old bounds and work area.
+ void SetSize(const gfx::Size& size_in_pixel);
+
+- // Computes and updates the display's work are using
++ // Computes and updates the display's work area using
+ // |work_area_insets| and the bounds.
+ void UpdateWorkAreaFromInsets(const gfx::Insets& work_area_insets);
+
+@@ -234,9 +234,7 @@ class DISPLAY_EXPORT Display final {
+
+ // The number of bits per pixel. Used by media query APIs.
+ int color_depth() const { return color_depth_; }
+- void set_color_depth(int color_depth) {
+- color_depth_ = color_depth;
+- }
++ void set_color_depth(int color_depth) { color_depth_ = color_depth; }
+
+ // The number of bits per color component (all color components are assumed to
+ // have the same number of bits). Used by media query APIs.
+diff --git a/ui/display/display_change_notifier_unittest.cc b/ui/display/display_change_notifier_unittest.cc
+index af69515cba98..346892980c7a 100644
+--- a/ui/display/display_change_notifier_unittest.cc
++++ b/ui/display/display_change_notifier_unittest.cc
+@@ -412,9 +412,9 @@ TEST(DisplayChangeNotifierTest, NotifyDisplaysChanged_Changed_DSF) {
+
+ std::vector<Display> old_displays, new_displays;
+ old_displays.push_back(Display(1));
+- old_displays[0].set_device_scale_factor(1.f);
++ old_displays[0].SetDeviceScaleFactor(1.f);
+ new_displays.push_back(Display(1));
+- new_displays[0].set_device_scale_factor(2.f);
++ new_displays[0].SetDeviceScaleFactor(2.f);
+
+ change_notifier.NotifyDisplaysChanged(old_displays, new_displays);
+ EXPECT_EQ(1, observer.display_changed());
+@@ -436,8 +436,8 @@ TEST(DisplayChangeNotifierTest, NotifyDisplaysChanged_Changed_Multi_Displays) {
+ new_displays.push_back(Display(2));
+ new_displays.push_back(Display(3));
+
+- old_displays[0].set_device_scale_factor(1.f);
+- new_displays[0].set_device_scale_factor(2.f);
++ old_displays[0].SetDeviceScaleFactor(1.f);
++ new_displays[0].SetDeviceScaleFactor(2.f);
+
+ old_displays[1].set_bounds(gfx::Rect(0, 0, 200, 200));
+ new_displays[1].set_bounds(gfx::Rect(0, 0, 400, 400));
+@@ -456,11 +456,11 @@ TEST(DisplayChangeNotifierTest, NotifyDisplaysChanged_Changed_Multi_Metrics) {
+
+ std::vector<Display> old_displays, new_displays;
+ old_displays.push_back(Display(1, gfx::Rect(0, 0, 200, 200)));
+- old_displays[0].set_device_scale_factor(1.f);
++ old_displays[0].SetDeviceScaleFactor(1.f);
+ old_displays[0].SetRotationAsDegree(0);
+
+ new_displays.push_back(Display(1, gfx::Rect(100, 100, 200, 200)));
+- new_displays[0].set_device_scale_factor(2.f);
++ new_displays[0].SetDeviceScaleFactor(2.f);
+ new_displays[0].SetRotationAsDegree(90);
+
+ change_notifier.NotifyDisplaysChanged(old_displays, new_displays);
+diff --git a/ui/display/display_list.cc b/ui/display/display_list.cc
+index 9edacb7399ea..cb4867a56ca3 100644
+--- a/ui/display/display_list.cc
++++ b/ui/display/display_list.cc
+@@ -90,7 +90,7 @@ uint32_t DisplayList::UpdateDisplay(const Display& display, Type type) {
+ changed_values |= DisplayObserver::DISPLAY_METRIC_ROTATION;
+ }
+ if (local_display->device_scale_factor() != display.device_scale_factor()) {
+- local_display->set_device_scale_factor(display.device_scale_factor());
++ local_display->SetDeviceScaleFactor(display.device_scale_factor());
+ changed_values |= DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+ }
+ if (local_display->color_space() != display.color_space()) {
+diff --git a/ui/display/ios/screen_ios.mm b/ui/display/ios/screen_ios.mm
+index cb3c47b282b5..7f26be4d24c3 100644
+--- a/ui/display/ios/screen_ios.mm
++++ b/ui/display/ios/screen_ios.mm
+@@ -17,7 +17,7 @@ class ScreenIos : public ScreenBase {
+ UIScreen* mainScreen = [UIScreen mainScreen];
+ CHECK(mainScreen);
+ Display display(0, gfx::Rect(mainScreen.bounds));
+- display.set_device_scale_factor([mainScreen scale]);
++ display.SetDeviceScaleFactor([mainScreen scale]);
+ ProcessDisplayChanged(display, true /* is_primary */);
+ }
+
+diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
+index 96f17137071a..79a7e39b05e2 100644
+--- a/ui/display/mac/screen_mac.mm
++++ b/ui/display/mac/screen_mac.mm
+@@ -78,7 +78,7 @@ Display BuildDisplayForScreen(NSScreen* screen) {
+ CGFloat scale = [screen backingScaleFactor];
+ if (Display::HasForceDeviceScaleFactor())
+ scale = Display::GetForcedDeviceScaleFactor();
+- display.set_device_scale_factor(scale);
++ display.SetDeviceScaleFactor(scale);
+
+ // Compute the color profile.
+ gfx::ICCProfile icc_profile;
+diff --git a/ui/display/mojo/display_struct_traits.cc b/ui/display/mojo/display_struct_traits.cc
+index 2603edefcccc..6bfba6a47650 100644
+--- a/ui/display/mojo/display_struct_traits.cc
++++ b/ui/display/mojo/display_struct_traits.cc
+@@ -126,7 +126,7 @@ bool StructTraits<display::mojom::DisplayDataView, display::Display>::Read(
+ if (!data.ReadWorkArea(&out->work_area_))
+ return false;
+
+- out->set_device_scale_factor(data.device_scale_factor());
++ out->SetDeviceScaleFactor(data.device_scale_factor());
+
+ if (!data.ReadRotation(&out->rotation_))
+ return false;
+diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc
+index 32a460e93949..83b860a7b5e1 100644
+--- a/ui/display/mojo/display_struct_traits_unittest.cc
++++ b/ui/display/mojo/display_struct_traits_unittest.cc
+@@ -131,7 +131,7 @@ TEST(DisplayStructTraitsTest, SetAllDisplayValues) {
+
+ Display input(246345234, bounds);
+ input.set_work_area(work_area);
+- input.set_device_scale_factor(2.0f);
++ input.SetDeviceScaleFactor(2.0f);
+ input.set_rotation(Display::ROTATE_270);
+ input.set_touch_support(Display::TouchSupport::AVAILABLE);
+ input.set_accelerometer_support(Display::AccelerometerSupport::UNAVAILABLE);
+diff --git a/ui/display/win/screen_win.cc b/ui/display/win/screen_win.cc
+index cb17d76dd94f..9701116b9e79 100644
+--- a/ui/display/win/screen_win.cc
++++ b/ui/display/win/screen_win.cc
+@@ -172,7 +172,7 @@ Display CreateDisplayFromDisplayInfo(const DisplayInfo& display_info,
+ bool hdr_enabled) {
+ Display display(display_info.id());
+ float scale_factor = display_info.device_scale_factor();
+- display.set_device_scale_factor(scale_factor);
++ display.SetDeviceScaleFactor(scale_factor);
+ display.set_work_area(
+ gfx::ScaleToEnclosingRect(display_info.screen_work_rect(),
+ 1.0f / scale_factor));
+diff --git a/ui/display/win/screen_win_display.cc b/ui/display/win/screen_win_display.cc
+index 5a000b563015..cdb36ccf29c1 100644
+--- a/ui/display/win/screen_win_display.cc
++++ b/ui/display/win/screen_win_display.cc
+@@ -14,7 +14,7 @@ namespace {
+ Display CreateDisplayFromDisplayInfo(const DisplayInfo& display_info) {
+ Display display(display_info.id());
+ float scale_factor = display_info.device_scale_factor();
+- display.set_device_scale_factor(scale_factor);
++ display.SetDeviceScaleFactor(scale_factor);
+ display.set_work_area(
+ gfx::ScaleToEnclosingRect(display_info.screen_work_rect(),
+ 1.0f / scale_factor));
+diff --git a/ui/ozone/platform/scenic/scenic_screen.cc b/ui/ozone/platform/scenic/scenic_screen.cc
+index e7658c5cf277..a504ad649046 100644
+--- a/ui/ozone/platform/scenic/scenic_screen.cc
++++ b/ui/ozone/platform/scenic/scenic_screen.cc
+@@ -55,7 +55,7 @@ void ScenicScreen::OnWindowMetrics(int32_t window_id,
+ });
+ DCHECK(display_it != displays_.end());
+
+- display_it->set_device_scale_factor(device_pixel_ratio);
++ display_it->SetDeviceScaleFactor(device_pixel_ratio);
+ for (auto& observer : observers_) {
+ observer.OnDisplayMetricsChanged(
+ *display_it,
+diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc
+index e7095507a83d..76c075cea38d 100644
+--- a/ui/ozone/platform/wayland/wayland_connection.cc
++++ b/ui/ozone/platform/wayland/wayland_connection.cc
+@@ -160,6 +160,16 @@ WaylandWindow* WaylandConnection::GetCurrentKeyboardFocusedWindow() {
+ return nullptr;
+ }
+
++std::vector<WaylandWindow*> WaylandConnection::GetWindowsOnDisplay(
++ uint32_t display_id) {
++ std::vector<WaylandWindow*> result;
++ for (auto entry : window_map_) {
++ if (entry.second->GetEnteredOutputsIds().count(display_id) > 0)
++ result.push_back(entry.second);
++ }
++ return result;
++}
++
+ void WaylandConnection::AddWindow(gfx::AcceleratedWidget widget,
+ WaylandWindow* window) {
+ window_map_[widget] = window;
+diff --git a/ui/ozone/platform/wayland/wayland_connection.h b/ui/ozone/platform/wayland/wayland_connection.h
+index c7da42b930dd..575b5fbf4b05 100644
+--- a/ui/ozone/platform/wayland/wayland_connection.h
++++ b/ui/ozone/platform/wayland/wayland_connection.h
+@@ -99,6 +99,9 @@ class WaylandConnection : public PlatformEventSource,
+ WaylandWindow* GetWindowWithLargestBounds();
+ WaylandWindow* GetCurrentFocusedWindow();
+ WaylandWindow* GetCurrentKeyboardFocusedWindow();
++ // TODO(adunaev) remove this in favor of targeted subscription of windows to
++ // their displays.
++ std::vector<WaylandWindow*> GetWindowsOnDisplay(uint32_t display_id);
+ void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window);
+ void RemoveWindow(gfx::AcceleratedWidget widget);
+
+@@ -220,7 +223,7 @@ class WaylandConnection : public PlatformEventSource,
+ // xdg_shell_listener
+ static void Ping(void* data, xdg_shell* shell, uint32_t serial);
+
+- std::map<gfx::AcceleratedWidget, WaylandWindow*> window_map_;
++ base::flat_map<gfx::AcceleratedWidget, WaylandWindow*> window_map_;
+
+ wl::Object<wl_display> display_;
+ wl::Object<wl_registry> registry_;
+diff --git a/ui/ozone/platform/wayland/wayland_output.cc b/ui/ozone/platform/wayland/wayland_output.cc
+index 91cdf2c43bf5..719f251a31b9 100644
+--- a/ui/ozone/platform/wayland/wayland_output.cc
++++ b/ui/ozone/platform/wayland/wayland_output.cc
+@@ -11,14 +11,10 @@
+
+ namespace ui {
+
+-namespace {
+-constexpr float kDefaultScaleFactor = 1.0f;
+-}
+-
+ WaylandOutput::WaylandOutput(const uint32_t output_id, wl_output* output)
+ : output_id_(output_id),
+ output_(output),
+- device_scale_factor_(kDefaultScaleFactor),
++ scale_factor_(kDefaultScaleFactor),
+ rect_in_physical_pixels_(gfx::Rect()) {}
+
+ WaylandOutput::~WaylandOutput() = default;
+@@ -36,7 +32,7 @@ void WaylandOutput::Initialize(Delegate* delegate) {
+ void WaylandOutput::TriggerDelegateNotification() const {
+ DCHECK(!rect_in_physical_pixels_.IsEmpty());
+ delegate_->OnOutputHandleMetrics(output_id_, rect_in_physical_pixels_,
+- device_scale_factor_);
++ scale_factor_);
+ }
+
+ // static
+@@ -80,7 +76,7 @@ void WaylandOutput::OutputHandleScale(void* data,
+ int32_t factor) {
+ WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
+ if (wayland_output)
+- wayland_output->device_scale_factor_ = factor;
++ wayland_output->scale_factor_ = factor;
+ }
+
+ } // namespace ui
+diff --git a/ui/ozone/platform/wayland/wayland_output.h b/ui/ozone/platform/wayland/wayland_output.h
+index 41a4d3959bb3..15d15672711f 100644
+--- a/ui/ozone/platform/wayland/wayland_output.h
++++ b/ui/ozone/platform/wayland/wayland_output.h
+@@ -36,12 +36,15 @@ class WaylandOutput {
+
+ uint32_t output_id() const { return output_id_; }
+ bool has_output(wl_output* output) const { return output_.get() == output; }
++ int32_t scale_factor() const { return scale_factor_; }
+
+ // Tells if the output has already received physical screen dimensions in the
+ // global compositor space.
+ bool is_ready() const { return !rect_in_physical_pixels_.IsEmpty(); }
+
+ private:
++ static constexpr int32_t kDefaultScaleFactor = 1;
++
+ // Callback functions used for setting geometric properties of the output
+ // and available modes.
+ static void OutputHandleGeometry(void* data,
+@@ -54,7 +57,6 @@ class WaylandOutput {
+ const char* make,
+ const char* model,
+ int32_t output_transform);
+-
+ static void OutputHandleMode(void* data,
+ wl_output* wl_output,
+ uint32_t flags,
+@@ -68,7 +70,7 @@ class WaylandOutput {
+
+ const uint32_t output_id_ = 0;
+ wl::Object<wl_output> output_;
+- float device_scale_factor_;
++ int32_t scale_factor_ = kDefaultScaleFactor;
+ gfx::Rect rect_in_physical_pixels_;
+
+ Delegate* delegate_ = nullptr;
+diff --git a/ui/ozone/platform/wayland/wayland_output_manager.cc b/ui/ozone/platform/wayland/wayland_output_manager.cc
+index 992d0c309333..34e1a9ef3a65 100644
+--- a/ui/ozone/platform/wayland/wayland_output_manager.cc
++++ b/ui/ozone/platform/wayland/wayland_output_manager.cc
+@@ -24,10 +24,7 @@ void WaylandOutputManager::AddWaylandOutput(const uint32_t output_id,
+ // Make sure an output with |output_id| has not been added yet. It's very
+ // unlikely to happen, unless a compositor has a bug in the numeric names
+ // representation of global objects.
+- auto output_it = std::find_if(output_list_.begin(), output_list_.end(),
+- [output_id](const auto& output) {
+- return output->output_id() == output_id;
+- });
++ auto output_it = GetOutputItById(output_id);
+ DCHECK(output_it == output_list_.end());
+ auto wayland_output = std::make_unique<WaylandOutput>(output_id, output);
+ WaylandOutput* wayland_output_ptr = wayland_output.get();
+@@ -42,10 +39,7 @@ void WaylandOutputManager::AddWaylandOutput(const uint32_t output_id,
+ }
+
+ void WaylandOutputManager::RemoveWaylandOutput(const uint32_t output_id) {
+- auto output_it = std::find_if(output_list_.begin(), output_list_.end(),
+- [output_id](const auto& output) {
+- return output->output_id() == output_id;
+- });
++ auto output_it = GetOutputItById(output_id);
+
+ // Check the comment in the WaylandConnetion::GlobalRemove.
+ if (output_it == output_list_.end())
+@@ -87,6 +81,13 @@ uint32_t WaylandOutputManager::GetIdForOutput(wl_output* output) const {
+ return output_it->get()->output_id();
+ }
+
++WaylandOutput* WaylandOutputManager::GetOutput(uint32_t id) const {
++ auto output_it = GetOutputItById(id);
++ // This is unlikely to happen, but better to be explicit here.
++ DCHECK(output_it != output_list_.end());
++ return output_it->get();
++}
++
+ void WaylandOutputManager::OnWaylandOutputAdded(uint32_t output_id) {
+ if (wayland_screen_)
+ wayland_screen_->OnOutputAdded(output_id);
+@@ -105,4 +106,11 @@ void WaylandOutputManager::OnOutputHandleMetrics(uint32_t output_id,
+ scale_factor);
+ }
+
++WaylandOutputManager::OutputList::const_iterator
++WaylandOutputManager::GetOutputItById(uint32_t id) const {
++ return std::find_if(
++ output_list_.begin(), output_list_.end(),
++ [id](const auto& item) { return item->output_id() == id; });
++}
++
+ } // namespace ui
+diff --git a/ui/ozone/platform/wayland/wayland_output_manager.h b/ui/ozone/platform/wayland/wayland_output_manager.h
+index cae7097d4b12..133d7a1256b5 100644
+--- a/ui/ozone/platform/wayland/wayland_output_manager.h
++++ b/ui/ozone/platform/wayland/wayland_output_manager.h
+@@ -39,6 +39,9 @@ class WaylandOutputManager : public WaylandOutput::Delegate {
+ WaylandConnection* connection);
+
+ uint32_t GetIdForOutput(wl_output* output) const;
++ WaylandOutput* GetOutput(uint32_t id) const;
++
++ WaylandScreen* wayland_screen() const { return wayland_screen_.get(); }
+
+ private:
+ void OnWaylandOutputAdded(uint32_t output_id);
+@@ -49,7 +52,11 @@ class WaylandOutputManager : public WaylandOutput::Delegate {
+ const gfx::Rect& new_bounds,
+ int32_t scale_factor) override;
+
+- std::vector<std::unique_ptr<WaylandOutput>> output_list_;
++ using OutputList = std::vector<std::unique_ptr<WaylandOutput>>;
++
++ OutputList::const_iterator GetOutputItById(uint32_t id) const;
++
++ OutputList output_list_;
+
+ // Non-owned wayland screen instance.
+ base::WeakPtr<WaylandScreen> wayland_screen_;
+diff --git a/ui/ozone/platform/wayland/wayland_screen.cc b/ui/ozone/platform/wayland/wayland_screen.cc
+index 19fb4050b2c0..6b77b8758440 100644
+--- a/ui/ozone/platform/wayland/wayland_screen.cc
++++ b/ui/ozone/platform/wayland/wayland_screen.cc
+@@ -23,14 +23,12 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection)
+ WaylandScreen::~WaylandScreen() = default;
+
+ void WaylandScreen::OnOutputAdded(uint32_t output_id) {
+- display::Display new_display(output_id);
+- display_list_.AddDisplay(std::move(new_display),
++ display_list_.AddDisplay(display::Display(output_id),
+ display::DisplayList::Type::NOT_PRIMARY);
+ }
+
+ void WaylandScreen::OnOutputRemoved(uint32_t output_id) {
+- display::Display primary_display = GetPrimaryDisplay();
+- if (primary_display.id() == output_id) {
++ if (output_id == GetPrimaryDisplay().id()) {
+ // First, set a new primary display as required by the |display_list_|. It's
+ // safe to set any of the displays to be a primary one. Once the output is
+ // completely removed, Wayland updates geometry of other displays. And a
+@@ -49,9 +47,9 @@ void WaylandScreen::OnOutputRemoved(uint32_t output_id) {
+
+ void WaylandScreen::OnOutputMetricsChanged(uint32_t output_id,
+ const gfx::Rect& new_bounds,
+- float device_pixel_ratio) {
++ int32_t output_scale) {
+ display::Display changed_display(output_id);
+- changed_display.set_device_scale_factor(device_pixel_ratio);
++ changed_display.SetDeviceScaleFactor(output_scale);
+ changed_display.set_bounds(new_bounds);
+ changed_display.set_work_area(new_bounds);
+
+@@ -81,6 +79,9 @@ void WaylandScreen::OnOutputMetricsChanged(uint32_t output_id,
+ display_list_.UpdateDisplay(
+ changed_display, is_primary ? display::DisplayList::Type::PRIMARY
+ : display::DisplayList::Type::NOT_PRIMARY);
++
++ for (auto* window : connection_->GetWindowsOnDisplay(output_id))
++ window->UpdateBufferScale(true);
+ }
+
+ base::WeakPtr<WaylandScreen> WaylandScreen::GetWeakPtr() {
+@@ -99,13 +100,14 @@ display::Display WaylandScreen::GetPrimaryDisplay() const {
+
+ display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
+ gfx::AcceleratedWidget widget) const {
+- auto* wayland_window = connection_->GetWindow(widget);
++ auto* window = connection_->GetWindow(widget);
+ // A window might be destroyed by this time on shutting down the browser.
+- if (!wayland_window)
++ if (!window)
+ return GetPrimaryDisplay();
+
+- const std::set<uint32_t> entered_outputs_ids =
+- wayland_window->GetEnteredOutputsIds();
++ const auto* parent_window = window->parent_window();
++
++ const std::set<uint32_t> entered_outputs_ids = window->GetEnteredOutputsIds();
+ // 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
+@@ -114,14 +116,19 @@ display::Display WaylandScreen::GetDisplayForAcceleratedWidget(
+ // events immediately, which can result in empty container of entered ids
+ // (check comments in WaylandWindow::RemoveEnteredOutputId). In this case,
+ // it's also safe to return the primary display.
+- if (entered_outputs_ids.empty())
++ // A child window will most probably enter the same display than its parent
++ // so we return the parent's display if there is a parent.
++ if (entered_outputs_ids.empty()) {
++ if (parent_window)
++ return GetDisplayForAcceleratedWidget(parent_window->GetWidget());
+ return GetPrimaryDisplay();
++ }
+
+ DCHECK(!display_list_.displays().empty());
+
+ // A widget can be located on two or more displays. It would be better if the
+- // most in pixels occupied display was returned, but it's impossible to do in
+- // Wayland. Thus, return the one, which was the very first used.
++ // most in DIP occupied display was returned, but it's impossible to do so in
++ // Wayland. Thus, return the one that was used the earliest.
+ for (const auto& display : display_list_.displays()) {
+ if (display.id() == *entered_outputs_ids.begin())
+ return display;
+diff --git a/ui/ozone/platform/wayland/wayland_screen.h b/ui/ozone/platform/wayland/wayland_screen.h
+index 480957bf024d..e1974458e272 100644
+--- a/ui/ozone/platform/wayland/wayland_screen.h
++++ b/ui/ozone/platform/wayland/wayland_screen.h
+@@ -29,7 +29,7 @@ class WaylandScreen : public PlatformScreen {
+ void OnOutputRemoved(uint32_t output_id);
+ void OnOutputMetricsChanged(uint32_t output_id,
+ const gfx::Rect& bounds,
+- float device_pixel_ratio);
++ int32_t output_scale);
+
+ base::WeakPtr<WaylandScreen> GetWeakPtr();
+
+diff --git a/ui/ozone/platform/wayland/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/wayland_screen_unittest.cc
+index bd2a30c58589..7a0d45fa47ea 100644
+--- a/ui/ozone/platform/wayland/wayland_screen_unittest.cc
++++ b/ui/ozone/platform/wayland/wayland_screen_unittest.cc
+@@ -224,9 +224,8 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
+ EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
+ EXPECT_EQ(observer.GetDisplay().bounds(), new_rect);
+
+- const float new_scale_value = 2.0f;
+- wl_output_send_scale(output_->resource(), new_scale_value);
+- wl_output_send_done(output_->resource());
++ const int32_t new_scale_value = 2;
++ output_->SetScale(new_scale_value);
+
+ Sync();
+
+@@ -581,6 +580,23 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
+ EXPECT_EQ(gfx::Point(1912, 1071), platform_screen_->GetCursorScreenPoint());
+ }
+
++// Checks that the surface that backs the window receives new scale of the
++// output that it is in.
++TEST_P(WaylandScreenTest, SetBufferScale) {
++ // Place the window onto the output.
++ 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);
++
++ Sync();
++
++ EXPECT_EQ(window_->buffer_scale(), kNewScale);
++}
++
+ INSTANTIATE_TEST_CASE_P(XdgVersionV5Test,
+ WaylandScreenTest,
+ ::testing::Values(kXdgShellV5));
+diff --git a/ui/ozone/platform/wayland/wayland_test.cc b/ui/ozone/platform/wayland/wayland_test.cc
+index c15bc87efa15..43f4b0dcff12 100644
+--- a/ui/ozone/platform/wayland/wayland_test.cc
++++ b/ui/ozone/platform/wayland/wayland_test.cc
+@@ -6,6 +6,8 @@
+
+ #include "base/run_loop.h"
+ #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
++#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
++#include "ui/ozone/platform/wayland/host/wayland_screen.h"
+ #include "ui/platform_window/platform_window_init_properties.h"
+
+ #if BUILDFLAG(USE_XKBCOMMON)
+@@ -37,6 +39,8 @@ WaylandTest::~WaylandTest() {}
+ void WaylandTest::SetUp() {
+ ASSERT_TRUE(server_.Start(GetParam()));
+ ASSERT_TRUE(connection_->Initialize());
++ screen_ = connection_->wayland_output_manager()->CreateWaylandScreen(
++ connection_.get());
+ EXPECT_CALL(delegate_, OnAcceleratedWidgetAvailable(_))
+ .WillOnce(SaveArg<0>(&widget_));
+ PlatformWindowInitProperties properties;
+diff --git a/ui/ozone/platform/wayland/wayland_test.h b/ui/ozone/platform/wayland/wayland_test.h
+index 7c2109062ca1..580dc57f01cc 100644
+--- a/ui/ozone/platform/wayland/wayland_test.h
++++ b/ui/ozone/platform/wayland/wayland_test.h
+@@ -20,6 +20,8 @@
+
+ namespace ui {
+
++class WaylandScreen;
++
+ const uint32_t kXdgShellV5 = 5;
+ const uint32_t kXdgShellV6 = 6;
+
+@@ -46,6 +48,7 @@ class WaylandTest : public ::testing::TestWithParam<uint32_t> {
+ MockPlatformWindowDelegate delegate_;
+ std::unique_ptr<WaylandConnectionProxy> connection_proxy_;
+ std::unique_ptr<WaylandConnection> connection_;
++ std::unique_ptr<WaylandScreen> screen_;
+ std::unique_ptr<WaylandWindow> window_;
+ gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
+
+diff --git a/ui/ozone/platform/wayland/wayland_touch.cc b/ui/ozone/platform/wayland/wayland_touch.cc
+index d30bc7342d99..c293681a4391 100644
+--- a/ui/ozone/platform/wayland/wayland_touch.cc
++++ b/ui/ozone/platform/wayland/wayland_touch.cc
+@@ -72,7 +72,9 @@ void WaylandTouch::Down(void* data,
+ WaylandTouch* touch = static_cast<WaylandTouch*>(data);
+ DCHECK(touch);
+ touch->connection_->set_serial(serial);
+- WaylandWindow::FromSurface(surface)->set_touch_focus(true);
++ auto* window = WaylandWindow::FromSurface(surface);
++ DCHECK(window);
++ window->set_touch_focus(true);
+
+ // Make sure this touch point wasn't present before.
+ if (touch->current_points_.find(id) != touch->current_points_.end()) {
+diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
+index 7b658951a403..5689ce0e9470 100644
+--- a/ui/ozone/platform/wayland/wayland_window.cc
++++ b/ui/ozone/platform/wayland/wayland_window.cc
+@@ -123,7 +123,11 @@ WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) {
+ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ DCHECK(xdg_shell_objects_factory_);
+
+- bounds_ = properties.bounds;
++ // Properties contain DIP bounds but the buffer scale is initially 1 so it's
++ // OK to assign. The bounds will be recalculated when the buffer scale
++ // changes.
++ DCHECK_EQ(buffer_scale_, 1);
++ bounds_px_ = properties.bounds;
+ opacity_ = properties.opacity;
+
+ surface_.reset(wl_compositor_create_surface(connection_->compositor()));
+@@ -131,16 +135,21 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ LOG(ERROR) << "Failed to create wl_surface";
+ return false;
+ }
+- wl_surface_set_user_data(surface_.get(), this);
++
++ wl_surface_set_user_data(surface(), this);
++
+ AddSurfaceListener();
+ MaybeUpdateOpaqueRegion();
+
+- ui::PlatformWindowType ui_window_type = properties.type;
+- switch (ui_window_type) {
++ switch (properties.type) {
+ case ui::PlatformWindowType::kMenu:
+ case ui::PlatformWindowType::kPopup:
+ parent_window_ = GetParentWindow(properties.parent_widget);
+
++ // Popups need to know their scale earlier to position themselves.
++ DCHECK(parent_window_);
++ SetBufferScale(parent_window_->buffer_scale_, false);
++
+ // TODO(msisov, jkim): Handle notification windows, which are marked
+ // as popup windows as well. Those are the windows that do not have
+ // parents and pop up when the browser receives a notification.
+@@ -161,9 +170,34 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ delegate_->OnAcceleratedWidgetAvailable(GetWidget());
+
++ // Will do nothing for popups because they have got their scale above.
++ UpdateBufferScale(false);
++
+ return true;
+ }
+
++void WaylandWindow::UpdateBufferScale(bool update_bounds) {
++ DCHECK(connection_->wayland_output_manager());
++ const auto* screen = connection_->wayland_output_manager()->wayland_screen();
++ DCHECK(screen);
++ const auto widget = GetWidget();
++
++ 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();
++ } else {
++ // This is the main window that is fully set up so we can ask which display
++ // we are at currently.
++ current_display_ = screen->GetDisplayForAcceleratedWidget(widget);
++ new_scale = connection_->wayland_output_manager()
++ ->GetOutput(current_display_.id())
++ ->scale_factor();
++ }
++ SetBufferScale(new_scale, update_bounds);
++}
++
+ gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
+ if (!surface_)
+ return gfx::kNullAcceleratedWidget;
+@@ -175,7 +209,7 @@ std::set<uint32_t> WaylandWindow::GetEnteredOutputsIds() const {
+ }
+
+ void WaylandWindow::CreateXdgPopup() {
+- if (bounds_.IsEmpty())
++ if (bounds_px_.IsEmpty())
+ return;
+
+ // TODO(jkim): Consider how to support DropArrow window on tabstrip.
+@@ -193,11 +227,11 @@ void WaylandWindow::CreateXdgPopup() {
+
+ DCHECK(parent_window_ && !xdg_popup_);
+
+- auto bounds = AdjustPopupWindowPosition();
++ auto bounds_px = AdjustPopupWindowPosition();
+
+ xdg_popup_ = xdg_shell_objects_factory_->CreateXDGPopup(connection_, this);
+- if (!xdg_popup_ ||
+- !xdg_popup_->Initialize(connection_, surface(), parent_window_, bounds)) {
++ if (!xdg_popup_ || !xdg_popup_->Initialize(connection_, surface(),
++ parent_window_, bounds_px)) {
+ CHECK(false) << "Failed to create xdg_popup";
+ }
+
+@@ -234,22 +268,24 @@ void WaylandWindow::CreateAndShowTooltipSubSurface() {
+ }
+
+ DCHECK(tooltip_subsurface_);
+- wl_subsurface_set_position(tooltip_subsurface_.get(), bounds_.x(),
+- bounds_.y());
++ // Convert position to DIP.
++ wl_subsurface_set_position(tooltip_subsurface_.get(),
++ bounds_px_.x() / buffer_scale_,
++ bounds_px_.y() / buffer_scale_);
+ wl_subsurface_set_desync(tooltip_subsurface_.get());
+ wl_surface_commit(parent_window_->surface());
+ connection_->ScheduleFlush();
+ }
+
+ void WaylandWindow::ApplyPendingBounds() {
+- if (pending_bounds_.IsEmpty())
++ if (pending_bounds_dip_.IsEmpty())
+ return;
+ DCHECK(xdg_surface_);
+
+- SetBounds(pending_bounds_);
+- xdg_surface_->SetWindowGeometry(bounds_);
++ SetBoundsDip(pending_bounds_dip_);
++ xdg_surface_->SetWindowGeometry(pending_bounds_dip_);
+ xdg_surface_->AckConfigure();
+- pending_bounds_ = gfx::Rect();
++ pending_bounds_dip_ = gfx::Rect();
+ connection_->ScheduleFlush();
+ }
+
+@@ -289,9 +325,16 @@ void WaylandWindow::Show() {
+ }
+
+ if (!xdg_popup_) {
++ // When showing a sub-menu after it has been previously shown and hidden,
++ // Wayland sends SetBounds prior to Show, and |bounds_px| takes the pixel
++ // 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_);
+ CreateXdgPopup();
+ connection_->ScheduleFlush();
+ }
++ UpdateBufferScale(false);
+ }
+
+ void WaylandWindow::Hide() {
+@@ -321,20 +364,26 @@ void WaylandWindow::Close() {
+
+ void WaylandWindow::PrepareForShutdown() {}
+
+-void WaylandWindow::SetBounds(const gfx::Rect& bounds) {
+- if (bounds == bounds_)
++void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
++ // TODO(adunaev): figure out if this return is legitimate, see
++ // https://crbug.com/958314
++ // The X11 implementation says that even if the pixel bounds
++ // didn't change, we still need to forward this call to the delegate, and that
++ // the device scale factor may have changed which effectively changes the
++ // bounds. Perhaps we need to do the same here.
++ if (bounds_px_ == bounds_px)
+ return;
+- bounds_ = bounds;
++ bounds_px_ = bounds_px;
+
+ // Opaque region is based on the size of the window. Thus, update the region
+ // on each update.
+ MaybeUpdateOpaqueRegion();
+
+- delegate_->OnBoundsChanged(bounds);
++ delegate_->OnBoundsChanged(bounds_px_);
+ }
+
+ gfx::Rect WaylandWindow::GetBounds() {
+- return bounds_;
++ return bounds_px_;
+ }
+
+ void WaylandWindow::SetTitle(const base::string16& title) {
+@@ -461,12 +510,12 @@ PlatformImeController* WaylandWindow::GetPlatformImeController() {
+ return nullptr;
+ }
+
+-void WaylandWindow::SetRestoredBoundsInPixels(const gfx::Rect& bounds) {
+- restored_bounds_ = bounds;
++void WaylandWindow::SetRestoredBoundsInPixels(const gfx::Rect& bounds_px) {
++ restored_bounds_px_ = bounds_px;
+ }
+
+ gfx::Rect WaylandWindow::GetRestoredBoundsInPixels() const {
+- return restored_bounds_;
++ return restored_bounds_px_;
+ }
+
+ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
+@@ -497,6 +546,10 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
+ Event* event = static_cast<Event*>(native_event);
+
+ if (event->IsLocatedEvent()) {
++ // Located events come in output scale and need to be translated to
++ // physical pixels.
++ event->AsLocatedEvent()->set_location_f(gfx::ScalePoint(
++ event->AsLocatedEvent()->location_f(), buffer_scale_, buffer_scale_));
+ auto copied_event = Event::Clone(*event);
+ UpdateCursorPositionFromEvent(std::move(copied_event));
+ }
+@@ -578,11 +631,12 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
+ // explicitly set the bounds to the current desired ones or the previous
+ // bounds.
+ if (width > 1 && height > 1) {
+- pending_bounds_ = gfx::Rect(0, 0, width, height);
++ pending_bounds_dip_ = gfx::Rect(0, 0, width, height);
+ } else if (is_normal) {
+- pending_bounds_.set_size(restored_bounds_.IsEmpty()
+- ? GetBounds().size()
+- : restored_bounds_.size());
++ pending_bounds_dip_.set_size(gfx::ScaleToRoundedSize(
++ restored_bounds_px_.IsEmpty() ? GetBounds().size()
++ : restored_bounds_px_.size(),
++ 1.0 / buffer_scale_));
+ }
+
+ if (state_changed) {
+@@ -594,8 +648,8 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
+ if (is_normal) {
+ SetRestoredBoundsInPixels({});
+ } else if (old_state == PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL ||
+- restored_bounds_.IsEmpty()) {
+- SetRestoredBoundsInPixels(bounds_);
++ restored_bounds_px_.IsEmpty()) {
++ SetRestoredBoundsInPixels(bounds_px_);
+ }
+
+ delegate_->OnWindowStateChanged(state_);
+@@ -604,12 +658,18 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
+ if (did_active_change)
+ delegate_->OnActivationChanged(is_active_);
+
++ UpdateBufferScale(true);
++
+ MaybeTriggerPendingStateChange();
+ }
+
+-void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds) {
++void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
+ DCHECK(xdg_popup());
+- gfx::Rect new_bounds = bounds;
++ DCHECK(parent_window_);
++
++ SetBufferScale(parent_window_->buffer_scale_, true);
++
++ gfx::Rect new_bounds_dip = bounds_dip;
+
+ // It's not enough to just set new bounds. If it is a menu window, whose
+ // parent is a top level window aka browser window, it can be flipped
+@@ -627,10 +687,10 @@ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds) {
+ gfx::Rect parent_bounds = parent_window_->GetBounds();
+ // The menu window is flipped along y-axis and have x,-y origin. Shift the
+ // parent top level window instead.
+- if (new_bounds.y() < 0) {
++ if (new_bounds_dip.y() < 0) {
+ // Move parent bounds along y-axis.
+- parent_bounds.set_y(-(new_bounds.y()));
+- new_bounds.set_y(0);
++ parent_bounds.set_y(-(new_bounds_dip.y() * buffer_scale_));
++ new_bounds_dip.set_y(0);
+ } else {
+ // If the menu window is located at correct origin from the browser point
+ // of view, return the top level window back to 0,0.
+@@ -642,11 +702,16 @@ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds) {
+ // Thus, the location must be translated to be relative to the top level
+ // window, which automatically becomes the same as relative to an origin of
+ // a display.
+- new_bounds = TranslateBoundsToTopLevelCoordinates(
+- new_bounds, parent_window_->GetBounds());
+- DCHECK(new_bounds.y() >= 0);
++ new_bounds_dip = gfx::ScaleToRoundedRect(
++ TranslateBoundsToTopLevelCoordinates(
++ gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_),
++ parent_window_->GetBounds()),
++ 1.0 / buffer_scale_);
++ DCHECK(new_bounds_dip.y() >= 0);
+ }
+- SetBounds(new_bounds);
++
++ // Finally, the menu bounds must be converted to physical pixels.
++ SetBoundsDip(new_bounds_dip);
+ }
+
+ void WaylandWindow::OnCloseRequest() {
+@@ -694,6 +759,26 @@ void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {
+ connection_->ResetPointerFlags();
+ }
+
++void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
++ SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_));
++}
++
++void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) {
++ DCHECK_GT(new_scale, 0);
++
++ if (new_scale == buffer_scale_)
++ return;
++
++ auto old_scale = buffer_scale_;
++ buffer_scale_ = new_scale;
++ if (update_bounds)
++ SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / old_scale));
++
++ DCHECK(surface());
++ wl_surface_set_buffer_scale(surface(), buffer_scale_);
++ connection_->ScheduleFlush();
++}
++
+ bool WaylandWindow::IsMinimized() const {
+ return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
+ }
+@@ -749,14 +834,28 @@ void WaylandWindow::AddSurfaceListener() {
+ }
+
+ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
++ // Wayland does weird things for popups so instead of tracking outputs that
++ // we entered or left, we take that from the parent window and ignore this
++ // event.
++ if (xdg_popup())
++ return;
++
+ const uint32_t entered_output_id =
+ connection_->wayland_output_manager()->GetIdForOutput(output);
+ DCHECK_NE(entered_output_id, 0u);
+ auto result = entered_outputs_ids_.insert(entered_output_id);
+ DCHECK(result.first != entered_outputs_ids_.end());
++
++ UpdateBufferScale(true);
+ }
+
+ void WaylandWindow::RemoveEnteredOutputId(struct wl_output* output) {
++ // Wayland does weird things for popups so instead of tracking outputs that
++ // we entered or left, we take that from the parent window and ignore this
++ // event.
++ if (xdg_popup())
++ return;
++
+ const uint32_t left_output_id =
+ connection_->wayland_output_manager()->GetIdForOutput(output);
+ auto entered_output_id_it = entered_outputs_ids_.find(left_output_id);
+@@ -766,8 +865,11 @@ void WaylandWindow::RemoveEnteredOutputId(struct wl_output* output) {
+ // displays in a single output mode results in leave events, but the surface
+ // might not have received enter event before. Thus, remove the id of left
+ // output only if it was stored before.
+- if (entered_output_id_it != entered_outputs_ids_.end())
++ if (entered_output_id_it != entered_outputs_ids_.end()) {
+ entered_outputs_ids_.erase(entered_output_id_it);
++ }
++
++ UpdateBufferScale(true);
+ }
+
+ void WaylandWindow::UpdateCursorPositionFromEvent(
+@@ -816,11 +918,15 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
+ ? parent_window_->parent_window_
+ : parent_window_;
+ DCHECK(parent_window);
++ DCHECK(buffer_scale_ == parent_window->buffer_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 = parent_window_->GetBounds();
++ const gfx::Rect parent_bounds_px =
++ gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / buffer_scale_);
++
+ gfx::Rect new_bounds =
+- TranslateBoundsToParentCoordinates(bounds_, parent_bounds);
++ TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_px);
+
+ // 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
+@@ -844,7 +950,8 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
+ // 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.width() - (new_bounds.width() + new_bounds.x());
++ int new_x =
++ parent_bounds_px.width() - (new_bounds.width() + new_bounds.x());
+ new_bounds.set_x(new_x);
+ }
+ }
+@@ -861,7 +968,7 @@ void WaylandWindow::MaybeUpdateOpaqueRegion() {
+
+ wl::Object<wl_region> region(
+ wl_compositor_create_region(connection_->compositor()));
+- wl_region_add(region.get(), 0, 0, bounds_.width(), bounds_.height());
++ wl_region_add(region.get(), 0, 0, bounds_px_.width(), bounds_px_.height());
+ wl_surface_set_opaque_region(surface(), region.get());
+
+ connection_->ScheduleFlush();
+diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h
+index 4c7271d19d94..25632cbd5f31 100644
+--- a/ui/ozone/platform/wayland/wayland_window.h
++++ b/ui/ozone/platform/wayland/wayland_window.h
+@@ -10,6 +10,7 @@
+
+ #include "base/callback.h"
+ #include "base/memory/ref_counted.h"
++#include "ui/display/display.h"
+ #include "ui/events/platform/platform_event_dispatcher.h"
+ #include "ui/gfx/geometry/rect.h"
+ #include "ui/gfx/native_widget_types.h"
+@@ -50,10 +51,19 @@ class WaylandWindow : public PlatformWindow,
+
+ bool Initialize(PlatformWindowInitProperties properties);
+
++ // Updates the surface buffer scale of the window. Top level windows take
++ // scale according to 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).
++ void UpdateBufferScale(bool update_bounds);
++
+ wl_surface* surface() const { return surface_.get(); }
+ XDGSurfaceWrapper* xdg_surface() const { return xdg_surface_.get(); }
+ XDGPopupWrapper* xdg_popup() const { return xdg_popup_.get(); }
+
++ WaylandWindow* parent_window() const { return parent_window_; }
++
+ gfx::AcceleratedWidget GetWidget() const;
+
+ // Returns the list of wl_outputs aka displays, which this window occupies.
+@@ -88,6 +98,8 @@ class WaylandWindow : public PlatformWindow,
+ void set_has_implicit_grab(bool value) { has_implicit_grab_ = value; }
+ bool has_implicit_grab() const { return has_implicit_grab_; }
+
++ int32_t buffer_scale() const { return buffer_scale_; }
++
+ bool is_active() const { return is_active_; }
+
+ // WmMoveResizeHandler
+@@ -128,6 +140,10 @@ class WaylandWindow : public PlatformWindow,
+ bool CanDispatchEvent(const PlatformEvent& event) override;
+ uint32_t DispatchEvent(const PlatformEvent& event) override;
+
++ // Handles the configuration events coming from the surface (see
++ // |XDGSurfaceWrapperV5::Configure| and
++ // |XDGSurfaceWrapperV6::ConfigureTopLevel|. The width and height come in
++ // DIP of the output that the surface is currently bound to.
+ void HandleSurfaceConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+@@ -146,6 +162,9 @@ class WaylandWindow : public PlatformWindow,
+ void OnDragSessionClose(uint32_t dnd_action);
+
+ private:
++ void SetBoundsDip(const gfx::Rect& bounds_dip);
++ void SetBufferScale(int32_t scale, bool update_bounds);
++
+ bool IsMinimized() const;
+ bool IsMaximized() const;
+ bool IsFullscreen() const;
+@@ -213,14 +232,28 @@ class WaylandWindow : public PlatformWindow,
+
+ base::OnceCallback<void(int)> drag_closed_callback_;
+
+- gfx::Rect bounds_;
+- gfx::Rect pending_bounds_;
++ // These bounds attributes below have suffices that indicate uints used.
++ // Values measured in physical pixels are used in calls to PlatformWindow
++ // and PlatformWindowDelegate that work with physical pixels.
++ //
++ // Current bounds of the window.
++ gfx::Rect bounds_px_;
++ // Bounds that will be applied when the window state is finalized. The window
++ // may get several configuration events that update the pending bounds, and
++ // only upon finalizing the state is the latest value stored as the current
++ // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the
++ // handler that receives DIP.
++ gfx::Rect pending_bounds_dip_;
+ // The bounds of the window before it went maximized or fullscreen.
+- gfx::Rect restored_bounds_;
++ gfx::Rect restored_bounds_px_;
++
++ display::Display current_display_;
++
+ bool has_pointer_focus_ = false;
+ bool has_keyboard_focus_ = false;
+ bool has_touch_focus_ = false;
+ bool has_implicit_grab_ = false;
++ int32_t buffer_scale_ = 1;
+
+ // Stores current states of the window.
+ ui::PlatformWindowState state_;
+@@ -236,7 +269,14 @@ class WaylandWindow : public PlatformWindow,
+
+ bool is_tooltip_ = false;
+
+- // Stores the list of entered outputs that the window is currently in.
++ // For top level window, stores the list of entered outputs that the window
++ // is currently in.
++ //
++ // For a popup, not used. Wayland 'repositions' sub-menus to wrong outputs
++ // (by sending them leave and enter events) when sub-menus are hidden and
++ // shown again so their list of entered outputs becomes meaningless after
++ // they have been hidden at least once. To determine which output the popup
++ // belongs to, refer to its parent.
+ std::set<uint32_t> entered_outputs_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
+diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
+index 38b274f5d7bd..fce77bb6a99c 100644
+--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
++++ b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
+@@ -165,6 +165,8 @@ gfx::Rect GetAnchorRect(MenuType menu_type,
+ break;
+ }
+
++ if (anchor_rect.width() == 0)
++ anchor_rect.set_width(1);
+ return anchor_rect;
+ }
+
+@@ -255,8 +257,10 @@ zxdg_positioner_v6* XDGPopupWrapperV6::CreatePositioner(
+ menu_type = MenuType::TYPE_3DOT_PARENT_MENU;
+
+ // Place anchor to the end of the possible position.
+- gfx::Rect anchor_rect =
+- GetAnchorRect(menu_type, bounds, parent_window->GetBounds());
++ gfx::Rect anchor_rect = GetAnchorRect(
++ menu_type, bounds,
++ gfx::ScaleToRoundedRect(parent_window->GetBounds(),
++ 1.0 / parent_window->buffer_scale()));
+
+ zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(),
+ anchor_rect.y(), anchor_rect.width(),
+@@ -282,11 +286,10 @@ void XDGPopupWrapperV6::Configure(void* data,
+ // Wayland requires doing so in respect to parent window's origin. To properly
+ // place windows, the bounds are translated and adjusted according to the
+ // Wayland compositor needs during WaylandWindow::CreateXdgPopup call.
+- gfx::Rect new_bounds(x, y, width, height);
+ WaylandWindow* window =
+ static_cast<XDGPopupWrapperV6*>(data)->wayland_window_;
+ DCHECK(window);
+- window->HandlePopupConfigure(new_bounds);
++ window->HandlePopupConfigure({x, y, width, height});
+ }
+
+ // static
+diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
+index 0796aec67623..e9b1c39edb27 100644
+--- a/ui/views/controls/menu/submenu_view.cc
++++ b/ui/views/controls/menu/submenu_view.cc
+@@ -167,16 +167,16 @@ gfx::Size SubmenuView::CalculatePreferredSize() const {
+ const MenuItemView* menu = static_cast<const MenuItemView*>(child);
+ const MenuItemView::MenuItemDimensions& dimensions =
+ menu->GetDimensions();
+- max_simple_width = std::max(
+- max_simple_width, dimensions.standard_width);
++ max_simple_width = std::max(max_simple_width, dimensions.standard_width);
+ max_minor_text_width_ =
+ std::max(max_minor_text_width_, dimensions.minor_text_width);
+- max_complex_width = std::max(max_complex_width,
+- dimensions.standard_width + dimensions.children_width);
++ max_complex_width =
++ std::max(max_complex_width,
++ dimensions.standard_width + dimensions.children_width);
+ touchable_minimum_width = dimensions.standard_width;
+ } else {
+- max_complex_width = std::max(max_complex_width,
+- child->GetPreferredSize().width());
++ max_complex_width =
++ std::max(max_complex_width, child->GetPreferredSize().width());
+ }
+ }
+ if (max_minor_text_width_ > 0)
+@@ -184,10 +184,10 @@ gfx::Size SubmenuView::CalculatePreferredSize() const {
+
+ // Finish calculating our optimum width.
+ gfx::Insets insets = GetInsets();
+- int width = std::max(max_complex_width,
+- std::max(max_simple_width + max_minor_text_width_ +
+- insets.width(),
+- minimum_preferred_width_ - 2 * insets.width()));
++ int width = std::max(
++ max_complex_width,
++ std::max(max_simple_width + max_minor_text_width_ + insets.width(),
++ minimum_preferred_width_ - 2 * insets.width()));
+
+ if (GetMenuItem()->GetMenuController() &&
+ GetMenuItem()->GetMenuController()->use_touchable_layout()) {
+@@ -318,8 +318,8 @@ bool SubmenuView::OnMouseWheel(const ui::MouseWheelEvent& e) {
+ if (GetMenuItemAt(first_vis_index)->y() == vis_bounds.y())
+ first_vis_index++;
+ }
+- ScrollRectToVisible(gfx::Rect(gfx::Point(0, scroll_target),
+- vis_bounds.size()));
++ ScrollRectToVisible(
++ gfx::Rect(gfx::Point(0, scroll_target), vis_bounds.size()));
+ vis_bounds = GetVisibleBounds();
+ }
+
+diff --git a/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+index 6dd57cd74545..be4ea972005a 100644
+--- a/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
++++ b/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+@@ -41,7 +41,7 @@ void DesktopScreenOzone::OnHostDisplaysReady(
+ display::Display display(display_snapshot->display_id());
+ display.set_bounds(gfx::Rect(scaled_size));
+ display.set_work_area(display.bounds());
+- display.set_device_scale_factor(device_scale_factor);
++ display.SetDeviceScaleFactor(device_scale_factor);
+
+ ProcessDisplayChanged(display, true /* is_primary */);
+ }
+diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+index 86834c46d1be..92ee9f82f46f 100644
+--- a/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
++++ b/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+@@ -468,25 +468,25 @@ TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) {
+ NotifyDisplaysChanged(displays);
+ ResetDisplayChanges();
+
+- displays[0].set_device_scale_factor(2.5f);
++ displays[0].SetDeviceScaleFactor(2.5f);
+ NotifyDisplaysChanged(displays);
+ EXPECT_EQ(1u, changed_display_.size());
+ EXPECT_EQ(2.5f, gfx::GetFontRenderParamsDeviceScaleFactor());
+
+- displays[1].set_device_scale_factor(2.5f);
++ displays[1].SetDeviceScaleFactor(2.5f);
+ NotifyDisplaysChanged(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+- displays[0].set_device_scale_factor(2.5f);
++ displays[0].SetDeviceScaleFactor(2.5f);
+ NotifyDisplaysChanged(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+- displays[1].set_device_scale_factor(2.5f);
++ displays[1].SetDeviceScaleFactor(2.5f);
+ NotifyDisplaysChanged(displays);
+ EXPECT_EQ(2u, changed_display_.size());
+
+- displays[0].set_device_scale_factor(1.f);
+- displays[1].set_device_scale_factor(1.f);
++ displays[0].SetDeviceScaleFactor(1.f);
++ displays[1].SetDeviceScaleFactor(1.f);
+ NotifyDisplaysChanged(displays);
+ EXPECT_EQ(4u, changed_display_.size());
+ EXPECT_EQ(1.f, gfx::GetFontRenderParamsDeviceScaleFactor());