summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Playfair Cal2020-01-12 01:15:04 +1100
committerDaniel Playfair Cal2020-01-12 01:17:55 +1100
commit849fc03d9e5cf971762a366fcda21b8fba156864 (patch)
tree44b4fb65c1d3f4d22afcc288accbaa4810ec48a0
parentb26c568927542ce7d5084c654382c51fea251f75 (diff)
downloadaur-849fc03d9e5cf971762a366fcda21b8fba156864.tar.gz
80.0.3987.42
-rw-r--r--.SRCINFO41
-rw-r--r--0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch240
-rw-r--r--0001-Refactor-bookmark-GUID-matching-logic.patch329
-rw-r--r--0001-cros-search-service-Include-cmath-for-std-pow.patch38
-rw-r--r--0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch173
-rw-r--r--0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch788
-rw-r--r--0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch646
-rw-r--r--0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch137
-rw-r--r--0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch33
-rw-r--r--0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch1424
-rw-r--r--0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch1043
-rw-r--r--0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch347
-rw-r--r--0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch1148
-rw-r--r--0009-ozone-wayland-window-state-change-must-be-synchronou.patch665
-rw-r--r--PKGBUILD37
-rw-r--r--chromium-system-hb.patch19
-rw-r--r--icu65.patch64
-rw-r--r--include-algorithm-to-use-std-lower_bound.patch49
-rw-r--r--launch_manager.h-uses-std-vector.patch36
19 files changed, 6877 insertions, 380 deletions
diff --git a/.SRCINFO b/.SRCINFO
index cea3486badf4..47a59635d918 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,6 +1,6 @@
pkgbase = chromium-ozone
pkgdesc = Chromium built with patches for wayland support via Ozone
- pkgver = 79.0.3945.117
+ pkgver = 80.0.3987.42
pkgrel = 1
url = https://www.chromium.org/Home
install = chromium.install
@@ -35,7 +35,6 @@ pkgbase = chromium-ozone
depends = desktop-file-utils
depends = hicolor-icon-theme
depends = icu
- depends = libxml2
depends = fontconfig
depends = harfbuzz
depends = libjpeg
@@ -56,30 +55,42 @@ pkgbase = chromium-ozone
conflicts = chromium
options = debug
options = !strip
- source = https://commondatastorage.googleapis.com/chromium-browser-official/chromium-79.0.3945.117.tar.xz
+ source = https://commondatastorage.googleapis.com/chromium-browser-official/chromium-80.0.3987.42.tar.xz
source = chromium-launcher-6.tar.gz::https://github.com/foutrelis/chromium-launcher/archive/v6.tar.gz
- source = launch_manager.h-uses-std-vector.patch
- source = include-algorithm-to-use-std-lower_bound.patch
source = 0001-Add-missing-algorithm-header-in-bitmap_cursor_factor.patch
- source = 0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch
- source = icu65.patch
+ source = 0001-cros-search-service-Include-cmath-for-std-pow.patch
+ source = 0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch
+ source = 0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch
+ source = 0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch
+ source = 0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch
+ source = 0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch
+ source = 0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch
+ source = 0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch
+ source = 0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch
+ source = 0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch
+ source = 0009-ozone-wayland-window-state-change-must-be-synchronou.patch
source = chromium-system-icu.patch
source = chromium-system-zlib.patch
- source = chromium-system-hb.patch
source = fix-spammy-unique-font-matching-log.patch
source = chromium-widevine.patch
source = chromium-skia-harmony.patch
- sha256sums = 4d960e8bd790cc1c8e7f0632790424957c4996a8a91b9d899eb572acec854ef1
+ sha256sums = 160c02ed00d45a074246c8984144a35b092102e9b9a31e2bc9c2dad49f297945
sha256sums = 04917e3cd4307d8e31bfb0027a5dce6d086edb10ff8a716024fbb8bb0c7dccf1
- sha256sums = bd0fae907c451252e91c4cbf1ad301716bc9f8a4644ecc60e9590a64197477d3
- sha256sums = 1f906676563e866e2b59719679e76e0b2f7f082f48ef0593e86da0351a586c73
sha256sums = 716c28bed9f6e9c32e3617e125c1b04806700aef691763923cd4ed14b8d23279
- sha256sums = 9e9e5c66d4555c787736c5d5d5fcef8b5e14d913b138041c9c90d1976ee46845
- sha256sums = 1de9bdbfed482295dda45c7d4e323cee55a34e42f66b892da1c1a778682b7a41
+ sha256sums = 4c892f046ab10df609aa39d9985248d368c77306783a64d335ff713dabad60b0
+ sha256sums = a44ed59db5258221ee187dc2501040e5ebfc5c1353ac98d4313ac6a12ae32d1f
+ sha256sums = 01f7a6e098e105949ec6267d7293eef4b79a4f9d20ecbf3b53f5944cf64674db
+ sha256sums = 2f9fc85844350e86e8b8389a2b4d84cf7a49ae582ddb66d3248b308b46ed33a2
+ sha256sums = d05d9dbb9ac53614365182cb04d473e906e20cba72225122b4ae1c03e7e19395
+ sha256sums = 8577707001330b4da42828708da8cf85d122127c3c84b6531e60dcbe9c04c587
+ sha256sums = 3909026200bb2b7d017da5a638bfa5785586a20445e24da846fe97878204a1c5
+ sha256sums = 88153c36bc639bee8959721b5140b325178fe548e3d5bd5e3b4b57129a7a9a0e
+ sha256sums = ca681e32a34fea040357554bdded0aed82d61c10f07a2da5f23317f45f3295cf
+ sha256sums = 38a951ffe9a031241179163a71391c4aabbd31432c4fb6cbc35800b632bce747
+ sha256sums = 7566c0690786bd2092736f6a7e6ad4c4304515e8a65814574d16f065c8a7d8f4
sha256sums = e73cc2ee8d3ea35aab18c478d76fdfc68ca4463e1e10306fa1e738c03b3f26b5
sha256sums = eb67eda4945a89c3b90473fa8dc20637511ca4dcb58879a8ed6bf403700ca9c8
- sha256sums = c0ad3fa426cb8fc1a237ddc6309a6b2dd4055bbe41dd07f50071ee61f969b81a
- sha256sums = 6fbffe59b886195b92c9a55137cef83021c16593f49714acb20023633e3ebb19
+ sha256sums = 71e63e2f4db01f7beecbbdc98f78134288429825dbef3412779506e51277fb80
sha256sums = 709e2fddba3c1f2ed4deb3a239fc0479bfa50c46e054e7f32db4fb1365fed070
sha256sums = 771292942c0901092a402cc60ee883877a99fb804cb54d568c8c6c94565a48e1
diff --git a/0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch b/0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch
new file mode 100644
index 000000000000..ba57aca99be3
--- /dev/null
+++ b/0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch
@@ -0,0 +1,240 @@
+From cdf3e81ff49b200213d67d65558f2919222b60ab Mon Sep 17 00:00:00 2001
+From: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Date: Mon, 16 Dec 2019 11:39:11 +0000
+Subject: [PATCH] BookmarkModelMerger: Move RemoteTreeNode declaration to
+ header.
+
+This fixes the build with libstdc++ after commit 8f5dad93e58 ("Fix CHECK
+failure due to untracked local nodes"):
+
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/stl_pair.h:215:11: error: field has incomplete type 'sync_bookmarks::BookmarkModelMerger::RemoteTreeNode'
+ _T2 second; /// @c second is a copy of the second object
+ ^
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/ext/aligned_buffer.h:91:28: note: in instantiation of template class 'std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>' requested here
+ : std::aligned_storage<sizeof(_Tp), __alignof__(_Tp)>
+ ^
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable_policy.h:233:43: note: in instantiation of template class '__gnu_cxx::__aligned_buffer<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> >' requested here
+ __gnu_cxx::__aligned_buffer<_Value> _M_storage;
+ ^
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable_policy.h:264:39: note: in instantiation of template class 'std::__detail::_Hash_node_value_base<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> >' requested here
+ struct _Hash_node<_Value, true> : _Hash_node_value_base<_Value>
+ ^
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable_policy.h:2028:25: note: in instantiation of template class 'std::__detail::_Hash_node<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>, true>' requested here
+ rebind_traits<typename __node_type::value_type>;
+ ^
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/hashtable.h:184:15: note: in instantiation of template class 'std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>, true> > >
+' requested here
+ private __detail::_Hashtable_alloc<
+ ^
+/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/bits/unordered_map.h:105:18: note: in instantiation of template class 'std::_Hashtable<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode>, std::allocator<std::pair<con
+st std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char> >, std::hash<std::string>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__deta
+il::_Hashtable_traits<true, false, true> >' requested here
+ _Hashtable _M_h;
+ ^
+../../components/sync_bookmarks/bookmark_model_merger.h:146:22: note: in instantiation of template class 'std::unordered_map<std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode, std::hash<std::string>, std::equal_to<std::__cxx11::basic_string<char> >, std::allocator<std::pair<con
+st std::__cxx11::basic_string<char>, sync_bookmarks::BookmarkModelMerger::RemoteTreeNode> > >' requested here
+ const RemoteForest remote_forest_;
+ ^
+../../components/sync_bookmarks/bookmark_model_merger.h:53:9: note: forward declaration of 'sync_bookmarks::BookmarkModelMerger::RemoteTreeNode'
+ class RemoteTreeNode;
+ ^
+
+Essentially, the problem is that libstdc++'s std::unordered_map<T, U>
+implementation requires both T and U to be fully declared. I raised the
+problem in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92770, and GCC's
+position is that we are relying on undefined behavior according to the C++
+standard (https://eel.is/c++draft/requirements#res.on.functions-2.5).
+
+Bug: 957519
+Change-Id: Ife7e435e516932a795bfbe05b2c910c3272878f0
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1960156
+Commit-Queue: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Reviewed-by: Mikel Astiz <mastiz@chromium.org>
+Auto-Submit: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Cr-Commit-Position: refs/heads/master@{#725070}
+---
+ .../sync_bookmarks/bookmark_model_merger.cc | 89 +++++++------------
+ .../sync_bookmarks/bookmark_model_merger.h | 48 +++++++++-
+ 2 files changed, 80 insertions(+), 57 deletions(-)
+
+diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc
+index eae153eff953..579848ee664e 100644
+--- a/components/sync_bookmarks/bookmark_model_merger.cc
++++ b/components/sync_bookmarks/bookmark_model_merger.cc
+@@ -5,7 +5,6 @@
+ #include "components/sync_bookmarks/bookmark_model_merger.h"
+
+ #include <algorithm>
+-#include <memory>
+ #include <set>
+ #include <string>
+ #include <utility>
+@@ -205,66 +204,44 @@ UpdatesPerParentId GroupValidUpdatesByParentId(
+
+ } // namespace
+
+-class BookmarkModelMerger::RemoteTreeNode final {
+- public:
+- // Constructs a tree given |update| as root and recursively all descendants by
+- // traversing |*updates_per_parent_id|. |update| and |updates_per_parent_id|
+- // must not be null. All updates |*updates_per_parent_id| must represent valid
+- // updates. Updates corresponding from descendant nodes are moved away from
+- // |*updates_per_parent_id|.
+- static RemoteTreeNode BuildTree(
+- std::unique_ptr<syncer::UpdateResponseData> update,
+- UpdatesPerParentId* updates_per_parent_id);
+-
+- ~RemoteTreeNode() = default;
+-
+- // Allow moves, useful during construction.
+- RemoteTreeNode(RemoteTreeNode&&) = default;
+- RemoteTreeNode& operator=(RemoteTreeNode&&) = default;
+-
+- const syncer::EntityData& entity() const { return *update_->entity; }
+- int64_t response_version() const { return update_->response_version; }
+-
+- // Direct children nodes, sorted by ascending unique position. These are
+- // guaranteed to be valid updates (e.g. IsValidBookmarkSpecifics()).
+- const std::vector<RemoteTreeNode>& children() const { return children_; }
+-
+- // Recursively emplaces all GUIDs (this node and descendants) into
+- // |*guid_to_remote_node_map|, which must not be null.
+- void EmplaceSelfAndDescendantsByGUID(
+- std::unordered_map<std::string, const RemoteTreeNode*>*
+- guid_to_remote_node_map) const {
+- DCHECK(guid_to_remote_node_map);
+-
+- const std::string& guid = entity().specifics.bookmark().guid();
+- if (!guid.empty()) {
+- DCHECK(base::IsValidGUID(guid));
+-
+- // Duplicate GUIDs have been sorted out before.
+- bool success = guid_to_remote_node_map->emplace(guid, this).second;
+- DCHECK(success);
+- }
++BookmarkModelMerger::RemoteTreeNode::RemoteTreeNode() = default;
+
+- for (const RemoteTreeNode& child : children_) {
+- child.EmplaceSelfAndDescendantsByGUID(guid_to_remote_node_map);
+- }
+- }
++BookmarkModelMerger::RemoteTreeNode::~RemoteTreeNode() = default;
++
++BookmarkModelMerger::RemoteTreeNode::RemoteTreeNode(
++ BookmarkModelMerger::RemoteTreeNode&&) = default;
++BookmarkModelMerger::RemoteTreeNode& BookmarkModelMerger::RemoteTreeNode::
++operator=(BookmarkModelMerger::RemoteTreeNode&&) = default;
++
++void BookmarkModelMerger::RemoteTreeNode::EmplaceSelfAndDescendantsByGUID(
++ std::unordered_map<std::string, const RemoteTreeNode*>*
++ guid_to_remote_node_map) const {
++ DCHECK(guid_to_remote_node_map);
++
++ const std::string& guid = entity().specifics.bookmark().guid();
++ if (!guid.empty()) {
++ DCHECK(base::IsValidGUID(guid));
+
+- private:
+- static bool UniquePositionLessThan(const RemoteTreeNode& lhs,
+- const RemoteTreeNode& rhs) {
+- const syncer::UniquePosition a_pos =
+- syncer::UniquePosition::FromProto(lhs.entity().unique_position);
+- const syncer::UniquePosition b_pos =
+- syncer::UniquePosition::FromProto(rhs.entity().unique_position);
+- return a_pos.LessThan(b_pos);
++ // Duplicate GUIDs have been sorted out before.
++ bool success = guid_to_remote_node_map->emplace(guid, this).second;
++ DCHECK(success);
+ }
+
+- RemoteTreeNode() = default;
++ for (const RemoteTreeNode& child : children_) {
++ child.EmplaceSelfAndDescendantsByGUID(guid_to_remote_node_map);
++ }
++}
+
+- std::unique_ptr<syncer::UpdateResponseData> update_;
+- std::vector<RemoteTreeNode> children_;
+-};
++// static
++bool BookmarkModelMerger::RemoteTreeNode::UniquePositionLessThan(
++ const RemoteTreeNode& lhs,
++ const RemoteTreeNode& rhs) {
++ const syncer::UniquePosition a_pos =
++ syncer::UniquePosition::FromProto(lhs.entity().unique_position);
++ const syncer::UniquePosition b_pos =
++ syncer::UniquePosition::FromProto(rhs.entity().unique_position);
++ return a_pos.LessThan(b_pos);
++}
+
+ // static
+ BookmarkModelMerger::RemoteTreeNode
+diff --git a/components/sync_bookmarks/bookmark_model_merger.h b/components/sync_bookmarks/bookmark_model_merger.h
+index 9b592000dc59..bf0783ecf8ee 100644
+--- a/components/sync_bookmarks/bookmark_model_merger.h
++++ b/components/sync_bookmarks/bookmark_model_merger.h
+@@ -5,6 +5,7 @@
+ #ifndef COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_MERGER_H_
+ #define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_MERGER_H_
+
++#include <memory>
+ #include <string>
+ #include <unordered_map>
+ #include <vector>
+@@ -50,7 +51,52 @@ class BookmarkModelMerger {
+
+ private:
+ // Internal representation of a remote tree, composed of nodes.
+- class RemoteTreeNode;
++ class RemoteTreeNode final {
++ private:
++ using UpdatesPerParentId =
++ std::unordered_map<base::StringPiece,
++ syncer::UpdateResponseDataList,
++ base::StringPieceHash>;
++
++ public:
++ // Constructs a tree given |update| as root and recursively all descendants
++ // by traversing |*updates_per_parent_id|. |update| and
++ // |updates_per_parent_id| must not be null. All updates
++ // |*updates_per_parent_id| must represent valid updates. Updates
++ // corresponding from descendant nodes are moved away from
++ // |*updates_per_parent_id|.
++ static RemoteTreeNode BuildTree(
++ std::unique_ptr<syncer::UpdateResponseData> update,
++ UpdatesPerParentId* updates_per_parent_id);
++
++ ~RemoteTreeNode();
++
++ // Allow moves, useful during construction.
++ RemoteTreeNode(RemoteTreeNode&&);
++ RemoteTreeNode& operator=(RemoteTreeNode&&);
++
++ const syncer::EntityData& entity() const { return *update_->entity; }
++ int64_t response_version() const { return update_->response_version; }
++
++ // Direct children nodes, sorted by ascending unique position. These are
++ // guaranteed to be valid updates (e.g. IsValidBookmarkSpecifics()).
++ const std::vector<RemoteTreeNode>& children() const { return children_; }
++
++ // Recursively emplaces all GUIDs (this node and descendants) into
++ // |*guid_to_remote_node_map|, which must not be null.
++ void EmplaceSelfAndDescendantsByGUID(
++ std::unordered_map<std::string, const RemoteTreeNode*>*
++ guid_to_remote_node_map) const;
++
++ private:
++ static bool UniquePositionLessThan(const RemoteTreeNode& lhs,
++ const RemoteTreeNode& rhs);
++
++ RemoteTreeNode();
++
++ std::unique_ptr<syncer::UpdateResponseData> update_;
++ std::vector<RemoteTreeNode> children_;
++ };
+
+ // A forest composed of multiple trees where the root of each tree represents
+ // a permanent node, keyed by server-defined unique tag of the root.
+--
+2.24.1
+
diff --git a/0001-Refactor-bookmark-GUID-matching-logic.patch b/0001-Refactor-bookmark-GUID-matching-logic.patch
new file mode 100644
index 000000000000..3c0a732efc6e
--- /dev/null
+++ b/0001-Refactor-bookmark-GUID-matching-logic.patch
@@ -0,0 +1,329 @@
+From afc8770181f528d391e74af41e9be125814e3009 Mon Sep 17 00:00:00 2001
+From: Mikel Astiz <mastiz@chromium.org>
+Date: Mon, 25 Nov 2019 10:53:45 +0000
+Subject: [PATCH] Refactor bookmark GUID-matching logic
+
+Prior to this patch, the two existing functions to build GUID-keyed maps
+were heavily coupled and there were fragile underlying assumptions that
+made it work (e.g. there were potentially entries in
+|guid_to_remote_node_map_| that didn't actually match any local GUID).
+
+Instead, let's centralize the matching logic into one single function,
+and adopt a unified map to represent the matches. This simplifies the
+code and enforces more strict invariants without the need for DCHECKs.
+
+Bug: 978430
+Change-Id: Ieea0db8d43376e204b793dcc64b2dc84d521b289
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1929216
+Commit-Queue: Mikel Astiz <mastiz@chromium.org>
+Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#718580}
+---
+ .../sync_bookmarks/bookmark_model_merger.cc | 133 ++++++++----------
+ .../sync_bookmarks/bookmark_model_merger.h | 40 ++----
+ .../bookmark_specifics_conversions.cc | 6 +
+ 3 files changed, 81 insertions(+), 98 deletions(-)
+
+diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc
+index 861403dbe05a..dfd19a27a592 100644
+--- a/components/sync_bookmarks/bookmark_model_merger.cc
++++ b/components/sync_bookmarks/bookmark_model_merger.cc
+@@ -237,9 +237,8 @@ BookmarkModelMerger::BookmarkModelMerger(
+ favicon_service_(favicon_service),
+ bookmark_tracker_(bookmark_tracker),
+ remote_forest_(BuildRemoteForest(std::move(updates))),
+- guid_to_remote_node_map_(BuildGUIDToRemoteNodeMap(remote_forest_)),
+- guid_to_local_node_map_(
+- BuildGUIDToLocalNodeMap(bookmark_model_, guid_to_remote_node_map_)) {
++ guid_to_match_map_(
++ FindGuidMatchesOrReassignLocal(remote_forest_, bookmark_model_)) {
+ DCHECK(bookmark_tracker_->IsEmpty());
+ DCHECK(favicon_service);
+ }
+@@ -307,63 +306,62 @@ BookmarkModelMerger::RemoteForest BookmarkModelMerger::BuildRemoteForest(
+ }
+
+ // static
+-std::unordered_map<std::string, const BookmarkModelMerger::RemoteTreeNode*>
+-BookmarkModelMerger::BuildGUIDToRemoteNodeMap(
+- const RemoteForest& remote_forest) {
++std::unordered_map<std::string, BookmarkModelMerger::GuidMatch>
++BookmarkModelMerger::FindGuidMatchesOrReassignLocal(
++ const RemoteForest& remote_forest,
++ bookmarks::BookmarkModel* bookmark_model) {
++ DCHECK(bookmark_model);
++
+ // TODO(crbug.com/978430): Handle potential duplicate GUIDs within remote
+ // updates.
+- std::unordered_map<std::string, const RemoteTreeNode*>
+- guid_to_remote_node_map;
++
+ if (!base::FeatureList::IsEnabled(switches::kMergeBookmarksUsingGUIDs)) {
+- return guid_to_remote_node_map;
++ return {};
+ }
+
++ // Build a temporary lookup table for remote GUIDs.
++ std::unordered_map<std::string, const RemoteTreeNode*>
++ guid_to_remote_node_map;
+ for (const auto& tree_tag_and_root : remote_forest) {
+ tree_tag_and_root.second.EmplaceSelfAndDescendantsByGUID(
+ &guid_to_remote_node_map);
+ }
+
+- return guid_to_remote_node_map;
+-}
+-
+-// static
+-std::unordered_map<std::string, const bookmarks::BookmarkNode*>
+-BookmarkModelMerger::BuildGUIDToLocalNodeMap(
+- bookmarks::BookmarkModel* bookmark_model,
+- const std::unordered_map<std::string, const RemoteTreeNode*>&
+- guid_to_remote_node_map) {
+- DCHECK(bookmark_model);
+-
+- std::unordered_map<std::string, const bookmarks::BookmarkNode*>
+- guid_to_local_node_map;
+- if (!base::FeatureList::IsEnabled(switches::kMergeBookmarksUsingGUIDs)) {
+- return guid_to_local_node_map;
+- }
+-
++ // Iterate through all local bookmarks to find matches by GUID.
++ std::unordered_map<std::string, BookmarkModelMerger::GuidMatch>
++ guid_to_match_map;
+ ui::TreeNodeIterator<const bookmarks::BookmarkNode> iterator(
+ bookmark_model->root_node());
+ while (iterator.has_next()) {
+- const bookmarks::BookmarkNode* node = iterator.Next();
++ const bookmarks::BookmarkNode* const node = iterator.Next();
+ DCHECK(base::IsValidGUID(node->guid()));
++
+ if (node->is_permanent_node()) {
+ continue;
+ }
++
+ const auto remote_it = guid_to_remote_node_map.find(node->guid());
+ if (remote_it == guid_to_remote_node_map.end()) {
+ continue;
+ }
+- // If local node and its remote node match are conflicting in node type or
+- // URL, replace local GUID with a random GUID.
+- const syncer::EntityData& remote_entity = remote_it->second->entity();
++
++ const RemoteTreeNode* const remote_node = remote_it->second;
++ const syncer::EntityData& remote_entity = remote_node->entity();
+ if (node->is_folder() != remote_entity.is_folder ||
+ (node->is_url() &&
+ node->url() != remote_entity.specifics.bookmark().url())) {
+- node =
+- ReplaceBookmarkNodeGUID(node, base::GenerateGUID(), bookmark_model);
++ // If local node and its remote node match are conflicting in node type or
++ // URL, replace local GUID with a random GUID.
++ // TODO(crbug.com/978430): Local GUIDs should also be reassigned if they
++ // match a remote originator_item_id.
++ ReplaceBookmarkNodeGUID(node, base::GenerateGUID(), bookmark_model);
++ continue;
+ }
+- guid_to_local_node_map.emplace(node->guid(), node);
++
++ guid_to_match_map.emplace(node->guid(), GuidMatch{node, remote_node});
+ }
+- return guid_to_local_node_map;
++
++ return guid_to_match_map;
+ }
+
+ void BookmarkModelMerger::MergeSubtree(
+@@ -422,25 +420,27 @@ const bookmarks::BookmarkNode* BookmarkModelMerger::FindMatchingLocalNode(
+ const bookmarks::BookmarkNode* local_parent,
+ size_t local_child_start_index) const {
+ // Try to match child by GUID. If we can't, try to match child by semantics.
+- const bookmarks::BookmarkNode* matching_local_node =
++ const bookmarks::BookmarkNode* matching_local_node_by_guid =
+ FindMatchingLocalNodeByGUID(remote_child);
+- if (!matching_local_node) {
+- // All local nodes up to |remote_index-1| have processed already. Look for a
+- // matching local node starting with the local node at position
+- // |local_child_start_index|. FindMatchingChildBySemanticsStartingAt()
+- // returns kInvalidIndex in the case where no semantics match was found or
+- // the semantics match found is GUID-matchable to a different node.
+- const size_t local_index = FindMatchingChildBySemanticsStartingAt(
+- /*remote_node=*/remote_child,
+- /*local_parent=*/local_parent,
+- /*starting_child_index=*/local_child_start_index);
+- if (local_index == kInvalidIndex) {
+- // If no match found, return.
+- return nullptr;
+- }
+- matching_local_node = local_parent->children()[local_index].get();
++ if (matching_local_node_by_guid) {
++ return matching_local_node_by_guid;
++ }
++
++ // All local nodes up to |remote_index-1| have processed already. Look for a
++ // matching local node starting with the local node at position
++ // |local_child_start_index|. FindMatchingChildBySemanticsStartingAt()
++ // returns kInvalidIndex in the case where no semantics match was found or
++ // the semantics match found is GUID-matchable to a different node.
++ const size_t local_index = FindMatchingChildBySemanticsStartingAt(
++ /*remote_node=*/remote_child,
++ /*local_parent=*/local_parent,
++ /*starting_child_index=*/local_child_start_index);
++ if (local_index == kInvalidIndex) {
++ // If no match found, return.
++ return nullptr;
+ }
+- return matching_local_node;
++
++ return local_parent->children()[local_index].get();
+ }
+
+ const bookmarks::BookmarkNode*
+@@ -471,8 +471,6 @@ BookmarkModelMerger::UpdateBookmarkNodeFromSpecificsIncludingGUID(
+ return local_node;
+ }
+ DCHECK(base::IsValidGUID(specifics.guid()));
+- // We do not update the GUID maps upon node replacement as per the comment
+- // in bookmark_model_merger.h.
+ return ReplaceBookmarkNodeGUID(local_node, specifics.guid(), bookmark_model_);
+ }
+
+@@ -574,7 +572,7 @@ void BookmarkModelMerger::ProcessLocalCreation(
+ if (FindMatchingRemoteNodeByGUID(node->children()[i].get())) {
+ continue;
+ }
+- ProcessLocalCreation(node, i);
++ ProcessLocalCreation(/*parent=*/node, i);
+ }
+ }
+
+@@ -612,36 +610,25 @@ const BookmarkModelMerger::RemoteTreeNode*
+ BookmarkModelMerger::FindMatchingRemoteNodeByGUID(
+ const bookmarks::BookmarkNode* local_node) const {
+ DCHECK(local_node);
+- // Ensure matching nodes are of the same type and have the same URL,
+- // guaranteed by BuildGUIDToLocalNodeMap().
+- const auto it = guid_to_remote_node_map_.find(local_node->guid());
+- if (it == guid_to_remote_node_map_.end()) {
++
++ const auto it = guid_to_match_map_.find(local_node->guid());
++ if (it == guid_to_match_map_.end()) {
+ return nullptr;
+ }
+
+- const RemoteTreeNode* const remote_node = it->second;
+- DCHECK(remote_node);
+- DCHECK_EQ(local_node->is_folder(), remote_node->entity().is_folder);
+- DCHECK_EQ(local_node->url(),
+- remote_node->entity().specifics.bookmark().url());
+- return remote_node;
++ return it->second.remote_node;
+ }
+
+ const bookmarks::BookmarkNode* BookmarkModelMerger::FindMatchingLocalNodeByGUID(
+ const RemoteTreeNode& remote_node) const {
+ const syncer::EntityData& remote_entity = remote_node.entity();
+ const auto it =
+- guid_to_local_node_map_.find(remote_entity.specifics.bookmark().guid());
+- if (it == guid_to_local_node_map_.end()) {
++ guid_to_match_map_.find(remote_entity.specifics.bookmark().guid());
++ if (it == guid_to_match_map_.end()) {
+ return nullptr;
+ }
+- DCHECK(!remote_entity.specifics.bookmark().guid().empty());
+- const bookmarks::BookmarkNode* local_node = it->second;
+- // Ensure matching nodes are of the same type and have the same URL,
+- // guaranteed by BuildGUIDToLocalNodeMap().
+- DCHECK_EQ(local_node->is_folder(), remote_entity.is_folder);
+- DCHECK_EQ(local_node->url(), remote_entity.specifics.bookmark().url());
+- return local_node;
++
++ return it->second.local_node;
+ }
+
+ } // namespace sync_bookmarks
+diff --git a/components/sync_bookmarks/bookmark_model_merger.h b/components/sync_bookmarks/bookmark_model_merger.h
+index 1a40fad2a074..18744920a1a4 100644
+--- a/components/sync_bookmarks/bookmark_model_merger.h
++++ b/components/sync_bookmarks/bookmark_model_merger.h
+@@ -56,6 +56,14 @@ class BookmarkModelMerger {
+ // a permanent node, keyed by server-defined unique tag of the root.
+ using RemoteForest = std::unordered_map<std::string, RemoteTreeNode>;
+
++ // Represents a pair of bookmarks, one local and one remote, that have been
++ // matched by GUID. They are guaranteed to have the same type and URL (if
++ // applicable).
++ struct GuidMatch {
++ const bookmarks::BookmarkNode* local_node;
++ const RemoteTreeNode* remote_node;
++ };
++
+ // Constructs the remote bookmark tree to be merged. Each entry in the
+ // returned map is a permanent node, identified (keyed) by the server-defined
+ // tag. All invalid updates are filtered out, including invalid bookmark
+@@ -63,22 +71,12 @@ class BookmarkModelMerger {
+ // sends tombstones as part of the initial download.
+ static RemoteForest BuildRemoteForest(syncer::UpdateResponseDataList updates);
+
+- // Constructs a map from GUID to corresponding remote nodes, used in the merge
+- // process to determine GUID-based node matches.
+- static std::unordered_map<std::string, const RemoteTreeNode*>
+- BuildGUIDToRemoteNodeMap(const RemoteForest& remote_forest);
+-
+- // Constructs a map from GUID to corresponding local node, used in the merge
+- // process to determine GUID-based node matches. |bookmark_model| must not be
+- // null. |guid_to_remote_node_map| is used to detect conflicting GUID matches
+- // between local and remote bookmarks for the cases where they cannot be
+- // merged (e.g. folder vs non-folder) and in such cases regenerate a random
+- // GUID for the local bookmark.
+- static std::unordered_map<std::string, const bookmarks::BookmarkNode*>
+- BuildGUIDToLocalNodeMap(
+- bookmarks::BookmarkModel* bookmark_model,
+- const std::unordered_map<std::string, const RemoteTreeNode*>&
+- guid_to_remote_node_map);
++ // Computes bookmark pairs that should be matched by GUID. Local bookmark
++ // GUIDs may be regenerated for the case where they collide with a remote GUID
++ // that is not compatible (e.g. folder vs non-folder).
++ static std::unordered_map<std::string, GuidMatch>
++ FindGuidMatchesOrReassignLocal(const RemoteForest& remote_forest,
++ bookmarks::BookmarkModel* bookmark_model);
+
+ // Merges a local and a remote subtrees. The input nodes are two equivalent
+ // local and remote nodes. This method tries to recursively match their
+@@ -151,15 +149,7 @@ class BookmarkModelMerger {
+ // Preprocessed remote nodes in the form a forest where each tree's root is a
+ // permanent node. Computed upon construction via BuildRemoteForest().
+ const RemoteForest remote_forest_;
+- // Maps GUIDs to their respective remote nodes. Used for GUID-based node
+- // matching and is populated at the beginning of the merge process.
+- const std::unordered_map<std::string, const RemoteTreeNode*>
+- guid_to_remote_node_map_;
+- // Maps GUIDs to their respective local nodes. Used for GUID-based
+- // node matching and is populated at the beginning of the merge process.
+- // Is not updated upon potential changes to the model during merge.
+- const std::unordered_map<std::string, const bookmarks::BookmarkNode*>
+- guid_to_local_node_map_;
++ std::unordered_map<std::string, GuidMatch> guid_to_match_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkModelMerger);
+ };
+diff --git a/components/sync_bookmarks/bookmark_specifics_conversions.cc b/components/sync_bookmarks/bookmark_specifics_conversions.cc
+index 98725dce2a61..74914f187509 100644
+--- a/components/sync_bookmarks/bookmark_specifics_conversions.cc
++++ b/components/sync_bookmarks/bookmark_specifics_conversions.cc
+@@ -255,6 +255,12 @@ const bookmarks::BookmarkNode* ReplaceBookmarkNodeGUID(
+ }
+ const bookmarks::BookmarkNode* new_node;
+ DCHECK(base::IsValidGUID(guid));
++
++ if (node->guid() == guid) {
++ // Nothing to do.
++ return node;
++ }
++
+ if (node->is_folder()) {
+ new_node =
+ model->AddFolder(node->parent(), node->parent()->GetIndexOf(node),
+--
+2.24.1
+
diff --git a/0001-cros-search-service-Include-cmath-for-std-pow.patch b/0001-cros-search-service-Include-cmath-for-std-pow.patch
new file mode 100644
index 000000000000..5c620a79edf6
--- /dev/null
+++ b/0001-cros-search-service-Include-cmath-for-std-pow.patch
@@ -0,0 +1,38 @@
+From 8273f4d3130e06fd8b6bef87b07c936304b971d9 Mon Sep 17 00:00:00 2001
+From: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Date: Tue, 10 Dec 2019 20:59:57 +0000
+Subject: [PATCH] [cros search service]: Include <cmath> for std::pow()
+
+IWYU. Follow up to commit 2b2ea3c09b ("[cros search service] Move shared
+string matching functions to //chrome"), which broke the libstdc++ build:
+
+ ../../chrome/common/string_matching/fuzzy_tokenized_string_match.cc:199:14: error: no member named 'pow' in namespace 'std'
+ std::pow(partial_match_penalty_rate, long_start - current - 1);
+ ~~~~~^
+
+Bug: 957519
+Change-Id: I66f61cb4f93cfa0bfa3d1b00ba391ddd8f31a7fb
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1960310
+Auto-Submit: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Reviewed-by: Jia Meng <jiameng@chromium.org>
+Commit-Queue: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Cr-Commit-Position: refs/heads/master@{#723499}
+---
+ chrome/common/string_matching/fuzzy_tokenized_string_match.cc | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/chrome/common/string_matching/fuzzy_tokenized_string_match.cc b/chrome/common/string_matching/fuzzy_tokenized_string_match.cc
+index 8351fa701e4d..884ef638c61c 100644
+--- a/chrome/common/string_matching/fuzzy_tokenized_string_match.cc
++++ b/chrome/common/string_matching/fuzzy_tokenized_string_match.cc
+@@ -5,6 +5,7 @@
+ #include "chrome/common/string_matching/fuzzy_tokenized_string_match.h"
+
+ #include <algorithm>
++#include <cmath>
+ #include <iterator>
+
+ #include "base/i18n/case_conversion.h"
+--
+2.24.1
+
diff --git a/0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch b/0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch
deleted file mode 100644
index 53da1d5d3118..000000000000
--- a/0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch
+++ /dev/null
@@ -1,173 +0,0 @@
-Upstream-Status: Backport
-
-Backported from https://crrev.com/c/1946479
-
-Signed-off-by: Maksim Sisov <msisov@igalia.com>
----
-From 4c9a7209005ee6c134692932d4c6d784d48ada34 Mon Sep 17 00:00:00 2001
-From: Maksim Sisov <msisov@igalia.com>
-Date: Tue, 3 Dec 2019 08:23:42 +0000
-Subject: [PATCH] ozone/wayland: Complete submission of a buffer submitted more
- than once
-
-This CL fixes a corner use case that was caught by one of the users
-of Ozone/Wayland.
-
-The problem appeared when the Chromium compositor sent a next frame into
-the same buffer that had just been submitted and a OnSubmission callback
-had been sent to the viz process located WaylandBufferManager. This
-happened only when the remote inspector was attached and the screencast
-was enabled.
-
-In this case, Wayland compositor will not send an OnRelease callback
-and we should not wait for that. Instead, we must complete the
-submission immediately and set the |WaylandBuffer::released|
-member to be false. Once another buffer is committed, Wayland compositor
-will release the previous buffer.
-
-Bug: 1029777
-Change-Id: Ib74c16f41f128298998bc9699f8d9ded3697cd43
-Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1946479
-Commit-Queue: Maksim Sisov <msisov@igalia.com>
-Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
-Cr-Commit-Position: refs/heads/master@{#720878}
----
- .../host/wayland_buffer_manager_host.cc | 22 ++++--
- .../wayland_buffer_manager_unittest.cc | 78 +++++++++++++++++++
- 2 files changed, 95 insertions(+), 5 deletions(-)
-
-diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
-index f360f916cae7..c7fc7094475a 100644
---- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
-+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
-@@ -231,13 +231,20 @@ class WaylandBufferManagerHost::Surface {
- DCHECK(buffer);
- DCHECK(!pending_buffer_);
-
-- // Once the BufferRelease is called, the buffer will be released.
-- DCHECK(buffer->released);
-- buffer->released = false;
--
- DCHECK(!submitted_buffer_);
- submitted_buffer_ = buffer;
-
-+ // if the same buffer has been submitted again right after the client
-+ // received OnSubmission for that buffer, just verify that the buffer has
-+ // not been released by Wayland compositor, which is correct.
-+ if (prev_submitted_buffer_ != submitted_buffer_) {
-+ // Once the BufferRelease is called, the buffer will be released.
-+ DCHECK(buffer->released);
-+ buffer->released = false;
-+ } else {
-+ DCHECK(!buffer->released);
-+ }
-+
- AttachAndDamageBuffer(buffer);
-
- SetupFrameCallback();
-@@ -258,7 +265,12 @@ class WaylandBufferManagerHost::Surface {
- // If it was the very first frame, the surface has not had a back buffer
- // before, and Wayland won't release the front buffer until next buffer is
- // attached. Thus, notify about successful submission immediately.
-- if (!prev_submitted_buffer_)
-+ //
-+ // As said above, if the client submits the same buffer again, we must
-+ // notify the client about the submission immediately as Wayland compositor
-+ // is not going to send a release callback for a buffer committed more than
-+ // once.
-+ if (!prev_submitted_buffer_ || prev_submitted_buffer_ == submitted_buffer_)
- CompleteSubmission();
-
- return true;
-diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
-index 3908e2af629c..012e40f5a75a 100644
---- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
-+++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
-@@ -477,6 +477,84 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
- Sync();
- }
-
-+// This test verifies that submitting the buffer more than once results in
-+// OnSubmission callback as Wayland compositor is not supposed to release the
-+// buffer committed twice.
-+TEST_P(WaylandBufferManagerTest, SubmitSameBufferMultipleTimes) {
-+ constexpr uint32_t kBufferId1 = 1;
-+ constexpr uint32_t kBufferId2 = 2;
-+
-+ const gfx::AcceleratedWidget widget = window_->GetWidget();
-+ const gfx::Rect bounds = window_->GetBounds();
-+
-+ MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget);
-+
-+ auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
-+ EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(2);
-+ CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId1);
-+ CreateDmabufBasedBufferAndSetTerminateExpecation(false /*fail*/, kBufferId2);
-+
-+ Sync();
-+
-+ ProcessCreatedBufferResourcesWithExpectation(2u /* expected size */,
-+ false /* fail */);
-+
-+ // All the other expectations must come in order.
-+ ::testing::InSequence sequence;
-+ EXPECT_CALL(mock_surface_gpu,
-+ OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK))
-+ .Times(1);
-+ ASSERT_TRUE(!connection_->presentation());
-+ EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
-+
-+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
-+
-+ Sync();
-+
-+ testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
-+
-+ auto* mock_surface = server_.GetObject<wl::MockSurface>(widget);
-+ mock_surface->SendFrameCallback();
-+
-+ Sync();
-+
-+ // Commit second buffer now.
-+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
-+
-+ Sync();
-+
-+ EXPECT_CALL(mock_surface_gpu,
-+ OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK))
-+ .Times(1);
-+ EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1);
-+
-+ mock_surface->ReleasePrevAttachedBuffer();
-+ mock_surface->SendFrameCallback();
-+
-+ Sync();
-+
-+ testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
-+
-+ // Now, commit the buffer with the |kBufferId2| again and make sure the
-+ // manager manually sends the submission callback as long as the compositor is
-+ // not going to release a buffer as it was the same buffer submitted more than
-+ // once.
-+ EXPECT_CALL(mock_surface_gpu,
-+ OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK))
-+ .Times(1);
-+ EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1);
-+
-+ // Commit second buffer now.
-+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
-+
-+ Sync();
-+
-+ testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
-+
-+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/);
-+ DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/);
-+}
-+
- INSTANTIATE_TEST_SUITE_P(XdgVersionV5Test,
- WaylandBufferManagerTest,
- ::testing::Values(kXdgShellV5));
---
-2.20.1
-
diff --git a/0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch b/0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch
new file mode 100644
index 000000000000..ff7a44ce17c5
--- /dev/null
+++ b/0001-ozone-wayland-Extract-ShellObjectFactory-to-a-separa.patch
@@ -0,0 +1,788 @@
+From 40bbda2b7265437d6dea1ce9d3361f85147fedf1 Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Fri, 6 Dec 2019 19:35:16 +0000
+Subject: [PATCH 1/9] ozone/wayland: Extract ShellObjectFactory to a separate
+ file.
+
+This CL
+1) extracts ShellObjectFactory into a separate file and keeps
+the same creation and initialization logic of wrappers of shell objects,
+2) extends ShellPopupWrapper and ShellSurfaceWrapper interfaces by adding
+Initialize method so that it is more convenient to initialize
+XdgPopupWrapperImpl XdgSurfaceWrapperImpl and let them handle initialization
+based on the available xdg-shell version,
+3) makes WaylandWindow use the extracted ShellObjectFactory,
+4) makes InitializeStable and InitializeV6 methods of
+XDGWrapper objects be private members. The decision on which
+one to call is made in the main Initialize method now.
+5) reconsiders the logging whether we need to keep pointers to
+some objects or not.
+
+Bug: 1028919
+Change-Id: I87fd5fc0d0b35222f26c460c9174da6053dc320e
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1953708
+Reviewed-by: Michael Spang <spang@chromium.org>
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Cr-Commit-Position: refs/heads/master@{#722572}
+---
+ ui/ozone/platform/wayland/BUILD.gn | 2 +
+ .../wayland/host/shell_object_factory.cc | 47 +++++
+ .../wayland/host/shell_object_factory.h | 44 +++++
+ .../wayland/host/shell_popup_wrapper.h | 6 +
+ .../wayland/host/shell_surface_wrapper.h | 4 +
+ .../platform/wayland/host/wayland_window.cc | 72 +------
+ .../platform/wayland/host/wayland_window.h | 7 -
+ .../wayland/host/xdg_popup_wrapper_impl.cc | 48 ++---
+ .../wayland/host/xdg_popup_wrapper_impl.h | 19 +-
+ .../wayland/host/xdg_surface_wrapper_impl.cc | 181 ++++++++++--------
+ .../wayland/host/xdg_surface_wrapper_impl.h | 27 +--
+ 11 files changed, 261 insertions(+), 196 deletions(-)
+ create mode 100644 ui/ozone/platform/wayland/host/shell_object_factory.cc
+ create mode 100644 ui/ozone/platform/wayland/host/shell_object_factory.h
+
+diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
+index 37e7ffb5d83c..9c2cbc52500b 100644
+--- a/ui/ozone/platform/wayland/BUILD.gn
++++ b/ui/ozone/platform/wayland/BUILD.gn
+@@ -45,6 +45,8 @@ source_set("wayland") {
+ "host/internal/wayland_data_offer_base.h",
+ "host/internal/wayland_data_source_base.cc",
+ "host/internal/wayland_data_source_base.h",
++ "host/shell_object_factory.cc",
++ "host/shell_object_factory.h",
+ "host/shell_popup_wrapper.cc",
+ "host/shell_popup_wrapper.h",
+ "host/shell_surface_wrapper.cc",
+diff --git a/ui/ozone/platform/wayland/host/shell_object_factory.cc b/ui/ozone/platform/wayland/host/shell_object_factory.cc
+new file mode 100644
+index 000000000000..57383be20da5
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/shell_object_factory.cc
+@@ -0,0 +1,47 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
++
++#include "ui/ozone/platform/wayland/host/wayland_connection.h"
++#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h"
++#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
++
++namespace ui {
++
++ShellObjectFactory::ShellObjectFactory() = default;
++ShellObjectFactory::~ShellObjectFactory() = default;
++
++std::unique_ptr<ShellSurfaceWrapper>
++ShellObjectFactory::CreateShellSurfaceWrapper(WaylandConnection* connection,
++ WaylandWindow* wayland_window) {
++ if (connection->shell() || connection->shell_v6()) {
++ auto surface =
++ std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection);
++ return surface->Initialize(true /* with_top_level */) ? std::move(surface)
++ : nullptr;
++ }
++ LOG(WARNING) << "Shell protocol is not available.";
++ return nullptr;
++}
++
++std::unique_ptr<ShellPopupWrapper> ShellObjectFactory::CreateShellPopupWrapper(
++ WaylandConnection* connection,
++ WaylandWindow* wayland_window,
++ const gfx::Rect& bounds) {
++ if (connection->shell() || connection->shell_v6()) {
++ auto surface =
++ std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection);
++ if (!surface->Initialize(false /* with_top_level */))
++ return nullptr;
++
++ auto popup = std::make_unique<XDGPopupWrapperImpl>(std::move(surface),
++ wayland_window);
++ return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr;
++ }
++ LOG(WARNING) << "Shell protocol is not available.";
++ return nullptr;
++}
++
++} // namespace ui
+\ No newline at end of file
+diff --git a/ui/ozone/platform/wayland/host/shell_object_factory.h b/ui/ozone/platform/wayland/host/shell_object_factory.h
+new file mode 100644
+index 000000000000..a915326c23fb
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/shell_object_factory.h
+@@ -0,0 +1,44 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_
++#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_
++
++#include <memory>
++
++namespace gfx {
++class Rect;
++}
++
++namespace ui {
++
++class ShellSurfaceWrapper;
++class ShellPopupWrapper;
++class WaylandConnection;
++class WaylandWindow;
++
++// Shell factory that creates shell objects for different protocols. Preferred
++// protocols are defined in the following order:
++// 1) xdg-shell-stable-protocol.
++// 2) xdg-shell-v6-unstable-protocol.
++class ShellObjectFactory {
++ public:
++ ShellObjectFactory();
++ ~ShellObjectFactory();
++
++ // Creates and initializes a ShellSurfaceWrapper.
++ std::unique_ptr<ShellSurfaceWrapper> CreateShellSurfaceWrapper(
++ WaylandConnection* connection,
++ WaylandWindow* wayland_window);
++
++ // Creates and intitializes a ShellPopupSurface.
++ std::unique_ptr<ShellPopupWrapper> CreateShellPopupWrapper(
++ WaylandConnection* connection,
++ WaylandWindow* wayland_window,
++ const gfx::Rect& bounds);
++};
++
++} // namespace ui
++
++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_
+\ No newline at end of file
+diff --git a/ui/ozone/platform/wayland/host/shell_popup_wrapper.h b/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
+index 952c0a2a278a..2970549dd09b 100644
+--- a/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
++++ b/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
+@@ -10,6 +10,8 @@
+
+ namespace ui {
+
++class WaylandConnection;
++
+ enum class MenuType {
+ TYPE_RIGHT_CLICK,
+ TYPE_3DOT_PARENT_MENU,
+@@ -67,6 +69,10 @@ inline WlConstraintAdjustment operator&(WlConstraintAdjustment a,
+ class ShellPopupWrapper {
+ public:
+ virtual ~ShellPopupWrapper() {}
++
++ // Initializes the popup surface.
++ virtual bool Initialize(WaylandConnection* connection,
++ const gfx::Rect& bounds) = 0;
+ };
+
+ gfx::Rect GetAnchorRect(MenuType menu_type,
+diff --git a/ui/ozone/platform/wayland/host/shell_surface_wrapper.h b/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
+index 49b27e4c7214..c75e87a627b4 100644
+--- a/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
++++ b/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
+@@ -21,6 +21,10 @@ class ShellSurfaceWrapper {
+ public:
+ virtual ~ShellSurfaceWrapper() {}
+
++ // Initializes the ShellSurface. Some protocols may require to create shell
++ // surface without toplevel role and assign a popup role to it later.
++ virtual bool Initialize(bool with_toplevel) = 0;
++
+ // Sets a native window to maximized state.
+ virtual void SetMaximized() = 0;
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index 4787a1f3b396..95c6e5a46b3e 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -16,6 +16,7 @@
+ #include "ui/events/event_utils.h"
+ #include "ui/events/ozone/events_ozone.h"
+ #include "ui/gfx/geometry/point_f.h"
++#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+ #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+ #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+ #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+@@ -23,50 +24,12 @@
+ #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+ #include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+ #include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+-#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h"
+-#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+ #include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+
+ namespace ui {
+
+ namespace {
+
+-// Factory, which decides which version type of xdg object to build.
+-class XDGShellObjectFactory {
+- public:
+- XDGShellObjectFactory() = default;
+- ~XDGShellObjectFactory() = default;
+-
+- std::unique_ptr<ShellPopupWrapper> CreateXDGPopup(
+- WaylandConnection* connection,
+- WaylandWindow* wayland_window,
+- const gfx::Rect& bounds) {
+- std::unique_ptr<XDGSurfaceWrapperImpl> surface =
+- std::make_unique<XDGSurfaceWrapperImpl>(wayland_window);
+- if (connection->shell()) {
+- surface->InitializeStable(connection, wayland_window->surface(), false);
+- std::unique_ptr<XDGPopupWrapperImpl> popup =
+- std::make_unique<XDGPopupWrapperImpl>(std::move(surface),
+- wayland_window);
+- popup->InitializeStable(connection, wayland_window->surface(),
+- wayland_window->parent_window(), bounds);
+- return popup;
+- }
+- DCHECK(connection->shell_v6());
+-
+- surface->InitializeV6(connection, wayland_window->surface(), false);
+- std::unique_ptr<XDGPopupWrapperImpl> popup =
+- std::make_unique<XDGPopupWrapperImpl>(std::move(surface),
+- wayland_window);
+- popup->InitializeV6(connection, wayland_window->surface(),
+- wayland_window->parent_window(), bounds);
+- return popup;
+- }
+-
+- private:
+- DISALLOW_COPY_AND_ASSIGN(XDGShellObjectFactory);
+-};
+-
+ // Translates bounds relative to top level window to specified parent.
+ gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
+ const gfx::Rect& parent_bounds) {
+@@ -89,7 +52,6 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection)
+ : delegate_(delegate),
+ connection_(connection),
+- xdg_shell_objects_factory_(new XDGShellObjectFactory()),
+ state_(PlatformWindowState::kNormal),
+ pending_state_(PlatformWindowState::kUnknown) {
+ // Set a class property key, which allows |this| to be used for interactive
+@@ -124,8 +86,6 @@ WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) {
+ }
+
+ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+- DCHECK(xdg_shell_objects_factory_);
+-
+ // 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.
+@@ -244,35 +204,19 @@ void WaylandWindow::CreateShellPopup() {
+
+ auto bounds_px = AdjustPopupWindowPosition();
+
+- shell_popup_ =
+- xdg_shell_objects_factory_->CreateXDGPopup(connection_, this, bounds_px);
+-
+- if (!shell_popup_) {
++ ShellObjectFactory factory;
++ shell_popup_ = factory.CreateShellPopupWrapper(connection_, this, bounds_px);
++ if (!shell_popup_)
+ CHECK(false) << "Failed to create Wayland shell popup";
+- }
+
+ parent_window_->set_child_window(this);
+ }
+
+ void WaylandWindow::CreateShellSurface() {
+- std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface =
+- std::make_unique<XDGSurfaceWrapperImpl>(this);
+- if (!xdg_surface) {
+- CHECK(false) << "Failed to create Wayland shell surface";
+- return;
+- }
+-
+- if (connection_->shell()) {
+- if (!xdg_surface->InitializeStable(connection_, surface_.get())) {
+- CHECK(false) << "Failed to initialize Wayland shell surface";
+- }
+- } else {
+- DCHECK(connection_->shell_v6());
+- if (!xdg_surface->InitializeV6(connection_, surface_.get())) {
+- CHECK(false) << "Failed to initialize Wayland shell surface";
+- }
+- }
+- shell_surface_ = std::move(xdg_surface);
++ ShellObjectFactory factory;
++ shell_surface_ = factory.CreateShellSurfaceWrapper(connection_, this);
++ if (!shell_surface_)
++ CHECK(false) << "Failed to initialize Wayland shell surface";
+ }
+
+ void WaylandWindow::CreateAndShowTooltipSubSurface() {
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
+index 2745dde85c32..4233216d7a6f 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.h
++++ b/ui/ozone/platform/wayland/host/wayland_window.h
+@@ -35,10 +35,6 @@ class WaylandConnection;
+ class ShellPopupWrapper;
+ class ShellSurfaceWrapper;
+
+-namespace {
+-class XDGShellObjectFactory;
+-} // namespace
+-
+ class WaylandWindow : public PlatformWindow,
+ public PlatformEventDispatcher,
+ public WmMoveResizeHandler,
+@@ -229,9 +225,6 @@ class WaylandWindow : public PlatformWindow,
+ WaylandWindow* parent_window_ = nullptr;
+ WaylandWindow* child_window_ = nullptr;
+
+- // Creates xdg objects based on xdg shell version.
+- std::unique_ptr<XDGShellObjectFactory> xdg_shell_objects_factory_;
+-
+ wl::Object<wl_surface> surface_;
+ wl::Object<wl_subsurface> tooltip_subsurface_;
+
+diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+index 0c6683828e74..abf6e7fa6461 100644
+--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+@@ -260,40 +260,45 @@ XDGPopupWrapperImpl::XDGPopupWrapperImpl(
+ WaylandWindow* wayland_window)
+ : wayland_window_(wayland_window), xdg_surface_(std::move(surface)) {
+ DCHECK(xdg_surface_);
++ DCHECK(wayland_window_ && wayland_window_->parent_window());
+ }
+
+-XDGPopupWrapperImpl::~XDGPopupWrapperImpl() {}
++XDGPopupWrapperImpl::~XDGPopupWrapperImpl() = default;
++
++bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
++ const gfx::Rect& bounds) {
++ if (connection->shell())
++ return InitializeStable(connection, bounds);
++ else if (connection->shell_v6())
++ return InitializeV6(connection, bounds);
++ NOTREACHED() << "Wrong shell protocol";
++ return false;
++}
+
+ bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection,
+- wl_surface* surface,
+- WaylandWindow* parent_window,
+ const gfx::Rect& bounds) {
+- DCHECK(connection && surface && parent_window);
+ static const struct xdg_popup_listener xdg_popup_listener = {
+ &XDGPopupWrapperImpl::ConfigureStable,
+ &XDGPopupWrapperImpl::PopupDoneStable,
+ };
+
+- if (!xdg_surface_)
+- return false;
+-
+ XDGSurfaceWrapperImpl* parent_xdg_surface;
+ // If the parent window is a popup, the surface of that popup must be used as
+ // a parent.
+- if (parent_window->shell_popup()) {
+- XDGPopupWrapperImpl* popup =
+- reinterpret_cast<XDGPopupWrapperImpl*>(parent_window->shell_popup());
++ if (wayland_window_->parent_window()->shell_popup()) {
++ XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>(
++ wayland_window_->parent_window()->shell_popup());
+ parent_xdg_surface = popup->xdg_surface();
+ } else {
+ parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>(
+- parent_window->shell_surface());
++ wayland_window_->parent_window()->shell_surface());
+ }
+
+ if (!parent_xdg_surface)
+ return false;
+
+- struct xdg_positioner* positioner =
+- CreatePositionerStable(connection, parent_window, bounds);
++ struct xdg_positioner* positioner = CreatePositionerStable(
++ connection, wayland_window_->parent_window(), bounds);
+ if (!positioner)
+ return false;
+
+@@ -337,7 +342,7 @@ bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection,
+ }
+ xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this);
+
+- wl_surface_commit(surface);
++ wl_surface_commit(wayland_window_->surface());
+ return true;
+ }
+
+@@ -383,10 +388,7 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
+ }
+
+ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection,
+- wl_surface* surface,
+- WaylandWindow* parent_window,
+ const gfx::Rect& bounds) {
+- DCHECK(connection && surface && parent_window);
+ static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
+ &XDGPopupWrapperImpl::ConfigureV6,
+ &XDGPopupWrapperImpl::PopupDoneV6,
+@@ -398,20 +400,20 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection,
+ XDGSurfaceWrapperImpl* parent_xdg_surface;
+ // If the parent window is a popup, the surface of that popup must be used as
+ // a parent.
+- if (parent_window->shell_popup()) {
+- XDGPopupWrapperImpl* popup =
+- reinterpret_cast<XDGPopupWrapperImpl*>(parent_window->shell_popup());
++ if (wayland_window_->parent_window()->shell_popup()) {
++ XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>(
++ wayland_window_->parent_window()->shell_popup());
+ parent_xdg_surface = popup->xdg_surface();
+ } else {
+ parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>(
+- parent_window->shell_surface());
++ wayland_window_->parent_window()->shell_surface());
+ }
+
+ if (!parent_xdg_surface)
+ return false;
+
+ zxdg_positioner_v6* positioner =
+- CreatePositionerV6(connection, parent_window, bounds);
++ CreatePositionerV6(connection, wayland_window_->parent_window(), bounds);
+ if (!positioner)
+ return false;
+
+@@ -457,7 +459,7 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection,
+ zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
+ this);
+
+- wl_surface_commit(surface);
++ wl_surface_commit(wayland_window_->surface());
+ return true;
+ }
+
+diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+index 371f18157d73..2a900818ff6a 100644
+--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+@@ -23,19 +23,16 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper {
+ ~XDGPopupWrapperImpl() override;
+
+ // XDGPopupWrapper:
+- bool InitializeStable(WaylandConnection* connection,
+- wl_surface* surface,
+- WaylandWindow* parent_window,
+- const gfx::Rect& bounds);
+- bool InitializeV6(WaylandConnection* connection,
+- wl_surface* surface,
+- WaylandWindow* parent_window,
+- const gfx::Rect& bounds);
++ bool Initialize(WaylandConnection* connection,
++ const gfx::Rect& bounds) override;
+
+ private:
++ bool InitializeStable(WaylandConnection* connection, const gfx::Rect& bounds);
+ struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
++
++ bool InitializeV6(WaylandConnection* connection, const gfx::Rect& bounds);
+ struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
+@@ -64,9 +61,15 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper {
+
+ XDGSurfaceWrapperImpl* xdg_surface();
+
++ // Non-owned WaylandWindow that uses this popup.
+ WaylandWindow* const wayland_window_;
++
++ // Ground surface for this popup.
+ std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_;
++
++ // XDG Shell Stable object.
+ wl::Object<xdg_popup> xdg_popup_;
++ // XDG Shell V6 object.
+ wl::Object<zxdg_popup_v6> zxdg_popup_v6_;
+
+ DISALLOW_COPY_AND_ASSIGN(XDGPopupWrapperImpl);
+diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+index d4078e1bc139..e7df772ae472 100644
+--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
++++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+@@ -15,84 +15,19 @@
+
+ namespace ui {
+
+-XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window)
+- : wayland_window_(wayland_window) {}
++XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
++ WaylandConnection* connection)
++ : wayland_window_(wayland_window), connection_(connection) {}
+
+ XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {}
+
+-bool XDGSurfaceWrapperImpl::InitializeStable(WaylandConnection* connection,
+- wl_surface* surface,
+- bool with_toplevel) {
+- static const xdg_surface_listener xdg_surface_listener = {
+- &XDGSurfaceWrapperImpl::ConfigureStable,
+- };
+- static const xdg_toplevel_listener xdg_toplevel_listener = {
+- &XDGSurfaceWrapperImpl::ConfigureTopLevelStable,
+- &XDGSurfaceWrapperImpl::CloseTopLevelStable,
+- };
+-
+- // if this surface is created for the popup role, mark that it requires
+- // configuration acknowledgement on each configure event.
+- surface_for_popup_ = !with_toplevel;
+-
+- xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection->shell(), surface));
+- if (!xdg_surface_) {
+- LOG(ERROR) << "Failed to create xdg_surface";
+- return false;
+- }
+- xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
+- // XDGPopup requires a separate surface to be created, so this is just a
+- // request to get an xdg_surface for it.
+- if (surface_for_popup_)
+- return true;
+-
+- xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get()));
+- if (!xdg_toplevel_) {
+- LOG(ERROR) << "Failed to create xdg_toplevel";
+- return false;
+- }
+- xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
+- wl_surface_commit(surface);
+- return true;
+-}
+-
+-bool XDGSurfaceWrapperImpl::InitializeV6(WaylandConnection* connection,
+- wl_surface* surface,
+- bool with_toplevel) {
+- static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
+- &XDGSurfaceWrapperImpl::ConfigureV6,
+- };
+- static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
+- &XDGSurfaceWrapperImpl::ConfigureTopLevelV6,
+- &XDGSurfaceWrapperImpl::CloseTopLevelV6,
+- };
+-
+- // if this surface is created for the popup role, mark that it requires
+- // configuration acknowledgement on each configure event.
+- surface_for_popup_ = !with_toplevel;
+-
+- zxdg_surface_v6_.reset(
+- zxdg_shell_v6_get_xdg_surface(connection->shell_v6(), surface));
+- if (!zxdg_surface_v6_) {
+- LOG(ERROR) << "Failed to create zxdg_surface";
+- return false;
+- }
+- zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
+- &zxdg_surface_v6_listener, this);
+- // XDGPopupV6 requires a separate surface to be created, so this is just a
+- // request to get an xdg_surface for it.
+- if (surface_for_popup_)
+- return true;
+-
+- zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get()));
+- if (!zxdg_toplevel_v6_) {
+- LOG(ERROR) << "Failed to create zxdg_toplevel";
+- return false;
+- }
+- zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
+- &zxdg_toplevel_v6_listener, this);
+- wl_surface_commit(surface);
+- return true;
++bool XDGSurfaceWrapperImpl::Initialize(bool with_toplevel) {
++ if (connection_->shell())
++ return InitializeStable(with_toplevel);
++ else if (connection_->shell_v6())
++ return InitializeV6(with_toplevel);
++ NOTREACHED() << "Wrong shell protocol";
++ return false;
+ }
+
+ void XDGSurfaceWrapperImpl::SetMaximized() {
+@@ -142,25 +77,25 @@ void XDGSurfaceWrapperImpl::SetMinimized() {
+
+ void XDGSurfaceWrapperImpl::SurfaceMove(WaylandConnection* connection) {
+ if (xdg_toplevel_) {
+- xdg_toplevel_move(xdg_toplevel_.get(), connection->seat(),
+- connection->serial());
++ xdg_toplevel_move(xdg_toplevel_.get(), connection_->seat(),
++ connection_->serial());
+ } else {
+ DCHECK(zxdg_toplevel_v6_);
+- zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection->seat(),
+- connection->serial());
++ zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection_->seat(),
++ connection_->serial());
+ }
+ }
+
+ void XDGSurfaceWrapperImpl::SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) {
+ if (xdg_toplevel_) {
+- xdg_toplevel_resize(xdg_toplevel_.get(), connection->seat(),
+- connection->serial(),
++ xdg_toplevel_resize(xdg_toplevel_.get(), connection_->seat(),
++ connection_->serial(),
+ wl::IdentifyDirection(*connection, hittest));
+ } else {
+ DCHECK(zxdg_toplevel_v6_);
+- zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection->seat(),
+- connection->serial(),
++ zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection_->seat(),
++ connection_->serial(),
+ wl::IdentifyDirection(*connection, hittest));
+ }
+ }
+@@ -317,4 +252,84 @@ xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
+ return xdg_surface_.get();
+ }
+
++bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
++ static const xdg_surface_listener xdg_surface_listener = {
++ &XDGSurfaceWrapperImpl::ConfigureStable,
++ };
++ static const xdg_toplevel_listener xdg_toplevel_listener = {
++ &XDGSurfaceWrapperImpl::ConfigureTopLevelStable,
++ &XDGSurfaceWrapperImpl::CloseTopLevelStable,
++ };
++
++ // if this surface is created for the popup role, mark that it requires
++ // configuration acknowledgement on each configure event.
++ surface_for_popup_ = !with_toplevel;
++
++ xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection_->shell(),
++ wayland_window_->surface()));
++ if (!xdg_surface_) {
++ LOG(ERROR) << "Failed to create xdg_surface";
++ return false;
++ }
++ xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
++ // XDGPopup requires a separate surface to be created, so this is just a
++ // request to get an xdg_surface for it.
++ if (surface_for_popup_) {
++ connection_->ScheduleFlush();
++ return true;
++ }
++
++ xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get()));
++ if (!xdg_toplevel_) {
++ LOG(ERROR) << "Failed to create xdg_toplevel";
++ return false;
++ }
++ xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
++ wl_surface_commit(wayland_window_->surface());
++
++ connection_->ScheduleFlush();
++ return true;
++}
++
++bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
++ static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
++ &XDGSurfaceWrapperImpl::ConfigureV6,
++ };
++ static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
++ &XDGSurfaceWrapperImpl::ConfigureTopLevelV6,
++ &XDGSurfaceWrapperImpl::CloseTopLevelV6,
++ };
++
++ // if this surface is created for the popup role, mark that it requires
++ // configuration acknowledgement on each configure event.
++ surface_for_popup_ = !with_toplevel;
++
++ zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
++ connection_->shell_v6(), wayland_window_->surface()));
++ if (!zxdg_surface_v6_) {
++ LOG(ERROR) << "Failed to create zxdg_surface";
++ return false;
++ }
++ zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
++ &zxdg_surface_v6_listener, this);
++ // XDGPopupV6 requires a separate surface to be created, so this is just a
++ // request to get an xdg_surface for it.
++ if (surface_for_popup_) {
++ connection_->ScheduleFlush();
++ return true;
++ }
++
++ zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get()));
++ if (!zxdg_toplevel_v6_) {
++ LOG(ERROR) << "Failed to create zxdg_toplevel";
++ return false;
++ }
++ zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
++ &zxdg_toplevel_v6_listener, this);
++ wl_surface_commit(wayland_window_->surface());
++
++ connection_->ScheduleFlush();
++ return true;
++}
++
+ } // namespace ui
+diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+index e14956ebe3e7..b34f4b2281ec 100644
+--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
++++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+@@ -7,11 +7,10 @@
+
+ #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+
++#include "base/macros.h"
+ #include "base/strings/string16.h"
+ #include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+-#include "base/macros.h"
+-
+ namespace gfx {
+ class Rect;
+ }
+@@ -24,15 +23,12 @@ class WaylandWindow;
+ // Surface wrapper for xdg-shell stable and xdg-shell-unstable-v6
+ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
+ public:
+- XDGSurfaceWrapperImpl(WaylandWindow* wayland_window);
++ XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
++ WaylandConnection* connection);
+ ~XDGSurfaceWrapperImpl() override;
+
+- bool InitializeV6(WaylandConnection* connection,
+- wl_surface* surface,
+- bool with_toplevel = true);
+- bool InitializeStable(WaylandConnection* connection,
+- wl_surface* surface,
+- bool with_toplevel = true);
++ // ShellSurfaceWrapper overrides:
++ bool Initialize(bool with_toplevel) override;
+ void SetMaximized() override;
+ void UnSetMaximized() override;
+ void SetFullscreen() override;
+@@ -76,8 +72,17 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
+ zxdg_surface_v6* zxdg_surface() const;
+
+ private:
+- WaylandWindow* wayland_window_;
+- uint32_t pending_configure_serial_;
++ // Initializes using XDG Shell Stable protocol.
++ bool InitializeStable(bool with_toplevel);
++ // Initializes using XDG Shell V6 protocol.
++ bool InitializeV6(bool with_toplevel);
++
++ // Non-owing WaylandWindow that uses this surface wrapper.
++ WaylandWindow* const wayland_window_;
++ WaylandConnection* const connection_;
++
++ uint32_t pending_configure_serial_ = 0;
++
+ wl::Object<zxdg_surface_v6> zxdg_surface_v6_;
+ wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
+ wl::Object<struct xdg_surface> xdg_surface_;
+--
+2.24.1
+
diff --git a/0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch b/0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch
new file mode 100644
index 000000000000..5962d788740d
--- /dev/null
+++ b/0002-ozone-Wayland-Add-WaylandWindow-factory-method.patch
@@ -0,0 +1,646 @@
+From 53e253ee8daeff98359dfd1fd8f9374879e6aaa5 Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Fri, 6 Dec 2019 19:55:37 +0000
+Subject: [PATCH 2/9] ozone/Wayland: Add WaylandWindow factory method.
+
+To hide future different types of WaylandWindows (WaylandSurface,
+WaylandPopup and WaylandSubsurface), add a factory method, which
+will handle everything on its own.
+
+Also make unittests and OzonePlatformWayland use this factory.
+
+Bug: 1028919
+Change-Id: I745f99024b6657be3686ee92b0baf4c93f08b9a7
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954470
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Reviewed-by: Michael Spang <spang@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#722586}
+---
+ ui/ozone/platform/wayland/BUILD.gn | 1 +
+ .../wayland/host/wayland_pointer_unittest.cc | 5 +-
+ .../wayland/host/wayland_screen_unittest.cc | 5 +-
+ .../platform/wayland/host/wayland_window.cc | 132 +++++++++---------
+ .../platform/wayland/host/wayland_window.h | 17 ++-
+ .../wayland/host/wayland_window_factory.cc | 26 ++++
+ .../host/wayland_window_manager_unittests.cc | 8 +-
+ .../wayland/host/wayland_window_unittest.cc | 120 ++++++++--------
+ .../wayland/ozone_platform_wayland.cc | 6 +-
+ .../platform/wayland/test/wayland_test.cc | 4 +-
+ .../wayland_buffer_manager_unittest.cc | 6 +-
+ 11 files changed, 184 insertions(+), 146 deletions(-)
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_window_factory.cc
+
+diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
+index 9c2cbc52500b..a9c0302f162f 100644
+--- a/ui/ozone/platform/wayland/BUILD.gn
++++ b/ui/ozone/platform/wayland/BUILD.gn
+@@ -95,6 +95,7 @@ source_set("wayland") {
+ "host/wayland_touch.h",
+ "host/wayland_window.cc",
+ "host/wayland_window.h",
++ "host/wayland_window_factory.cc",
+ "host/wayland_window_manager.cc",
+ "host/wayland_window_manager.h",
+ "host/wayland_window_observer.cc",
+diff --git a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+index be9cd942d6ec..b96f2e6f73f9 100644
+--- a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
++++ b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+@@ -72,14 +72,15 @@ TEST_P(WaylandPointerTest, Enter) {
+
+ TEST_P(WaylandPointerTest, Leave) {
+ MockPlatformWindowDelegate other_delegate;
+- WaylandWindow other_window(&other_delegate, connection_.get());
+ gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget;
+ EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_))
+ .WillOnce(SaveArg<0>(&other_widget));
++
+ PlatformWindowInitProperties properties;
+ properties.bounds = gfx::Rect(0, 0, 10, 10);
+ properties.type = PlatformWindowType::kWindow;
+- ASSERT_TRUE(other_window.Initialize(std::move(properties)));
++ auto other_window = WaylandWindow::Create(&other_delegate, connection_.get(),
++ std::move(properties));
+ ASSERT_NE(other_widget, gfx::kNullAcceleratedWidget);
+
+ Sync();
+diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+index e1e3cc823ac3..9198aa88e054 100644
+--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
++++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+@@ -89,13 +89,12 @@ class WaylandScreenTest : public WaylandTest {
+ PlatformWindowType window_type,
+ gfx::AcceleratedWidget parent_widget,
+ MockPlatformWindowDelegate* delegate) {
+- auto window = std::make_unique<WaylandWindow>(delegate, connection_.get());
+ PlatformWindowInitProperties properties;
+ properties.bounds = bounds;
+ properties.type = window_type;
+ properties.parent_widget = parent_widget;
+- EXPECT_TRUE(window->Initialize(std::move(properties)));
+- return window;
++ return WaylandWindow::Create(delegate, connection_.get(),
++ std::move(properties));
+ }
+
+ void UpdateOutputGeometry(wl_resource* output_resource,
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index 95c6e5a46b3e..da9a4cb368b8 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -85,72 +85,6 @@ WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) {
+ wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface)));
+ }
+
+-bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+- // 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()));
+- if (!surface_) {
+- LOG(ERROR) << "Failed to create wl_surface";
+- return false;
+- }
+- wl_surface_set_user_data(surface_.get(), this);
+- AddSurfaceListener();
+-
+- connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
+-
+- ui::PlatformWindowType ui_window_type = properties.type;
+- switch (ui_window_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.
+- if (!parent_window_) {
+- LOG(ERROR) << "Failed to get a parent window for this popup";
+- return false;
+- }
+-
+- 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
+- // parents and pop up when the browser receives a notification.
+- CreateShellPopup();
+- break;
+- case ui::PlatformWindowType::kTooltip:
+- // Tooltips subsurfaces are created on demand, upon ::Show calls.
+- is_tooltip_ = true;
+- break;
+- case ui::PlatformWindowType::kWindow:
+- case ui::PlatformWindowType::kBubble:
+- case ui::PlatformWindowType::kDrag:
+- // TODO(msisov): Figure out what kind of surface we need to create for
+- // bubble and drag windows.
+- CreateShellSurface();
+- break;
+- }
+-
+- if (shell_surface_ && !properties.wm_class_class.empty())
+- shell_surface_->SetAppId(properties.wm_class_class);
+-
+- connection_->ScheduleFlush();
+-
+- PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+- delegate_->OnAcceleratedWidgetAvailable(GetWidget());
+-
+- // Will do nothing for popups because they have got their scale above.
+- UpdateBufferScale(false);
+-
+- MaybeUpdateOpaqueRegion();
+- return true;
+-}
+-
+ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
+ DCHECK(connection_->wayland_output_manager());
+ const auto* screen = connection_->wayland_output_manager()->wayland_screen();
+@@ -792,6 +726,72 @@ void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {
+ connection_->ResetPointerFlags();
+ }
+
++bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
++ // 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()));
++ if (!surface_) {
++ LOG(ERROR) << "Failed to create wl_surface";
++ return false;
++ }
++ wl_surface_set_user_data(surface_.get(), this);
++ AddSurfaceListener();
++
++ connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
++
++ ui::PlatformWindowType ui_window_type = properties.type;
++ switch (ui_window_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.
++ if (!parent_window_) {
++ LOG(ERROR) << "Failed to get a parent window for this popup";
++ return false;
++ }
++
++ 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
++ // parents and pop up when the browser receives a notification.
++ CreateShellPopup();
++ break;
++ case ui::PlatformWindowType::kTooltip:
++ // Tooltips subsurfaces are created on demand, upon ::Show calls.
++ is_tooltip_ = true;
++ break;
++ case ui::PlatformWindowType::kWindow:
++ case ui::PlatformWindowType::kBubble:
++ case ui::PlatformWindowType::kDrag:
++ // TODO(msisov): Figure out what kind of surface we need to create for
++ // bubble and drag windows.
++ CreateShellSurface();
++ break;
++ }
++
++ if (shell_surface_ && !properties.wm_class_class.empty())
++ shell_surface_->SetAppId(properties.wm_class_class);
++
++ connection_->ScheduleFlush();
++
++ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
++ delegate_->OnAcceleratedWidgetAvailable(GetWidget());
++
++ // Will do nothing for popups because they have got their scale above.
++ UpdateBufferScale(false);
++
++ MaybeUpdateOpaqueRegion();
++ return true;
++}
++
+ void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
+ SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_));
+ }
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
+index 4233216d7a6f..b8cdc991e30e 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.h
++++ b/ui/ozone/platform/wayland/host/wayland_window.h
+@@ -40,13 +40,16 @@ class WaylandWindow : public PlatformWindow,
+ public WmMoveResizeHandler,
+ public WmDragHandler {
+ public:
+- WaylandWindow(PlatformWindowDelegate* delegate,
+- WaylandConnection* connection);
+ ~WaylandWindow() override;
+
+- static WaylandWindow* FromSurface(wl_surface* surface);
++ // A factory method that can create any of the derived types of WaylandWindow
++ // (WaylandSurface, WaylandPopup and WaylandSubsurface).
++ static std::unique_ptr<WaylandWindow> Create(
++ PlatformWindowDelegate* delegate,
++ WaylandConnection* connection,
++ PlatformWindowInitProperties properties);
+
+- bool Initialize(PlatformWindowInitProperties properties);
++ static WaylandWindow* FromSurface(wl_surface* surface);
+
+ // Updates the surface buffer scale of the window. Top level windows take
+ // scale from the output attached to either their current display or the
+@@ -168,6 +171,12 @@ class WaylandWindow : public PlatformWindow,
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale);
+
++ WaylandWindow(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection);
++
++ // Initializes the WaylandWindow with supplied properties.
++ bool Initialize(PlatformWindowInitProperties properties);
++
+ void SetBoundsDip(const gfx::Rect& bounds_dip);
+ void SetBufferScale(int32_t scale, bool update_bounds);
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+new file mode 100644
+index 000000000000..19da59357d55
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+@@ -0,0 +1,26 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "ui/ozone/platform/wayland/host/wayland_window.h"
++
++#include <memory>
++
++#include "ui/ozone/platform/wayland/host/wayland_window.h"
++
++namespace ui {
++
++// static
++std::unique_ptr<WaylandWindow> WaylandWindow::Create(
++ PlatformWindowDelegate* delegate,
++ WaylandConnection* connection,
++ PlatformWindowInitProperties properties) {
++ // TODO(msisov): once WaylandWindow becomes a base class, add switch cases to
++ // create different Wayland windows.
++ std::unique_ptr<WaylandWindow> window(
++ new WaylandWindow(delegate, connection));
++ return window->Initialize(std::move(properties)) ? std::move(window)
++ : nullptr;
++}
++
++} // namespace ui
+\ No newline at end of file
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
+index 737c7cdd25d9..64a387723560 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
+@@ -36,12 +36,8 @@ class WaylandWindowManagerTest : public WaylandTest {
+ PlatformWindowInitProperties properties;
+ properties.bounds = bounds;
+ properties.type = type;
+-
+- std::unique_ptr<WaylandWindow> window =
+- std::make_unique<WaylandWindow>(delegate, connection_.get());
+-
+- EXPECT_TRUE(window->Initialize(std::move(properties)));
+- return window;
++ return WaylandWindow::Create(delegate, connection_.get(),
++ std::move(properties));
+ }
+
+ WaylandWindowManager* manager_ = nullptr;
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+index f8dc4429c073..b03a28daadf2 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+@@ -150,20 +150,19 @@ class WaylandWindowTest : public WaylandTest {
+ return result;
+ }
+
+- bool CreateWaylandWindowWithParams(PlatformWindowType type,
+- gfx::AcceleratedWidget parent_widget,
+- const gfx::Rect bounds,
+- MockPlatformWindowDelegate* delegate,
+- std::unique_ptr<WaylandWindow>* window) {
++ std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams(
++ PlatformWindowType type,
++ gfx::AcceleratedWidget parent_widget,
++ const gfx::Rect bounds,
++ MockPlatformWindowDelegate* delegate) {
+ PlatformWindowInitProperties properties;
+ // TODO(msisov): use a fancy method to calculate position of a popup window.
+ properties.bounds = bounds;
+ properties.type = type;
+ properties.parent_widget = parent_widget;
+
+- *window = std::make_unique<WaylandWindow>(delegate, connection_.get());
+-
+- return (*window)->Initialize(std::move(properties));
++ return WaylandWindow::Create(delegate, connection_.get(),
++ std::move(properties));
+ }
+
+ void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) {
+@@ -736,27 +735,29 @@ TEST_P(WaylandWindowTest, CanCreateMenuWindow) {
+ ASSERT_TRUE(connection_->pointer() && connection_->touch());
+ window_->SetPointerFocus(true);
+
+- std::unique_ptr<WaylandWindow> menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+- gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window));
++ gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+
+ Sync();
+
+ window_->SetPointerFocus(false);
+ window_->set_touch_focus(false);
+
+- EXPECT_FALSE(CreateWaylandWindowWithParams(
++ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+- gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window));
++ gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
++ EXPECT_FALSE(menu_window);
+
+ Sync();
+
+ window_->set_touch_focus(true);
+
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+- gfx::Rect(0, 0, 10, 10), &menu_window_delegate, &menu_window));
++ gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+
+ Sync();
+ }
+@@ -767,29 +768,30 @@ TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) {
+ EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_))
+ .WillOnce(SaveArg<0>(&menu_window_widget));
+
+- std::unique_ptr<WaylandWindow> menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10),
+- &menu_window_delegate, &menu_window));
++ &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+ ASSERT_NE(menu_window_widget, gfx::kNullAcceleratedWidget);
+
+ Sync();
+
+ MockPlatformWindowDelegate nested_menu_window_delegate;
+- std::unique_ptr<WaylandWindow> nested_menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
+- PlatformWindowType::kMenu, menu_window_widget, gfx::Rect(20, 0, 10, 10),
+- &nested_menu_window_delegate, &nested_menu_window));
++ std::unique_ptr<WaylandWindow> nested_menu_window =
++ CreateWaylandWindowWithParams(
++ PlatformWindowType::kMenu, menu_window_widget,
++ gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate);
++ EXPECT_TRUE(nested_menu_window);
+
+ Sync();
+ }
+
+ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNonNested) {
+ MockPlatformWindowDelegate menu_window_delegate;
+- std::unique_ptr<WaylandWindow> menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10),
+- &menu_window_delegate, &menu_window));
++ &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+
+ wl_seat_send_capabilities(server_.seat()->resource(),
+ WL_SEAT_CAPABILITY_POINTER);
+@@ -812,18 +814,19 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) {
+ EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_))
+ .WillOnce(SaveArg<0>(&menu_window_widget));
+
+- std::unique_ptr<WaylandWindow> menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10),
+- &menu_window_delegate, &menu_window));
++ &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+
+ Sync();
+
+ MockPlatformWindowDelegate nested_menu_window_delegate;
+- std::unique_ptr<WaylandWindow> nested_menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
+- PlatformWindowType::kMenu, menu_window_widget, gfx::Rect(20, 0, 10, 10),
+- &nested_menu_window_delegate, &nested_menu_window));
++ std::unique_ptr<WaylandWindow> nested_menu_window =
++ CreateWaylandWindowWithParams(
++ PlatformWindowType::kMenu, menu_window_widget,
++ gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate);
++ EXPECT_TRUE(nested_menu_window);
+
+ Sync();
+
+@@ -903,10 +906,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+ MockPlatformWindowDelegate menu_window_delegate;
+ gfx::Rect menu_window_bounds(gfx::Point(440, 76),
+ menu_window_positioner.size);
+- std::unique_ptr<WaylandWindow> menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, toplevel_window->GetWidget(),
+- menu_window_bounds, &menu_window_delegate, &menu_window));
++ menu_window_bounds, &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+
+ Sync();
+
+@@ -924,10 +927,11 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+ MockPlatformWindowDelegate nested_menu_window_delegate;
+ gfx::Rect nested_menu_window_bounds(gfx::Point(723, 156),
+ nested_menu_window_positioner.size);
+- std::unique_ptr<WaylandWindow> nested_menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
+- PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds,
+- &nested_menu_window_delegate, &nested_menu_window));
++ std::unique_ptr<WaylandWindow> nested_menu_window =
++ CreateWaylandWindowWithParams(
++ PlatformWindowType::kMenu, menu_window_widget,
++ nested_menu_window_bounds, &nested_menu_window_delegate);
++ EXPECT_TRUE(nested_menu_window);
+
+ Sync();
+
+@@ -985,9 +989,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+ // side. Thus, we have to check that anchor rect is correct.
+ nested_menu_window.reset();
+ nested_menu_window_bounds.set_origin({723, 258});
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ nested_menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds,
+- &nested_menu_window_delegate, &nested_menu_window));
++ &nested_menu_window_delegate);
++ EXPECT_TRUE(nested_menu_window);
+
+ Sync();
+
+@@ -1050,9 +1055,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+ window_->SetBounds(gfx::Rect(0, 0, 2493, 1413));
+
+ menu_window_bounds.set_origin({2206, 67});
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, toplevel_window->GetWidget(),
+- menu_window_bounds, &menu_window_delegate, &menu_window));
++ menu_window_bounds, &menu_window_delegate);
++ EXPECT_TRUE(menu_window);
+
+ Sync();
+
+@@ -1066,9 +1072,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+ Sync();
+
+ nested_menu_window_bounds.set_origin({1905, 147});
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ nested_menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds,
+- &nested_menu_window_delegate, &nested_menu_window));
++ &nested_menu_window_delegate);
++ EXPECT_TRUE(nested_menu_window);
+
+ Sync();
+
+@@ -1096,9 +1103,10 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+
+ nested_menu_window.reset();
+
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ nested_menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, menu_window_widget, nested_menu_window_bounds,
+- &nested_menu_window_delegate, &nested_menu_window));
++ &nested_menu_window_delegate);
++ EXPECT_TRUE(nested_menu_window);
+
+ Sync();
+
+@@ -1174,10 +1182,10 @@ TEST_P(WaylandWindowTest, TooltipSimpleParent) {
+ VerifyAndClearExpectations();
+
+ gfx::Rect tooltip_window_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
+- std::unique_ptr<WaylandWindow> tooltip_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> tooltip_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kTooltip, window_->GetWidget(), tooltip_window_bounds,
+- &delegate_, &tooltip_window));
++ &delegate_);
++ EXPECT_TRUE(tooltip_window);
+
+ window_->SetPointerFocus(true);
+
+@@ -1199,18 +1207,18 @@ TEST_P(WaylandWindowTest, TooltipNestedParent) {
+ VerifyAndClearExpectations();
+
+ gfx::Rect menu_window_bounds(gfx::Point(10, 10), gfx::Size(100, 100));
+- std::unique_ptr<WaylandWindow> menu_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
+- &delegate_, &menu_window));
++ &delegate_);
++ EXPECT_TRUE(menu_window);
+
+ VerifyAndClearExpectations();
+
+ gfx::Rect tooltip_window_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
+- std::unique_ptr<WaylandWindow> tooltip_window;
+- EXPECT_TRUE(CreateWaylandWindowWithParams(
++ std::unique_ptr<WaylandWindow> tooltip_window = CreateWaylandWindowWithParams(
+ PlatformWindowType::kTooltip, menu_window->GetWidget(),
+- tooltip_window_bounds, &delegate_, &tooltip_window));
++ tooltip_window_bounds, &delegate_);
++ EXPECT_TRUE(tooltip_window);
+
+ VerifyAndClearExpectations();
+
+diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+index 541d9c4848d7..dbf880e9a0c1 100644
+--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
++++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+@@ -107,10 +107,8 @@ class OzonePlatformWayland : public OzonePlatform {
+ std::unique_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ PlatformWindowInitProperties properties) override {
+- auto window = std::make_unique<WaylandWindow>(delegate, connection_.get());
+- if (!window->Initialize(std::move(properties)))
+- return nullptr;
+- return std::move(window);
++ return WaylandWindow::Create(delegate, connection_.get(),
++ std::move(properties));
+ }
+
+ std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
+diff --git a/ui/ozone/platform/wayland/test/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc
+index 2bd8c38219c1..2543981d8c38 100644
+--- a/ui/ozone/platform/wayland/test/wayland_test.cc
++++ b/ui/ozone/platform/wayland/test/wayland_test.cc
+@@ -37,7 +37,6 @@ WaylandTest::WaylandTest()
+ buffer_manager_gpu_ = std::make_unique<WaylandBufferManagerGpu>();
+ surface_factory_ = std::make_unique<WaylandSurfaceFactory>(
+ connection_.get(), buffer_manager_gpu_.get());
+- window_ = std::make_unique<WaylandWindow>(&delegate_, connection_.get());
+ }
+
+ WaylandTest::~WaylandTest() {}
+@@ -52,7 +51,8 @@ void WaylandTest::SetUp() {
+ PlatformWindowInitProperties properties;
+ properties.bounds = gfx::Rect(0, 0, 800, 600);
+ properties.type = PlatformWindowType::kWindow;
+- ASSERT_TRUE(window_->Initialize(std::move(properties)));
++ window_ = WaylandWindow::Create(&delegate_, connection_.get(),
++ std::move(properties));
+ ASSERT_NE(widget_, gfx::kNullAcceleratedWidget);
+
+ // Wait for the client to flush all pending requests from initialization.
+diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+index 21b0c3eefd9b..767f9354f6da 100644
+--- a/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
++++ b/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+@@ -189,12 +189,12 @@ class WaylandBufferManagerTest : public WaylandTest {
+
+ std::unique_ptr<WaylandWindow> CreateWindow() {
+ testing::Mock::VerifyAndClearExpectations(&delegate_);
+- auto new_window =
+- std::make_unique<WaylandWindow>(&delegate_, connection_.get());
+ PlatformWindowInitProperties properties;
+ properties.bounds = gfx::Rect(0, 0, 800, 600);
+ properties.type = PlatformWindowType::kWindow;
+- EXPECT_TRUE(new_window->Initialize(std::move(properties)));
++ auto new_window = WaylandWindow::Create(&delegate_, connection_.get(),
++ std::move(properties));
++ EXPECT_TRUE(new_window);
+
+ Sync();
+
+--
+2.24.1
+
diff --git a/0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch b/0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch
new file mode 100644
index 000000000000..14d5143a81e3
--- /dev/null
+++ b/0003-ozone-Wayland-move-bounds-translation-util-to-utilit.patch
@@ -0,0 +1,137 @@
+From d7680c81c95c4609bf4ffbad05656a09d589a382 Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Fri, 6 Dec 2019 19:49:45 +0000
+Subject: [PATCH 3/9] ozone/Wayland: move bounds translation util to utilities.
+
+Just moving the translation helper method to utilities.
+
+Bug: 1028919
+Change-Id: I6e60bcdf804e4aaff9cb39d437e4302af2ed3fd2
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1953710
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Reviewed-by: Michael Spang <spang@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#722582}
+---
+ .../platform/wayland/common/wayland_util.cc | 14 ++++++++++
+ .../platform/wayland/common/wayland_util.h | 8 ++++++
+ .../platform/wayland/host/wayland_window.cc | 27 +++----------------
+ 3 files changed, 26 insertions(+), 23 deletions(-)
+
+diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc
+index 0201f689e90d..e0430b860adf 100644
+--- a/ui/ozone/platform/wayland/common/wayland_util.cc
++++ b/ui/ozone/platform/wayland/common/wayland_util.cc
+@@ -141,4 +141,18 @@ void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents) {
+ contents->insert(contents->end(), buffer, buffer + length);
+ }
+
++gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
++ const gfx::Rect& parent_bounds) {
++ return gfx::Rect(
++ (child_bounds.origin() - parent_bounds.origin().OffsetFromOrigin()),
++ child_bounds.size());
++}
++
++gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
++ const gfx::Rect& parent_bounds) {
++ return gfx::Rect(
++ (child_bounds.origin() + parent_bounds.origin().OffsetFromOrigin()),
++ child_bounds.size());
++}
++
+ } // namespace wl
+diff --git a/ui/ozone/platform/wayland/common/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h
+index 368f3d9a9427..48332e059da0 100644
+--- a/ui/ozone/platform/wayland/common/wayland_util.h
++++ b/ui/ozone/platform/wayland/common/wayland_util.h
+@@ -13,6 +13,7 @@
+ #include "base/containers/flat_map.h"
+ #include "base/files/scoped_file.h"
+ #include "base/macros.h"
++#include "ui/gfx/geometry/rect.h"
+ #include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+ class SkBitmap;
+@@ -50,6 +51,13 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer);
+ // Helper function to read data from a file.
+ void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents);
+
++// Translates bounds relative to top level window to specified parent.
++gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
++ const gfx::Rect& parent_bounds);
++// Translates bounds relative to parent window to top level window.
++gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
++ const gfx::Rect& parent_bounds);
++
+ } // namespace wl
+
+ #endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index da9a4cb368b8..709fb681f7d9 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -16,6 +16,7 @@
+ #include "ui/events/event_utils.h"
+ #include "ui/events/ozone/events_ozone.h"
+ #include "ui/gfx/geometry/point_f.h"
++#include "ui/ozone/platform/wayland/common/wayland_util.h"
+ #include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+ #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+ #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+@@ -28,26 +29,6 @@
+
+ namespace ui {
+
+-namespace {
+-
+-// Translates bounds relative to top level window to specified parent.
+-gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
+- const gfx::Rect& parent_bounds) {
+- return gfx::Rect(gfx::Point(child_bounds.x() - parent_bounds.x(),
+- child_bounds.y() - parent_bounds.y()),
+- child_bounds.size());
+-}
+-
+-// Translates bounds relative to parent window to top level window.
+-gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
+- const gfx::Rect& parent_bounds) {
+- return gfx::Rect(gfx::Point(child_bounds.x() + parent_bounds.x(),
+- child_bounds.y() + parent_bounds.y()),
+- child_bounds.size());
+-}
+-
+-} // namespace
+-
+ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection)
+ : delegate_(delegate),
+@@ -177,7 +158,7 @@ void WaylandWindow::CreateAndShowTooltipSubSurface() {
+ const auto parent_bounds_dip =
+ gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale_);
+ auto new_bounds_dip =
+- TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip);
++ wl::TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip);
+ auto bounds_px =
+ gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_);
+
+@@ -671,7 +652,7 @@ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
+ // window, which automatically becomes the same as relative to an origin of
+ // a display.
+ new_bounds_dip = gfx::ScaleToRoundedRect(
+- TranslateBoundsToTopLevelCoordinates(
++ wl::TranslateBoundsToTopLevelCoordinates(
+ gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_),
+ parent_window_->GetBounds()),
+ 1.0 / buffer_scale_);
+@@ -962,7 +943,7 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
+ 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);
++ wl::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
+--
+2.24.1
+
diff --git a/0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch b/0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch
new file mode 100644
index 000000000000..2e6b2a4b770c
--- /dev/null
+++ b/0004-ozone-wayland-Fix-regression-with-hiding-nested-wind.patch
@@ -0,0 +1,33 @@
+From 738a0d76c3102509e052927e49f978b197bc3a3c Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Fri, 6 Dec 2019 19:19:30 +0000
+Subject: [PATCH 4/9] ozone/wayland: Fix regression with hiding nested windows.
+
+It must be non-tooltip that closes children windows.
+
+Bug: 1028046
+Change-Id: I9b5212873cb2c1a4179a28e915edd5fe84b29c5e
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954483
+Reviewed-by: Michael Spang <spang@chromium.org>
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Cr-Commit-Position: refs/heads/master@{#722560}
+---
+ ui/ozone/platform/wayland/host/wayland_window.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index 709fb681f7d9..1f8cc423d4aa 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -247,7 +247,7 @@ void WaylandWindow::Show(bool inactive) {
+ }
+
+ void WaylandWindow::Hide() {
+- if (!is_tooltip_) {
++ if (is_tooltip_) {
+ tooltip_subsurface_.reset();
+ } else {
+ if (child_window_)
+--
+2.24.1
+
diff --git a/0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch b/0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch
new file mode 100644
index 000000000000..2307bfec56ac
--- /dev/null
+++ b/0005-ozone-Wayland-extract-toplevel-surface-methods-into-.patch
@@ -0,0 +1,1424 @@
+From 0bbc15f0d57b4bcbd389776b3bee492a75fd60a5 Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Fri, 6 Dec 2019 20:31:04 +0000
+Subject: [PATCH 5/9] ozone/Wayland: extract toplevel surface methods into
+ WaylandSurface.
+
+WaylandWindow handles too many things and confuses developers that
+are not familiar with it. To make things better, extract
+surface methods into WaylandSurface.
+
+This change does not bring any functional changes except removed
+is_active() method that was only used by tests. Instead, tests
+just rely on the PlatformWindowDelegate::OnActivationChanged calls.
+
+Test: ozone_unittests
+Bug: 1028919
+Change-Id: Ia58577f86d8e31ec93b113d887b34166fbe19cf0
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1954478
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Reviewed-by: Michael Spang <spang@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#722592}
+---
+ ui/ozone/platform/wayland/BUILD.gn | 2 +
+ .../platform/wayland/host/wayland_surface.cc | 348 ++++++++++++++++++
+ .../platform/wayland/host/wayland_surface.h | 114 ++++++
+ .../platform/wayland/host/wayland_window.cc | 346 ++---------------
+ .../platform/wayland/host/wayland_window.h | 110 ++----
+ .../wayland/host/wayland_window_factory.cc | 31 +-
+ .../wayland/host/wayland_window_unittest.cc | 14 +-
+ .../wayland/host/xdg_popup_wrapper_impl.cc | 9 +-
+ 8 files changed, 572 insertions(+), 402 deletions(-)
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_surface.cc
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_surface.h
+
+diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
+index a9c0302f162f..b6059c7d9962 100644
+--- a/ui/ozone/platform/wayland/BUILD.gn
++++ b/ui/ozone/platform/wayland/BUILD.gn
+@@ -91,6 +91,8 @@ source_set("wayland") {
+ "host/wayland_shm.h",
+ "host/wayland_shm_buffer.cc",
+ "host/wayland_shm_buffer.h",
++ "host/wayland_surface.cc",
++ "host/wayland_surface.h",
+ "host/wayland_touch.cc",
+ "host/wayland_touch.h",
+ "host/wayland_window.cc",
+diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
+new file mode 100644
+index 000000000000..cfd4349db885
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
+@@ -0,0 +1,348 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "ui/ozone/platform/wayland/host/wayland_surface.h"
++
++#include "ui/base/dragdrop/drag_drop_types.h"
++#include "ui/base/dragdrop/os_exchange_data.h"
++#include "ui/base/hit_test.h"
++#include "ui/gfx/native_widget_types.h"
++#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
++#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
++#include "ui/ozone/platform/wayland/host/wayland_connection.h"
++#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
++
++namespace ui {
++
++WaylandSurface::WaylandSurface(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection)
++ : WaylandWindow(delegate, connection),
++ state_(PlatformWindowState::kNormal),
++ pending_state_(PlatformWindowState::kUnknown) {
++ // Set a class property key, which allows |this| to be used for interactive
++ // events, e.g. move or resize.
++ SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
++
++ // Set a class property key, which allows |this| to be used for drag action.
++ SetWmDragHandler(this, this);
++}
++
++WaylandSurface::~WaylandSurface() {
++ if (drag_closed_callback_) {
++ std::move(drag_closed_callback_)
++ .Run(DragDropTypes::DragOperation::DRAG_NONE);
++ }
++}
++
++void WaylandSurface::CreateShellSurface() {
++ ShellObjectFactory factory;
++ shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this);
++ if (!shell_surface_)
++ CHECK(false) << "Failed to initialize Wayland shell surface";
++}
++
++void WaylandSurface::ApplyPendingBounds() {
++ if (pending_bounds_dip_.IsEmpty())
++ return;
++ DCHECK(shell_surface_);
++
++ SetBoundsDip(pending_bounds_dip_);
++ shell_surface_->SetWindowGeometry(pending_bounds_dip_);
++ pending_bounds_dip_ = gfx::Rect();
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::DispatchHostWindowDragMovement(
++ int hittest,
++ const gfx::Point& pointer_location_in_px) {
++ DCHECK(shell_surface_);
++
++ connection()->ResetPointerFlags();
++ if (hittest == HTCAPTION)
++ shell_surface_->SurfaceMove(connection());
++ else
++ shell_surface_->SurfaceResize(connection(), hittest);
++
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::StartDrag(const ui::OSExchangeData& data,
++ int operation,
++ gfx::NativeCursor cursor,
++ base::OnceCallback<void(int)> callback) {
++ DCHECK(!drag_closed_callback_);
++ drag_closed_callback_ = std::move(callback);
++ connection()->StartDrag(data, operation);
++}
++
++void WaylandSurface::Show(bool inactive) {
++ set_keyboard_focus(true);
++ // TODO(msisov): recreate |shell_surface_| on show calls.
++}
++
++void WaylandSurface::Hide() {
++ // TODO(msisov): destroy |shell_surface_| on hide calls.
++}
++
++bool WaylandSurface::IsVisible() const {
++ // X and Windows return true if the window is minimized. For consistency, do
++ // the same.
++ return !!shell_surface_ || IsMinimized();
++}
++
++void WaylandSurface::SetTitle(const base::string16& title) {
++ DCHECK(shell_surface_);
++ shell_surface_->SetTitle(title);
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::ToggleFullscreen() {
++ DCHECK(shell_surface_);
++
++ // There are some cases, when Chromium triggers a fullscreen state change
++ // before the surface is activated. In such cases, Wayland may ignore state
++ // changes and such flags as --kiosk or --start-fullscreen will be ignored.
++ // To overcome this, set a pending state, and once the surface is activated,
++ // trigger the change.
++ if (!is_active_) {
++ DCHECK(!IsFullscreen());
++ pending_state_ = PlatformWindowState::kFullScreen;
++ return;
++ }
++
++ // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
++ // if shell_surface_set_fullscreen() is not provided with wl_output, it's up
++ // to the compositor to choose which display will be used to map this surface.
++ if (!IsFullscreen()) {
++ // Fullscreen state changes have to be handled manually and then checked
++ // against configuration events, which come from a compositor. The reason
++ // of manually changing the |state_| is that the compositor answers about
++ // state changes asynchronously, which leads to a wrong return value in
++ // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media
++ // files can never be set to fullscreen.
++ state_ = PlatformWindowState::kFullScreen;
++ shell_surface_->SetFullscreen();
++ } else {
++ // Check the comment above. If it's not handled synchronously, media files
++ // may not leave the fullscreen mode.
++ state_ = PlatformWindowState::kUnknown;
++ shell_surface_->UnSetFullscreen();
++ }
++
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::Maximize() {
++ DCHECK(shell_surface_);
++
++ if (IsFullscreen())
++ ToggleFullscreen();
++
++ shell_surface_->SetMaximized();
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::Minimize() {
++ DCHECK(shell_surface_);
++ DCHECK(!is_minimizing_);
++ // Wayland doesn't explicitly say if a window is minimized. Instead, it
++ // notifies that the window is not activated. But there are many cases, when
++ // the window is not minimized and deactivated. In order to properly record
++ // the minimized state, mark this window as being minimized. And as soon as a
++ // configuration event comes, check if the window has been deactivated and has
++ // |is_minimizing_| set.
++ is_minimizing_ = true;
++ shell_surface_->SetMinimized();
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::Restore() {
++ DCHECK(shell_surface_);
++
++ // Unfullscreen the window if it is fullscreen.
++ if (IsFullscreen())
++ ToggleFullscreen();
++
++ shell_surface_->UnSetMaximized();
++ connection()->ScheduleFlush();
++}
++
++PlatformWindowState WaylandSurface::GetPlatformWindowState() const {
++ return state_;
++}
++
++void WaylandSurface::SizeConstraintsChanged() {
++ // Size constraints only make sense for normal windows.
++ if (!shell_surface_)
++ return;
++
++ DCHECK(delegate());
++ auto min_size = delegate()->GetMinimumSizeForWindow();
++ auto max_size = delegate()->GetMaximumSizeForWindow();
++
++ if (min_size.has_value())
++ shell_surface_->SetMinSize(min_size->width(), min_size->height());
++ if (max_size.has_value())
++ shell_surface_->SetMaxSize(max_size->width(), max_size->height());
++
++ connection()->ScheduleFlush();
++}
++
++void WaylandSurface::HandleSurfaceConfigure(int32_t width,
++ int32_t height,
++ bool is_maximized,
++ bool is_fullscreen,
++ bool is_activated) {
++ // Propagate the window state information to the client.
++ PlatformWindowState old_state = state_;
++
++ // Ensure that manually handled state changes to fullscreen correspond to the
++ // configuration events from a compositor.
++ DCHECK_EQ(is_fullscreen, IsFullscreen());
++
++ // There are two cases, which must be handled for the minimized state.
++ // The first one is the case, when the surface goes into the minimized state
++ // (check comment in WaylandSurface::Minimize), and the second case is when
++ // the surface still has been minimized, but another configuration event with
++ // !is_activated comes. For this, check if the WaylandSurface has been
++ // minimized before and !is_activated is sent.
++ if ((is_minimizing_ || IsMinimized()) && !is_activated) {
++ is_minimizing_ = false;
++ state_ = PlatformWindowState::kMinimized;
++ } else if (is_fullscreen) {
++ // To ensure the |delegate()| is notified about state changes to fullscreen,
++ // assume the old_state is UNKNOWN (check comment in ToggleFullscreen).
++ old_state = PlatformWindowState::kUnknown;
++ DCHECK(state_ == PlatformWindowState::kFullScreen);
++ } else if (is_maximized) {
++ state_ = PlatformWindowState::kMaximized;
++ } else {
++ state_ = PlatformWindowState::kNormal;
++ }
++ const bool state_changed = old_state != state_;
++ const bool is_normal = !IsFullscreen() && !IsMaximized();
++
++ // Update state before notifying delegate.
++ const bool did_active_change = is_active_ != is_activated;
++ is_active_ = is_activated;
++
++ // Rather than call SetBounds here for every configure event, just save the
++ // most recent bounds, and have WaylandConnection call ApplyPendingBounds
++ // when it has finished processing events. We may get many configure events
++ // in a row during an interactive resize, and only the last one matters.
++ //
++ // Width or height set to 0 means that we should decide on width and height by
++ // ourselves, but we don't want to set them to anything else. Use restored
++ // bounds size or the current bounds iff the current state is normal (neither
++ // maximized nor fullscreen).
++ //
++ // Note: if the browser was started with --start-fullscreen and a user exits
++ // the fullscreen mode, wayland may set the width and height to be 1. Instead,
++ // explicitly set the bounds to the current desired ones or the previous
++ // bounds.
++ if (width > 1 && height > 1) {
++ pending_bounds_dip_ = gfx::Rect(0, 0, width, height);
++ } else if (is_normal) {
++ pending_bounds_dip_.set_size(
++ gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty()
++ ? GetBounds().size()
++ : GetRestoredBoundsInPixels().size(),
++
++ 1.0 / buffer_scale()));
++ }
++
++ if (state_changed) {
++ // The |restored_bounds_| are used when the window gets back to normal
++ // state after it went maximized or fullscreen. So we reset these if the
++ // window has just become normal and store the current bounds if it is
++ // either going out of normal state or simply changes the state and we don't
++ // have any meaningful value stored.
++ if (is_normal) {
++ SetRestoredBoundsInPixels({});
++ } else if (old_state == PlatformWindowState::kNormal ||
++ GetRestoredBoundsInPixels().IsEmpty()) {
++ SetRestoredBoundsInPixels(GetBounds());
++ }
++
++ delegate()->OnWindowStateChanged(state_);
++ }
++
++ ApplyPendingBounds();
++
++ if (did_active_change)
++ delegate()->OnActivationChanged(is_active_);
++
++ MaybeTriggerPendingStateChange();
++}
++
++void WaylandSurface::OnDragEnter(const gfx::PointF& point,
++ std::unique_ptr<OSExchangeData> data,
++ int operation) {
++ WmDropHandler* drop_handler = GetWmDropHandler(*this);
++ if (!drop_handler)
++ return;
++ drop_handler->OnDragEnter(point, std::move(data), operation);
++}
++
++int WaylandSurface::OnDragMotion(const gfx::PointF& point,
++ uint32_t time,
++ int operation) {
++ WmDropHandler* drop_handler = GetWmDropHandler(*this);
++ if (!drop_handler)
++ return 0;
++
++ return drop_handler->OnDragMotion(point, operation);
++}
++
++void WaylandSurface::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
++ WmDropHandler* drop_handler = GetWmDropHandler(*this);
++ if (!drop_handler)
++ return;
++ drop_handler->OnDragDrop(std::move(data));
++}
++
++void WaylandSurface::OnDragLeave() {
++ WmDropHandler* drop_handler = GetWmDropHandler(*this);
++ if (!drop_handler)
++ return;
++ drop_handler->OnDragLeave();
++}
++
++void WaylandSurface::OnDragSessionClose(uint32_t dnd_action) {
++ std::move(drag_closed_callback_).Run(dnd_action);
++ connection()->ResetPointerFlags();
++}
++
++bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) {
++ CreateShellSurface();
++ if (shell_surface_ && !properties.wm_class_class.empty())
++ shell_surface_->SetAppId(properties.wm_class_class);
++ return !!shell_surface_;
++}
++
++bool WaylandSurface::IsMinimized() const {
++ return state_ == PlatformWindowState::kMinimized;
++}
++
++bool WaylandSurface::IsMaximized() const {
++ return state_ == PlatformWindowState::kMaximized;
++}
++
++bool WaylandSurface::IsFullscreen() const {
++ return state_ == PlatformWindowState::kFullScreen;
++}
++
++void WaylandSurface::MaybeTriggerPendingStateChange() {
++ if (pending_state_ == PlatformWindowState::kUnknown || !is_active_)
++ return;
++ DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen);
++ pending_state_ = PlatformWindowState::kUnknown;
++ ToggleFullscreen();
++}
++
++WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() {
++ return static_cast<WmMoveResizeHandler*>(this);
++}
++
++} // namespace ui
+diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
+new file mode 100644
+index 000000000000..0f7204db3c48
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_surface.h
+@@ -0,0 +1,114 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
++#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
++
++#include "ui/ozone/platform/wayland/host/wayland_window.h"
++
++#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
++#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
++
++namespace ui {
++
++class ShellSurfaceWrapper;
++
++class WaylandSurface : public WaylandWindow,
++ public WmMoveResizeHandler,
++ public WmDragHandler {
++ public:
++ WaylandSurface(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection);
++ ~WaylandSurface() override;
++
++ ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); }
++
++ // 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();
++
++ // WmMoveResizeHandler
++ void DispatchHostWindowDragMovement(
++ int hittest,
++ const gfx::Point& pointer_location_in_px) override;
++
++ // WmDragHandler
++ void StartDrag(const ui::OSExchangeData& data,
++ int operation,
++ gfx::NativeCursor cursor,
++ base::OnceCallback<void(int)> callback) override;
++
++ // PlatformWindow
++ void Show(bool inactive) override;
++ void Hide() override;
++ bool IsVisible() const override;
++ void SetTitle(const base::string16& title) override;
++ void ToggleFullscreen() override;
++ void Maximize() override;
++ void Minimize() override;
++ void Restore() override;
++ PlatformWindowState GetPlatformWindowState() const override;
++ void SizeConstraintsChanged() override;
++
++ private:
++ // WaylandWindow overrides:
++ void HandleSurfaceConfigure(int32_t widht,
++ int32_t height,
++ bool is_maximized,
++ bool is_fullscreen,
++ bool is_activated) override;
++ void OnDragEnter(const gfx::PointF& point,
++ std::unique_ptr<OSExchangeData> data,
++ int operation) override;
++ int OnDragMotion(const gfx::PointF& point,
++ uint32_t time,
++ int operation) override;
++ void OnDragDrop(std::unique_ptr<OSExchangeData> data) override;
++ void OnDragLeave() override;
++ void OnDragSessionClose(uint32_t dnd_action) override;
++ bool OnInitialize(PlatformWindowInitProperties properties) override;
++
++ bool IsMinimized() const;
++ bool IsMaximized() const;
++ bool IsFullscreen() const;
++
++ void MaybeTriggerPendingStateChange();
++
++ // Creates a surface window, which is visible as a main window.
++ void CreateShellSurface();
++
++ WmMoveResizeHandler* AsWmMoveResizeHandler();
++
++ // Wrappers around shell surface.
++ std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
++
++ base::OnceCallback<void(int)> drag_closed_callback_;
++
++ // These bounds attributes below have suffices that indicate units used.
++ // Wayland operates in DIP but the platform operates in physical pixels so
++ // our WaylandSurface is the link that has to translate the units. See also
++ // comments in the implementation.
++ //
++ // 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 from Wayland.
++ gfx::Rect pending_bounds_dip_;
++
++ // Stores current states of the window.
++ PlatformWindowState state_;
++ // Stores a pending state of the window, which is used before the surface is
++ // activated.
++ PlatformWindowState pending_state_;
++
++ bool is_active_ = false;
++ bool is_minimizing_ = false;
++
++ DISALLOW_COPY_AND_ASSIGN(WaylandSurface);
++};
++
++} // namespace ui
++
++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SURFACE_H_
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index 1f8cc423d4aa..cdc95f904347 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -9,9 +9,6 @@
+
+ #include "base/bind.h"
+ #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+-#include "ui/base/dragdrop/drag_drop_types.h"
+-#include "ui/base/dragdrop/os_exchange_data.h"
+-#include "ui/base/hit_test.h"
+ #include "ui/events/event.h"
+ #include "ui/events/event_utils.h"
+ #include "ui/events/ozone/events_ozone.h"
+@@ -19,36 +16,19 @@
+ #include "ui/ozone/platform/wayland/common/wayland_util.h"
+ #include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+ #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+ #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+ #include "ui/ozone/platform/wayland/host/wayland_connection.h"
+ #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+ #include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+ #include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+-#include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+
+ namespace ui {
+
+ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection)
+- : delegate_(delegate),
+- connection_(connection),
+- state_(PlatformWindowState::kNormal),
+- pending_state_(PlatformWindowState::kUnknown) {
+- // Set a class property key, which allows |this| to be used for interactive
+- // events, e.g. move or resize.
+- SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
+-
+- // Set a class property key, which allows |this| to be used for drag action.
+- SetWmDragHandler(this, this);
+-}
++ : delegate_(delegate), connection_(connection) {}
+
+ WaylandWindow::~WaylandWindow() {
+- if (drag_closed_callback_) {
+- std::move(drag_closed_callback_)
+- .Run(DragDropTypes::DragOperation::DRAG_NONE);
+- }
+-
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ if (surface_)
+ connection_->wayland_window_manager()->RemoveWindow(GetWidget());
+@@ -127,13 +107,6 @@ void WaylandWindow::CreateShellPopup() {
+ parent_window_->set_child_window(this);
+ }
+
+-void WaylandWindow::CreateShellSurface() {
+- ShellObjectFactory factory;
+- shell_surface_ = factory.CreateShellSurfaceWrapper(connection_, this);
+- if (!shell_surface_)
+- CHECK(false) << "Failed to initialize Wayland shell surface";
+-}
+-
+ void WaylandWindow::CreateAndShowTooltipSubSurface() {
+ // Since Aura does not not provide a reference parent window, needed by
+ // Wayland, we get the current focused window to place and show the tooltips.
+@@ -172,21 +145,6 @@ void WaylandWindow::CreateAndShowTooltipSubSurface() {
+ connection_->ScheduleFlush();
+ }
+
+-void WaylandWindow::ApplyPendingBounds() {
+- if (pending_bounds_dip_.IsEmpty())
+- return;
+- DCHECK(shell_surface_);
+-
+- SetBoundsDip(pending_bounds_dip_);
+- shell_surface_->SetWindowGeometry(pending_bounds_dip_);
+- pending_bounds_dip_ = gfx::Rect();
+- connection_->ScheduleFlush();
+-
+- // Opaque region is based on the size of the window. Thus, update the region
+- // on each update.
+- MaybeUpdateOpaqueRegion();
+-}
+-
+ void WaylandWindow::SetPointerFocus(bool focus) {
+ has_pointer_focus_ = focus;
+
+@@ -197,36 +155,10 @@ void WaylandWindow::SetPointerFocus(bool focus) {
+ connection_->SetCursorBitmap(bitmap_->bitmaps(), bitmap_->hotspot());
+ }
+
+-void WaylandWindow::DispatchHostWindowDragMovement(
+- int hittest,
+- const gfx::Point& pointer_location_in_px) {
+- DCHECK(shell_surface_);
+-
+- connection_->ResetPointerFlags();
+- if (hittest == HTCAPTION)
+- shell_surface_->SurfaceMove(connection_);
+- else
+- shell_surface_->SurfaceResize(connection_, hittest);
+-
+- connection_->ScheduleFlush();
+-}
+-
+-void WaylandWindow::StartDrag(const ui::OSExchangeData& data,
+- int operation,
+- gfx::NativeCursor cursor,
+- base::OnceCallback<void(int)> callback) {
+- DCHECK(!drag_closed_callback_);
+- drag_closed_callback_ = std::move(callback);
+- connection_->StartDrag(data, operation);
+-}
+-
+ void WaylandWindow::Show(bool inactive) {
+ if (!is_tooltip_) // Tooltip windows should not get keyboard focus
+ set_keyboard_focus(true);
+
+- if (shell_surface_)
+- return;
+-
+ if (is_tooltip_) {
+ CreateAndShowTooltipSubSurface();
+ return;
+@@ -260,8 +192,7 @@ void WaylandWindow::Hide() {
+
+ // Detach buffer from surface in order to completely shutdown popups and
+ // tooltips, and release resources.
+- if (!shell_surface())
+- connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget());
++ connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+ }
+
+ void WaylandWindow::Close() {
+@@ -269,9 +200,7 @@ void WaylandWindow::Close() {
+ }
+
+ bool WaylandWindow::IsVisible() const {
+- // X and Windows return true if the window is minimized. For consistency, do
+- // the same.
+- return (!!shell_surface_ || !!shell_popup_) || IsMinimized();
++ return !!shell_popup_;
+ }
+
+ void WaylandWindow::PrepareForShutdown() {}
+@@ -281,6 +210,10 @@ void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
+ return;
+ 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_px_);
+ }
+
+@@ -288,11 +221,7 @@ gfx::Rect WaylandWindow::GetBounds() {
+ return bounds_px_;
+ }
+
+-void WaylandWindow::SetTitle(const base::string16& title) {
+- DCHECK(shell_surface_);
+- shell_surface_->SetTitle(title);
+- connection_->ScheduleFlush();
+-}
++void WaylandWindow::SetTitle(const base::string16& title) {}
+
+ void WaylandWindow::SetCapture() {
+ // Wayland does implicit grabs, and doesn't allow for explicit grabs. The
+@@ -309,79 +238,18 @@ bool WaylandWindow::HasCapture() const {
+ return shell_popup() ? true : has_implicit_grab_;
+ }
+
+-void WaylandWindow::ToggleFullscreen() {
+- DCHECK(shell_surface_);
++void WaylandWindow::ToggleFullscreen() {}
+
+- // There are some cases, when Chromium triggers a fullscreen state change
+- // before the surface is activated. In such cases, Wayland may ignore state
+- // changes and such flags as --kiosk or --start-fullscreen will be ignored.
+- // To overcome this, set a pending state, and once the surface is activated,
+- // trigger the change.
+- if (!is_active_) {
+- DCHECK(!IsFullscreen());
+- pending_state_ = PlatformWindowState::kFullScreen;
+- return;
+- }
+-
+- // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
+- // if shell_surface_set_fullscreen() is not provided with wl_output, it's up
+- // to the compositor to choose which display will be used to map this surface.
+- if (!IsFullscreen()) {
+- // Fullscreen state changes have to be handled manually and then checked
+- // against configuration events, which come from a compositor. The reason
+- // of manually changing the |state_| is that the compositor answers about
+- // state changes asynchronously, which leads to a wrong return value in
+- // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media
+- // files can never be set to fullscreen.
+- state_ = PlatformWindowState::kFullScreen;
+- shell_surface_->SetFullscreen();
+- } else {
+- // Check the comment above. If it's not handled synchronously, media files
+- // may not leave the fullscreen mode.
+- state_ = PlatformWindowState::kUnknown;
+- shell_surface_->UnSetFullscreen();
+- }
+-
+- connection_->ScheduleFlush();
+-}
++void WaylandWindow::Maximize() {}
+
+-void WaylandWindow::Maximize() {
+- DCHECK(shell_surface_);
++void WaylandWindow::Minimize() {}
+
+- if (IsFullscreen())
+- ToggleFullscreen();
+-
+- shell_surface_->SetMaximized();
+- connection_->ScheduleFlush();
+-}
+-
+-void WaylandWindow::Minimize() {
+- DCHECK(shell_surface_);
+- DCHECK(!is_minimizing_);
+- // Wayland doesn't explicitly say if a window is minimized. Instead, it
+- // notifies that the window is not activated. But there are many cases, when
+- // the window is not minimized and deactivated. In order to properly record
+- // the minimized state, mark this window as being minimized. And as soon as a
+- // configuration event comes, check if the window has been deactivated and has
+- // |is_minimizing_| set.
+- is_minimizing_ = true;
+- shell_surface_->SetMinimized();
+- connection_->ScheduleFlush();
+-}
+-
+-void WaylandWindow::Restore() {
+- DCHECK(shell_surface_);
+-
+- // Unfullscreen the window if it is fullscreen.
+- if (IsFullscreen())
+- ToggleFullscreen();
+-
+- shell_surface_->UnSetMaximized();
+- connection_->ScheduleFlush();
+-}
++void WaylandWindow::Restore() {}
+
+ PlatformWindowState WaylandWindow::GetPlatformWindowState() const {
+- return state_;
++ // Remove normal state for all the other types of windows as it's only the
++ // WaylandSurface that supports state changes.
++ return PlatformWindowState::kNormal;
+ }
+
+ void WaylandWindow::Activate() {
+@@ -448,22 +316,7 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon,
+ NOTIMPLEMENTED_LOG_ONCE();
+ }
+
+-void WaylandWindow::SizeConstraintsChanged() {
+- // Size constraints only make sense for normal windows.
+- if (!shell_surface_)
+- return;
+-
+- DCHECK(delegate_);
+- auto min_size = delegate_->GetMinimumSizeForWindow();
+- auto max_size = delegate_->GetMaximumSizeForWindow();
+-
+- if (min_size.has_value())
+- shell_surface_->SetMinSize(min_size->width(), min_size->height());
+- if (max_size.has_value())
+- shell_surface_->SetMaxSize(max_size->width(), max_size->height());
+-
+- connection_->ScheduleFlush();
+-}
++void WaylandWindow::SizeConstraintsChanged() {}
+
+ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
+ // This window is a nested popup window, all the events must be forwarded
+@@ -508,7 +361,7 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
+ if (event->IsLocatedEvent() && shell_popup()) {
+ // Parent window of the main menu window is not a popup, but rather an
+ // xdg surface.
+- DCHECK(!parent_window_->shell_popup() && parent_window_->shell_surface());
++ DCHECK(!parent_window_->shell_popup() || !parent_window_->is_tooltip_);
+ auto* window =
+ connection_->wayland_window_manager()->GetCurrentFocusedWindow();
+ if (window) {
+@@ -524,92 +377,13 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
+ return POST_DISPATCH_STOP_PROPAGATION;
+ }
+
+-void WaylandWindow::HandleSurfaceConfigure(int32_t width,
++void WaylandWindow::HandleSurfaceConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
+- DCHECK(!shell_popup());
+-
+- // Propagate the window state information to the client.
+- PlatformWindowState old_state = state_;
+-
+- // Ensure that manually handled state changes to fullscreen correspond to the
+- // configuration events from a compositor.
+- DCHECK_EQ(is_fullscreen, IsFullscreen());
+-
+- // There are two cases, which must be handled for the minimized state.
+- // The first one is the case, when the surface goes into the minimized state
+- // (check comment in WaylandWindow::Minimize), and the second case is when the
+- // surface still has been minimized, but another cofiguration event with
+- // !is_activated comes. For this, check if the WaylandWindow has been
+- // minimized before and !is_activated is sent.
+- if ((is_minimizing_ || IsMinimized()) && !is_activated) {
+- is_minimizing_ = false;
+- state_ = PlatformWindowState::kMinimized;
+- } else if (is_fullscreen) {
+- // To ensure the |delegate_| is notified about state changes to fullscreen,
+- // assume the old_state is UNKNOWN (check comment in ToggleFullscreen).
+- old_state = PlatformWindowState::kUnknown;
+- DCHECK(state_ == PlatformWindowState::kFullScreen);
+- } else if (is_maximized) {
+- state_ = PlatformWindowState::kMaximized;
+- } else {
+- state_ = PlatformWindowState::kNormal;
+- }
+- const bool state_changed = old_state != state_;
+- const bool is_normal = !IsFullscreen() && !IsMaximized();
+-
+- // Update state before notifying delegate.
+- const bool did_active_change = is_active_ != is_activated;
+- is_active_ = is_activated;
+-
+- // Rather than call SetBounds here for every configure event, just save the
+- // most recent bounds, and have WaylandConnection call ApplyPendingBounds
+- // when it has finished processing events. We may get many configure events
+- // in a row during an interactive resize, and only the last one matters.
+- //
+- // Width or height set to 0 means that we should decide on width and height by
+- // ourselves, but we don't want to set them to anything else. Use restored
+- // bounds size or the current bounds iff the current state is normal (neither
+- // maximized nor fullscreen).
+- //
+- // Note: if the browser was started with --start-fullscreen and a user exits
+- // the fullscreen mode, wayland may set the width and height to be 1. Instead,
+- // explicitly set the bounds to the current desired ones or the previous
+- // bounds.
+- if (width > 1 && height > 1) {
+- pending_bounds_dip_ = gfx::Rect(0, 0, width, height);
+- } else if (is_normal) {
+- pending_bounds_dip_.set_size(gfx::ScaleToRoundedSize(
+- restored_bounds_px_.IsEmpty() ? GetBounds().size()
+- : restored_bounds_px_.size(),
+-
+- 1.0 / buffer_scale_));
+- }
+-
+- if (state_changed) {
+- // The |restored_bounds_| are used when the window gets back to normal
+- // state after it went maximized or fullscreen. So we reset these if the
+- // window has just become normal and store the current bounds if it is
+- // either going out of normal state or simply changes the state and we don't
+- // have any meaningful value stored.
+- if (is_normal) {
+- SetRestoredBoundsInPixels({});
+- } else if (old_state == PlatformWindowState::kNormal ||
+- restored_bounds_px_.IsEmpty()) {
+- SetRestoredBoundsInPixels(bounds_px_);
+- }
+-
+- delegate_->OnWindowStateChanged(state_);
+- }
+-
+- ApplyPendingBounds();
+-
+- if (did_active_change)
+- delegate_->OnActivationChanged(is_active_);
+-
+- MaybeTriggerPendingStateChange();
++ NOTREACHED()
++ << "Only shell surfaces must receive HandleSurfaceConfigure calls.";
+ }
+
+ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
+@@ -671,40 +445,22 @@ void WaylandWindow::OnCloseRequest() {
+
+ void WaylandWindow::OnDragEnter(const gfx::PointF& point,
+ std::unique_ptr<OSExchangeData> data,
+- int operation) {
+- WmDropHandler* drop_handler = GetWmDropHandler(*this);
+- if (!drop_handler)
+- return;
+- drop_handler->OnDragEnter(point, std::move(data), operation);
+-}
++ int operation) {}
+
+ int WaylandWindow::OnDragMotion(const gfx::PointF& point,
+ uint32_t time,
+ int operation) {
+- WmDropHandler* drop_handler = GetWmDropHandler(*this);
+- if (!drop_handler)
+- return 0;
+-
+- return drop_handler->OnDragMotion(point, operation);
++ return -1;
+ }
+
+-void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
+- WmDropHandler* drop_handler = GetWmDropHandler(*this);
+- if (!drop_handler)
+- return;
+- drop_handler->OnDragDrop(std::move(data));
+-}
++void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {}
+
+-void WaylandWindow::OnDragLeave() {
+- WmDropHandler* drop_handler = GetWmDropHandler(*this);
+- if (!drop_handler)
+- return;
+- drop_handler->OnDragLeave();
+-}
++void WaylandWindow::OnDragLeave() {}
+
+-void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {
+- std::move(drag_closed_callback_).Run(dnd_action);
+- connection_->ResetPointerFlags();
++void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {}
++
++void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
++ SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale_));
+ }
+
+ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+@@ -752,15 +508,11 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ case ui::PlatformWindowType::kWindow:
+ case ui::PlatformWindowType::kBubble:
+ case ui::PlatformWindowType::kDrag:
+- // TODO(msisov): Figure out what kind of surface we need to create for
+- // bubble and drag windows.
+- CreateShellSurface();
++ if (!OnInitialize(std::move(properties)))
++ return false;
+ break;
+ }
+
+- if (shell_surface_ && !properties.wm_class_class.empty())
+- shell_surface_->SetAppId(properties.wm_class_class);
+-
+ connection_->ScheduleFlush();
+
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+@@ -773,10 +525,6 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ return true;
+ }
+
+-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);
+
+@@ -793,26 +541,6 @@ void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) {
+ connection_->ScheduleFlush();
+ }
+
+-bool WaylandWindow::IsMinimized() const {
+- return state_ == PlatformWindowState::kMinimized;
+-}
+-
+-bool WaylandWindow::IsMaximized() const {
+- return state_ == PlatformWindowState::kMaximized;
+-}
+-
+-bool WaylandWindow::IsFullscreen() const {
+- return state_ == PlatformWindowState::kFullScreen;
+-}
+-
+-void WaylandWindow::MaybeTriggerPendingStateChange() {
+- if (pending_state_ == PlatformWindowState::kUnknown || !is_active_)
+- return;
+- DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen);
+- pending_state_ = PlatformWindowState::kUnknown;
+- ToggleFullscreen();
+-}
+-
+ WaylandWindow* WaylandWindow::GetParentWindow(
+ gfx::AcceleratedWidget parent_widget) {
+ auto* parent_window =
+@@ -838,10 +566,6 @@ WaylandWindow* WaylandWindow::GetRootParentWindow() {
+ return parent_window_ ? parent_window_->GetRootParentWindow() : this;
+ }
+
+-WmMoveResizeHandler* WaylandWindow::AsWmMoveResizeHandler() {
+- return static_cast<WmMoveResizeHandler*>(this);
+-}
+-
+ void WaylandWindow::AddSurfaceListener() {
+ static struct wl_surface_listener surface_listener = {
+ &WaylandWindow::Enter,
+@@ -960,10 +684,12 @@ gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
+ // the parent menu window, which results in showing it on a second display if
+ // more than one display is used.
+ if (parent_window_->shell_popup() && parent_window_->parent_window_ &&
+- !parent_window_->parent_window_->IsMaximized()) {
++ (parent_window_->parent_window()->GetPlatformWindowState() !=
++ PlatformWindowState::kMaximized)) {
+ auto* top_level_window = parent_window_->parent_window_;
+ DCHECK(top_level_window && !top_level_window->shell_popup());
+- if (new_bounds_dip.x() <= 0 && !top_level_window->IsMaximized()) {
++ if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() !=
++ PlatformWindowState::kMaximized) {
+ // Position the child menu window on the right side of the parent window
+ // and let the Wayland compositor decide how to do constraint
+ // adjustements.
+@@ -995,6 +721,10 @@ bool WaylandWindow::IsOpaqueWindow() const {
+ return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow;
+ }
+
++bool WaylandWindow::OnInitialize(PlatformWindowInitProperties properties) {
++ return true;
++}
++
+ // static
+ void WaylandWindow::Enter(void* data,
+ struct wl_surface* wl_surface,
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
+index b8cdc991e30e..b9ee70d0ecd2 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.h
++++ b/ui/ozone/platform/wayland/host/wayland_window.h
+@@ -19,8 +19,6 @@
+ #include "ui/ozone/platform/wayland/common/wayland_object.h"
+ #include "ui/platform_window/platform_window.h"
+ #include "ui/platform_window/platform_window_delegate.h"
+-#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
+-#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
+ #include "ui/platform_window/platform_window_init_properties.h"
+
+ namespace gfx {
+@@ -33,12 +31,8 @@ class BitmapCursorOzone;
+ class OSExchangeData;
+ class WaylandConnection;
+ class ShellPopupWrapper;
+-class ShellSurfaceWrapper;
+
+-class WaylandWindow : public PlatformWindow,
+- public PlatformEventDispatcher,
+- public WmMoveResizeHandler,
+- public WmDragHandler {
++class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ public:
+ ~WaylandWindow() override;
+
+@@ -59,17 +53,12 @@ class WaylandWindow : public PlatformWindow,
+ void UpdateBufferScale(bool update_bounds);
+
+ wl_surface* surface() const { return surface_.get(); }
+- ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); }
+ ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); }
+
+ WaylandWindow* parent_window() const { return parent_window_; }
+
+ gfx::AcceleratedWidget GetWidget() 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();
+-
+ // Set whether this window has pointer focus and should dispatch mouse events.
+ void SetPointerFocus(bool focus);
+ bool has_pointer_focus() const { return has_pointer_focus_; }
+@@ -94,23 +83,10 @@ class WaylandWindow : public PlatformWindow,
+
+ int32_t buffer_scale() const { return buffer_scale_; }
+
+- 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,
+- const gfx::Point& pointer_location_in_px) override;
+-
+- // WmDragHandler
+- void StartDrag(const ui::OSExchangeData& data,
+- int operation,
+- gfx::NativeCursor cursor,
+- base::OnceCallback<void(int)> callback) override;
+-
+ // PlatformWindow
+ void Show(bool inactive) override;
+ void Hide() override;
+@@ -147,49 +123,49 @@ 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
+- // |XDGSurfaceWrapperStable::ConfigureTopLevel| 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,
+- bool is_fullscreen,
+- bool is_activated);
++ // Handles the configuration events coming from the shell objects.
++ // The width and height come in DIP of the output that the surface is
++ // currently bound to.
++ virtual void HandleSurfaceConfigure(int32_t widht,
++ int32_t height,
++ bool is_maximized,
++ bool is_fullscreen,
++ bool is_activated);
+ void HandlePopupConfigure(const gfx::Rect& bounds);
+
+ void OnCloseRequest();
+
+- void OnDragEnter(const gfx::PointF& point,
+- std::unique_ptr<OSExchangeData> data,
+- int operation);
+- int OnDragMotion(const gfx::PointF& point, uint32_t time, int operation);
+- void OnDragDrop(std::unique_ptr<OSExchangeData> data);
+- void OnDragLeave();
+- void OnDragSessionClose(uint32_t dnd_action);
++ // Notifies about drag/drop session events.
++ virtual void OnDragEnter(const gfx::PointF& point,
++ std::unique_ptr<OSExchangeData> data,
++ int operation);
++ virtual int OnDragMotion(const gfx::PointF& point,
++ uint32_t time,
++ int operation);
++ virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data);
++ virtual void OnDragLeave();
++ virtual void OnDragSessionClose(uint32_t dnd_action);
++
++ protected:
++ WaylandWindow(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection);
++
++ WaylandConnection* connection() { return connection_; }
++ PlatformWindowDelegate* delegate() { return delegate_; }
++
++ // Sets bounds in dip.
++ void SetBoundsDip(const gfx::Rect& bounds_dip);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale);
+
+- WaylandWindow(PlatformWindowDelegate* delegate,
+- WaylandConnection* connection);
+-
+ // Initializes the WaylandWindow with supplied properties.
+ bool Initialize(PlatformWindowInitProperties properties);
+
+- void SetBoundsDip(const gfx::Rect& bounds_dip);
+ void SetBufferScale(int32_t scale, bool update_bounds);
+
+- bool IsMinimized() const;
+- bool IsMaximized() const;
+- bool IsFullscreen() const;
+-
+- void MaybeTriggerPendingStateChange();
+-
+ // Creates a popup window, which is visible as a menu window.
+ void CreateShellPopup();
+- // Creates a surface window, which is visible as a main window.
+- void CreateShellSurface();
+ // Creates (if necessary) and show subsurface window, to host
+ // tooltip's content.
+ void CreateAndShowTooltipSubSurface();
+@@ -200,8 +176,6 @@ class WaylandWindow : public PlatformWindow,
+ // Returns a root parent window.
+ WaylandWindow* GetRootParentWindow();
+
+- WmMoveResizeHandler* AsWmMoveResizeHandler();
+-
+ // Install a surface listener and start getting wl_output enter/leave events.
+ void AddSurfaceListener();
+
+@@ -221,6 +195,9 @@ class WaylandWindow : public PlatformWindow,
+
+ bool IsOpaqueWindow() const;
+
++ // Additional initialization of derived classes.
++ virtual bool OnInitialize(PlatformWindowInitProperties properties);
++
+ // wl_surface_listener
+ static void Enter(void* data,
+ struct wl_surface* wl_surface,
+@@ -239,25 +216,11 @@ class WaylandWindow : public PlatformWindow,
+
+ // Wrappers around xdg v5 and xdg v6 objects. WaylandWindow doesn't
+ // know anything about the version.
+- std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
+ std::unique_ptr<ShellPopupWrapper> shell_popup_;
+
+ // The current cursor bitmap (immutable).
+ scoped_refptr<BitmapCursorOzone> bitmap_;
+
+- base::OnceCallback<void(int)> drag_closed_callback_;
+-
+- // These bounds attributes below have suffices that indicate units used.
+- // Wayland operates in DIP but the platform operates in physical pixels so
+- // our WaylandWindow is the link that has to translate the units. See also
+- // comments in the implementation.
+- //
+- // 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 from Wayland.
+- gfx::Rect pending_bounds_dip_;
+ // Current bounds of the platform window.
+ gfx::Rect bounds_px_;
+ // The bounds of the platform window before it went maximized or fullscreen.
+@@ -275,18 +238,9 @@ class WaylandWindow : public PlatformWindow,
+ // We need it to place and size the menus properly.
+ float ui_scale_ = 1.0;
+
+- // Stores current states of the window.
+- PlatformWindowState state_;
+- // Stores a pending state of the window, which is used before the surface is
+- // activated.
+- PlatformWindowState pending_state_;
+-
+ // Stores current opacity of the window. Set on ::Initialize call.
+ ui::PlatformWindowOpacity opacity_;
+
+- bool is_active_ = false;
+- bool is_minimizing_ = false;
+-
+ bool is_tooltip_ = false;
+
+ // For top level window, stores IDs of outputs that the window is currently
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+index 19da59357d55..892902e7f845 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_factory.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+@@ -6,6 +6,7 @@
+
+ #include <memory>
+
++#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+ #include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+ namespace ui {
+@@ -15,12 +16,30 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
+ PlatformWindowDelegate* delegate,
+ WaylandConnection* connection,
+ PlatformWindowInitProperties properties) {
+- // TODO(msisov): once WaylandWindow becomes a base class, add switch cases to
+- // create different Wayland windows.
+- std::unique_ptr<WaylandWindow> window(
+- new WaylandWindow(delegate, connection));
+- return window->Initialize(std::move(properties)) ? std::move(window)
+- : nullptr;
++ std::unique_ptr<WaylandWindow> window;
++ switch (properties.type) {
++ case PlatformWindowType::kMenu:
++ case PlatformWindowType::kPopup:
++ // TODO(msisov): Add WaylandPopup.
++ window.reset(new WaylandWindow(delegate, connection));
++ break;
++ case PlatformWindowType::kTooltip:
++ // TODO(msisov): Add WaylandSubsurface.
++ window.reset(new WaylandWindow(delegate, connection));
++ break;
++ case PlatformWindowType::kWindow:
++ case PlatformWindowType::kBubble:
++ case PlatformWindowType::kDrag:
++ // TODO(msisov): Figure out what kind of surface we need to create for
++ // bubble and drag windows.
++ window.reset(new WaylandSurface(delegate, connection));
++ break;
++ default:
++ NOTREACHED();
++ break;
++ }
++ return window && window->Initialize(std::move(properties)) ? std::move(window)
++ : nullptr;
+ }
+
+ } // namespace ui
+\ No newline at end of file
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+index b03a28daadf2..132f740b0eb1 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+@@ -26,6 +26,7 @@
+ #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+ #include "ui/ozone/platform/wayland/test/wayland_test.h"
+ #include "ui/ozone/test/mock_platform_window_delegate.h"
++#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
+ #include "ui/platform_window/platform_window_init_properties.h"
+
+ using ::testing::_;
+@@ -249,7 +250,6 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+ SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2,
+ inactive_maximized.get());
+ Sync();
+- EXPECT_FALSE(window_->is_active());
+ VerifyAndClearExpectations();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
+@@ -259,7 +259,6 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+ SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3,
+ active_maximized.get());
+ Sync();
+- EXPECT_TRUE(window_->is_active());
+ VerifyAndClearExpectations();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+@@ -703,21 +702,17 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
+ }
+
+ TEST_P(WaylandWindowTest, OnActivationChanged) {
+- EXPECT_FALSE(window_->is_active());
+-
+ {
+ ScopedWlArray states = InitializeWlArrayWithActivatedState();
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
+ SendConfigureEvent(0, 0, 1, states.get());
+ Sync();
+- EXPECT_TRUE(window_->is_active());
+ }
+
+ ScopedWlArray states;
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
+ SendConfigureEvent(0, 0, 2, states.get());
+ Sync();
+- EXPECT_FALSE(window_->is_active());
+ }
+
+ TEST_P(WaylandWindowTest, OnAcceleratedWidgetDestroy) {
+@@ -847,7 +842,7 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) {
+
+ TEST_P(WaylandWindowTest, DispatchWindowMove) {
+ EXPECT_CALL(*GetXdgSurface(), Move(_));
+- window_->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point());
++ ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point());
+ }
+
+ // Makes sure hit tests are converted into right edges.
+@@ -855,11 +850,14 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) {
+ std::vector<int> hit_test_values;
+ InitializeWithSupportedHitTestValues(&hit_test_values);
+
++ auto* wm_move_resize_handler = ui::GetWmMoveResizeHandler(*window_);
++
+ for (const int value : hit_test_values) {
+ {
+ uint32_t direction = wl::IdentifyDirection(*(connection_.get()), value);
+ EXPECT_CALL(*GetXdgSurface(), Resize(_, Eq(direction)));
+- window_->DispatchHostWindowDragMovement(value, gfx::Point());
++ wm_move_resize_handler->DispatchHostWindowDragMovement(value,
++ gfx::Point());
+ }
+ }
+ }
+diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+index abf6e7fa6461..e85236ce47d7 100644
+--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+@@ -14,6 +14,7 @@
+ #include "ui/gfx/geometry/rect.h"
+ #include "ui/ozone/platform/wayland/host/wayland_connection.h"
+ #include "ui/ozone/platform/wayland/host/wayland_pointer.h"
++#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+ #include "ui/ozone/platform/wayland/host/wayland_window.h"
+ #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+
+@@ -290,8 +291,10 @@ bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection,
+ wayland_window_->parent_window()->shell_popup());
+ parent_xdg_surface = popup->xdg_surface();
+ } else {
++ WaylandSurface* wayland_surface =
++ static_cast<WaylandSurface*>(wayland_window_->parent_window());
+ parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>(
+- wayland_window_->parent_window()->shell_surface());
++ wayland_surface->shell_surface());
+ }
+
+ if (!parent_xdg_surface)
+@@ -405,8 +408,10 @@ bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection,
+ wayland_window_->parent_window()->shell_popup());
+ parent_xdg_surface = popup->xdg_surface();
+ } else {
++ WaylandSurface* wayland_surface =
++ static_cast<WaylandSurface*>(wayland_window_->parent_window());
+ parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>(
+- wayland_window_->parent_window()->shell_surface());
++ wayland_surface->shell_surface());
+ }
+
+ if (!parent_xdg_surface)
+--
+2.24.1
+
diff --git a/0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch b/0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch
new file mode 100644
index 000000000000..2d62b81885fd
--- /dev/null
+++ b/0006-ozone-wayland-extract-popup-methods-to-WaylandPopup.patch
@@ -0,0 +1,1043 @@
+From 0cff96c5189fee16e0b2f79685c86e73216652aa Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Wed, 11 Dec 2019 09:50:09 +0000
+Subject: [PATCH 6/9] ozone/wayland: extract popup methods to WaylandPopup
+
+This change does not bring any functional changes and just
+extracts menus/popups methods to a separate class named
+WaylandPopup.
+
+Also, to avoid code duplicate, the XdgPopupWrapperImpl::Initialize
+gets a parent xdg surface and passes it to ::InitializeStable and
+::InitializeV6 methods.
+
+Test: ozone_unittests
+Bug: 1028919
+Change-Id: I216e1374b7e6e97080e40043634db91a20a7b4cf
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1958989
+Reviewed-by: Michael Spang <spang@chromium.org>
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Cr-Commit-Position: refs/heads/master@{#723755}
+---
+ ui/ozone/platform/wayland/BUILD.gn | 2 +
+ .../platform/wayland/common/wayland_util.cc | 5 +
+ .../platform/wayland/common/wayland_util.h | 4 +
+ .../platform/wayland/host/wayland_popup.cc | 210 +++++++++++++++
+ .../platform/wayland/host/wayland_popup.h | 49 ++++
+ .../platform/wayland/host/wayland_window.cc | 243 +++---------------
+ .../platform/wayland/host/wayland_window.h | 41 +--
+ .../wayland/host/wayland_window_factory.cc | 3 +-
+ .../wayland/host/xdg_popup_wrapper_impl.cc | 83 +++---
+ .../wayland/host/xdg_popup_wrapper_impl.h | 8 +-
+ 10 files changed, 371 insertions(+), 277 deletions(-)
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_popup.cc
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_popup.h
+
+diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
+index b6059c7d9962..4bfe93352f34 100644
+--- a/ui/ozone/platform/wayland/BUILD.gn
++++ b/ui/ozone/platform/wayland/BUILD.gn
+@@ -85,6 +85,8 @@ source_set("wayland") {
+ "host/wayland_output_manager.h",
+ "host/wayland_pointer.cc",
+ "host/wayland_pointer.h",
++ "host/wayland_popup.cc",
++ "host/wayland_popup.h",
+ "host/wayland_screen.cc",
+ "host/wayland_screen.h",
+ "host/wayland_shm.cc",
+diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc
+index e0430b860adf..578bab8930c8 100644
+--- a/ui/ozone/platform/wayland/common/wayland_util.cc
++++ b/ui/ozone/platform/wayland/common/wayland_util.cc
+@@ -155,4 +155,9 @@ gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
+ child_bounds.size());
+ }
+
++bool IsMenuType(ui::PlatformWindowType type) {
++ return type == ui::PlatformWindowType::kMenu ||
++ type == ui::PlatformWindowType::kPopup;
++}
++
+ } // namespace wl
+diff --git a/ui/ozone/platform/wayland/common/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h
+index 48332e059da0..3db369654025 100644
+--- a/ui/ozone/platform/wayland/common/wayland_util.h
++++ b/ui/ozone/platform/wayland/common/wayland_util.h
+@@ -15,6 +15,7 @@
+ #include "base/macros.h"
+ #include "ui/gfx/geometry/rect.h"
+ #include "ui/ozone/platform/wayland/common/wayland_object.h"
++#include "ui/platform_window/platform_window_init_properties.h"
+
+ class SkBitmap;
+
+@@ -58,6 +59,9 @@ gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
+ gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
+ const gfx::Rect& parent_bounds);
+
++// Says if the type is kPopup or kMenu.
++bool IsMenuType(ui::PlatformWindowType type);
++
+ } // namespace wl
+
+ #endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
+diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc
+new file mode 100644
+index 000000000000..45aac6e51bfc
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_popup.cc
+@@ -0,0 +1,210 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "ui/ozone/platform/wayland/host/wayland_popup.h"
++
++#include "ui/ozone/platform/wayland/common/wayland_util.h"
++#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
++#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
++#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
++#include "ui/ozone/platform/wayland/host/wayland_connection.h"
++
++namespace ui {
++
++WaylandPopup::WaylandPopup(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection)
++ : WaylandWindow(delegate, connection) {}
++
++WaylandPopup::~WaylandPopup() = default;
++
++void WaylandPopup::CreateShellPopup() {
++ if (GetBounds().IsEmpty())
++ return;
++
++ // TODO(jkim): Consider how to support DropArrow window on tabstrip.
++ // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3,
++ // the client must have an active implicit grab. If we try to create a popup
++ // window while dragging is executed, it gets 'popup_done' directly from
++ // Wayland compositor and it's destroyed through 'popup_done'. It causes
++ // a crash when aura::Window is destroyed.
++ // https://crbug.com/875164
++ if (connection()->IsDragInProgress()) {
++ LOG(ERROR) << "Wayland can't create a popup window during dragging.";
++ return;
++ }
++
++ DCHECK(parent_window() && !shell_popup_);
++
++ auto bounds_px = AdjustPopupWindowPosition();
++
++ ShellObjectFactory factory;
++ shell_popup_ = factory.CreateShellPopupWrapper(connection(), this, bounds_px);
++ if (!shell_popup_)
++ CHECK(false) << "Failed to create Wayland shell popup";
++
++ parent_window()->set_child_window(this);
++}
++
++void WaylandPopup::Show(bool inactive) {
++ set_keyboard_focus(true);
++
++ if (!shell_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.
++ SetBounds(gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale()));
++ CreateShellPopup();
++ connection()->ScheduleFlush();
++ }
++
++ UpdateBufferScale(false);
++}
++
++void WaylandPopup::Hide() {
++ if (child_window())
++ child_window()->Hide();
++
++ if (shell_popup_) {
++ parent_window()->set_child_window(nullptr);
++ shell_popup_.reset();
++ }
++
++ // Detach buffer from surface in order to completely shutdown popups and
++ // tooltips, and release resources.
++ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
++}
++
++bool WaylandPopup::IsVisible() const {
++ return !!shell_popup_;
++}
++
++bool WaylandPopup::HasCapture() const {
++ // WaylandPopups always have captures.
++ return shell_popup();
++}
++
++void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
++ DCHECK(shell_popup());
++ 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 a.k.a browser window, it can be flipped
++ // vertically along y-axis and have negative values set. Chromium cannot
++ // understand that and starts to position nested menu windows incorrectly. To
++ // fix that, we have to bear in mind that Wayland compositor does not share
++ // global coordinates for any surfaces, and Chromium assumes the top level
++ // window is always located at 0,0 origin. What is more, child windows must
++ // always be positioned relative to parent window local surface coordinates.
++ // Thus, if the menu window is flipped along y-axis by Wayland and its origin
++ // is above the top level parent window, the origin of the top level window
++ // has to be shifted by that value on y-axis so that the origin of the menu
++ // becomes x,0, and events can be handled normally.
++ if (!wl::IsMenuType(parent_window()->type())) {
++ 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_dip.y() < 0) {
++ // Move parent bounds along y-axis.
++ 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.
++ parent_bounds.set_y(0);
++ }
++ parent_window()->SetBounds(parent_bounds);
++ } else {
++ // The nested menu windows are located relative to the parent menu windows.
++ // 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_dip = gfx::ScaleToRoundedRect(
++ wl::TranslateBoundsToTopLevelCoordinates(
++ gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale()),
++ parent_window()->GetBounds()),
++ 1.0 / buffer_scale());
++ DCHECK(new_bounds_dip.y() >= 0);
++ }
++
++ SetBoundsDip(new_bounds_dip);
++}
++
++void WaylandPopup::OnCloseRequest() {
++ // Before calling OnCloseRequest, the |shell_popup_| must become hidden and
++ // only then call OnCloseRequest().
++ DCHECK(!shell_popup_);
++ WaylandWindow::OnCloseRequest();
++}
++
++bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
++ if (!wl::IsMenuType(type()))
++ return false;
++
++ set_parent_window(GetParentWindow(properties.parent_widget));
++ if (!parent_window()) {
++ LOG(ERROR) << "Failed to get a parent window for this popup";
++ return false;
++ }
++ // If parent window is known in advanced, we may set the scale early.
++ SetBufferScale(parent_window()->buffer_scale(), false);
++ set_ui_scale(parent_window()->ui_scale());
++ CreateShellPopup();
++ return true;
++}
++
++gfx::Rect WaylandPopup::AdjustPopupWindowPosition() {
++ auto* top_level_parent = wl::IsMenuType(parent_window()->type())
++ ? parent_window()->parent_window()
++ : parent_window();
++ DCHECK(top_level_parent);
++ DCHECK(buffer_scale() == top_level_parent->buffer_scale());
++ DCHECK(ui_scale() == top_level_parent->ui_scale());
++
++ // Chromium positions windows in screen coordinates, but Wayland requires them
++ // to be in local surface coordinates a.k.a relative to parent window.
++ const gfx::Rect parent_bounds_dip =
++ gfx::ScaleToRoundedRect(parent_window()->GetBounds(), 1.0 / ui_scale());
++ gfx::Rect new_bounds_dip =
++ wl::TranslateBoundsToParentCoordinates(GetBounds(), 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
++ // window becomes larger than the display it is shown on. It's correct when
++ // the window is located on one display and occupies the whole work area, but
++ // as soon as it's moved and there is space on the right side, Chromium
++ // continues positioning the nested menus on the left side relative to the
++ // parent menu (Wayland does not provide clients with global coordinates).
++ // Instead, reposition that window to be on the right side of the parent menu
++ // window and let the compositor decide how to position it if it does not fit
++ // a single display. However, there is one exception - if the window is
++ // maximized, let Chromium position it on the left side as long as the Wayland
++ // compositor may decide to position the nested window on the right side of
++ // the parent menu window, which results in showing it on a second display if
++ // more than one display is used.
++ if (wl::IsMenuType(parent_window()->type()) &&
++ parent_window()->parent_window() &&
++ (parent_window()->parent_window()->GetPlatformWindowState() !=
++ PlatformWindowState::kMaximized)) {
++ auto* top_level_window = parent_window()->parent_window();
++ DCHECK(top_level_window && !wl::IsMenuType(top_level_window->type()));
++ if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() !=
++ PlatformWindowState::kMaximized) {
++ // Position the child menu window on the right side of the parent window
++ // and let the Wayland compositor decide how to do constraint
++ // adjustments.
++ int new_x = parent_bounds_dip.width() -
++ (new_bounds_dip.width() + new_bounds_dip.x());
++ new_bounds_dip.set_x(new_x);
++ }
++ }
++ return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale() / buffer_scale());
++}
++
++} // namespace ui
+diff --git a/ui/ozone/platform/wayland/host/wayland_popup.h b/ui/ozone/platform/wayland/host/wayland_popup.h
+new file mode 100644
+index 000000000000..2d45986ba36a
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_popup.h
+@@ -0,0 +1,49 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_
++#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_
++
++#include "ui/ozone/platform/wayland/host/wayland_window.h"
++
++namespace ui {
++
++class WaylandConnection;
++class ShellPopupWrapper;
++
++class WaylandPopup : public WaylandWindow {
++ public:
++ WaylandPopup(PlatformWindowDelegate* delegate, WaylandConnection* connection);
++ ~WaylandPopup() override;
++
++ ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); }
++
++ // PlatformWindow
++ void Show(bool inactive) override;
++ void Hide() override;
++ bool IsVisible() const override;
++ bool HasCapture() const override;
++
++ private:
++ // WaylandWindow overrides:
++ void HandlePopupConfigure(const gfx::Rect& bounds) override;
++ void OnCloseRequest() override;
++ bool OnInitialize(PlatformWindowInitProperties properties) override;
++
++ // Creates a popup window, which is visible as a menu window.
++ void CreateShellPopup();
++
++ // Returns bounds with origin relative to parent window's origin.
++ gfx::Rect AdjustPopupWindowPosition();
++
++ // Wrappers around xdg v5 and xdg v6 objects. WaylandPopup doesn't
++ // know anything about the version.
++ std::unique_ptr<ShellPopupWrapper> shell_popup_;
++
++ DISALLOW_COPY_AND_ASSIGN(WaylandPopup);
++};
++
++} // namespace ui
++
++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_POPUP_H_
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index cdc95f904347..045f922a759e 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -14,8 +14,6 @@
+ #include "ui/events/ozone/events_ozone.h"
+ #include "ui/gfx/geometry/point_f.h"
+ #include "ui/ozone/platform/wayland/common/wayland_util.h"
+-#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+-#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+ #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+ #include "ui/ozone/platform/wayland/host/wayland_connection.h"
+ #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+@@ -78,35 +76,6 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
+ return surface_.id();
+ }
+
+-void WaylandWindow::CreateShellPopup() {
+- if (bounds_px_.IsEmpty())
+- return;
+-
+- // TODO(jkim): Consider how to support DropArrow window on tabstrip.
+- // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3,
+- // the client must have an active implicit grab. If we try to create a popup
+- // window while dragging is executed, it gets 'popup_done' directly from
+- // Wayland compositor and it's destroyed through 'popup_done'. It causes
+- // a crash when aura::Window is destroyed.
+- // https://crbug.com/875164
+- if (connection_->IsDragInProgress()) {
+- surface_.reset();
+- LOG(ERROR) << "Wayland can't create a popup window during dragging.";
+- return;
+- }
+-
+- DCHECK(parent_window_ && !shell_popup_);
+-
+- auto bounds_px = AdjustPopupWindowPosition();
+-
+- ShellObjectFactory factory;
+- shell_popup_ = factory.CreateShellPopupWrapper(connection_, this, bounds_px);
+- if (!shell_popup_)
+- CHECK(false) << "Failed to create Wayland shell popup";
+-
+- parent_window_->set_child_window(this);
+-}
+-
+ void WaylandWindow::CreateAndShowTooltipSubSurface() {
+ // Since Aura does not not provide a reference parent window, needed by
+ // Wayland, we get the current focused window to place and show the tooltips.
+@@ -156,41 +125,17 @@ void WaylandWindow::SetPointerFocus(bool focus) {
+ }
+
+ void WaylandWindow::Show(bool inactive) {
+- if (!is_tooltip_) // Tooltip windows should not get keyboard focus
+- set_keyboard_focus(true);
+-
+- if (is_tooltip_) {
+- CreateAndShowTooltipSubSurface();
+- return;
+- }
+-
+- if (!shell_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 / ui_scale_);
+- CreateShellPopup();
+- connection_->ScheduleFlush();
+- }
++ DCHECK(is_tooltip_);
++ CreateAndShowTooltipSubSurface();
+
+ UpdateBufferScale(false);
+ }
+
+ void WaylandWindow::Hide() {
+- if (is_tooltip_) {
+- tooltip_subsurface_.reset();
+- } else {
+- if (child_window_)
+- child_window_->Hide();
+- if (shell_popup_) {
+- parent_window_->set_child_window(nullptr);
+- shell_popup_.reset();
+- }
+- }
++ DCHECK(is_tooltip_);
++ tooltip_subsurface_.reset();
+
+- // Detach buffer from surface in order to completely shutdown popups and
++ // Detach buffer from surface in order to completely shutdown menus and
+ // tooltips, and release resources.
+ connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+ }
+@@ -200,7 +145,7 @@ void WaylandWindow::Close() {
+ }
+
+ bool WaylandWindow::IsVisible() const {
+- return !!shell_popup_;
++ return !!tooltip_subsurface_;
+ }
+
+ void WaylandWindow::PrepareForShutdown() {}
+@@ -225,8 +170,8 @@ void WaylandWindow::SetTitle(const base::string16& title) {}
+
+ void WaylandWindow::SetCapture() {
+ // Wayland does implicit grabs, and doesn't allow for explicit grabs. The
+- // exception to that are popups, but we explicitly send events to a
+- // parent popup if such exists.
++ // exception to that are menus, but we explicitly send events to a
++ // parent menu if such exists.
+ }
+
+ void WaylandWindow::ReleaseCapture() {
+@@ -234,8 +179,7 @@ void WaylandWindow::ReleaseCapture() {
+ }
+
+ bool WaylandWindow::HasCapture() const {
+- // If WaylandWindow is a popup window, assume it has the capture.
+- return shell_popup() ? true : has_implicit_grab_;
++ return has_implicit_grab_;
+ }
+
+ void WaylandWindow::ToggleFullscreen() {}
+@@ -319,14 +263,14 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon,
+ void WaylandWindow::SizeConstraintsChanged() {}
+
+ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
+- // This window is a nested popup window, all the events must be forwarded
+- // to the main popup window.
+- if (child_window_ && child_window_->shell_popup())
+- return !!shell_popup_.get();
++ // This window is a nested menu window, all the events must be forwarded
++ // to the main menu window.
++ if (child_window_ && wl::IsMenuType(child_window_->type()))
++ return wl::IsMenuType(type());
+
+ // If this is a nested menu window with a parent, it mustn't recieve any
+ // events.
+- if (parent_window_ && parent_window_->shell_popup())
++ if (parent_window_ && wl::IsMenuType(parent_window_->type()))
+ return false;
+
+ // If another window has capture, return early before checking focus.
+@@ -344,7 +288,6 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
+
+ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
+ Event* event = static_cast<Event*>(native_event);
+-
+ if (event->IsLocatedEvent()) {
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+@@ -355,13 +298,14 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
+ }
+
+ // If the window does not have a pointer focus, but received this event, it
+- // means the window is a popup window with a child popup window. In this case,
+- // the location of the event must be converted from the nested popup to the
+- // main popup, which the menu controller needs to properly handle events.
+- if (event->IsLocatedEvent() && shell_popup()) {
+- // Parent window of the main menu window is not a popup, but rather an
++ // means the window is a menu window with a child menu window. In this case,
++ // the location of the event must be converted from the nested menu to the
++ // main menu, which the menu controller needs to properly handle events.
++ if (event->IsLocatedEvent() && wl::IsMenuType(type())) {
++ // Parent window of the main menu window is not a menu, but rather an
+ // xdg surface.
+- DCHECK(!parent_window_->shell_popup() || !parent_window_->is_tooltip_);
++ DCHECK(!wl::IsMenuType(parent_window_->type()) ||
++ !parent_window_->is_tooltip_);
+ auto* window =
+ connection_->wayland_window_manager()->GetCurrentFocusedWindow();
+ if (window) {
+@@ -387,59 +331,10 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t widht,
+ }
+
+ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
+- DCHECK(shell_popup());
+- 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
+- // vertically along y-axis and have negative values set. Chromium cannot
+- // understand that and starts to position nested menu windows incorrectly. To
+- // fix that, we have to bear in mind that Wayland compositor does not share
+- // global coordinates for any surfaces, and Chromium assumes the top level
+- // window is always located at 0,0 origin. What is more, child windows must
+- // always be positioned relative to parent window local surface coordinates.
+- // Thus, if the menu window is flipped along y-axis by Wayland and its origin
+- // is above the top level parent window, the origin of the top level window
+- // has to be shifted by that value on y-axis so that the origin of the menu
+- // becomes x,0, and events can be handled normally.
+- if (!parent_window_->shell_popup()) {
+- 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_dip.y() < 0) {
+- // Move parent bounds along y-axis.
+- 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.
+- parent_bounds.set_y(0);
+- }
+- parent_window_->SetBounds(parent_bounds);
+- } else {
+- // The nested menu windows are located relative to the parent menu windows.
+- // 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_dip = gfx::ScaleToRoundedRect(
+- wl::TranslateBoundsToTopLevelCoordinates(
+- gfx::ScaleToRoundedRect(new_bounds_dip, buffer_scale_),
+- parent_window_->GetBounds()),
+- 1.0 / buffer_scale_);
+- DCHECK(new_bounds_dip.y() >= 0);
+- }
+-
+- SetBoundsDip(new_bounds_dip);
++ NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls.";
+ }
+
+ void WaylandWindow::OnCloseRequest() {
+- // Before calling OnCloseRequest, the |shell_popup_| must become hidden and
+- // only then call OnCloseRequest().
+- DCHECK(!shell_popup_);
+ delegate_->OnCloseRequest();
+ }
+
+@@ -470,6 +365,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+ DCHECK_EQ(buffer_scale_, 1);
+ bounds_px_ = properties.bounds;
+ opacity_ = properties.opacity;
++ type_ = properties.type;
+
+ surface_.reset(wl_compositor_create_surface(connection_->compositor()));
+ if (!surface_) {
+@@ -481,44 +377,18 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+
+ connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
+
+- ui::PlatformWindowType ui_window_type = properties.type;
+- switch (ui_window_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.
+- if (!parent_window_) {
+- LOG(ERROR) << "Failed to get a parent window for this popup";
+- return false;
+- }
+-
+- 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
+- // parents and pop up when the browser receives a notification.
+- CreateShellPopup();
+- break;
+- case ui::PlatformWindowType::kTooltip:
+- // Tooltips subsurfaces are created on demand, upon ::Show calls.
+- is_tooltip_ = true;
+- break;
+- case ui::PlatformWindowType::kWindow:
+- case ui::PlatformWindowType::kBubble:
+- case ui::PlatformWindowType::kDrag:
+- if (!OnInitialize(std::move(properties)))
+- return false;
+- break;
+- }
++ if (type_ == ui::PlatformWindowType::kTooltip)
++ is_tooltip_ = true;
++
++ if (!OnInitialize(std::move(properties)))
++ return false;
+
+ connection_->ScheduleFlush();
+
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ delegate_->OnAcceleratedWidgetAvailable(GetWidget());
+
+- // Will do nothing for popups because they have got their scale above.
++ // Will do nothing for menus because they have got their scale above.
+ UpdateBufferScale(false);
+
+ MaybeUpdateOpaqueRegion();
+@@ -575,10 +445,10 @@ void WaylandWindow::AddSurfaceListener() {
+ }
+
+ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
+- // Wayland does weird things for popups so instead of tracking outputs that
++ // Wayland does weird things for menus so instead of tracking outputs that
+ // we entered or left, we take that from the parent window and ignore this
+ // event.
+- if (shell_popup())
++ if (wl::IsMenuType(type()))
+ return;
+
+ const uint32_t entered_output_id =
+@@ -591,10 +461,10 @@ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
+ }
+
+ void WaylandWindow::RemoveEnteredOutputId(struct wl_output* output) {
+- // Wayland does weird things for popups so instead of tracking outputs that
++ // Wayland does weird things for menus so instead of tracking outputs that
+ // we entered or left, we take that from the parent window and ignore this
+ // event.
+- if (shell_popup())
++ if (wl::IsMenuType(type()))
+ return;
+
+ const uint32_t left_output_id =
+@@ -654,53 +524,6 @@ void WaylandWindow::UpdateCursorPositionFromEvent(
+ }
+ }
+
+-gfx::Rect WaylandWindow::AdjustPopupWindowPosition() const {
+- auto* parent_window = parent_window_->shell_popup()
+- ? parent_window_->parent_window_
+- : 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_dip =
+- gfx::ScaleToRoundedRect(parent_window_->GetBounds(), 1.0 / ui_scale_);
+- gfx::Rect new_bounds_dip =
+- wl::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
+- // window becomes larger than the display it is shown on. It's correct when
+- // the window is located on one display and occupies the whole work area, but
+- // as soon as it's moved and there is space on the right side, Chromium
+- // continues positioning the nested menus on the left side relative to the
+- // parent menu (Wayland does not provide clients with global coordinates).
+- // Instead, reposition that window to be on the right side of the parent menu
+- // window and let the compositor decide how to position it if it does not fit
+- // a single display. However, there is one exception - if the window is
+- // maximized, let Chromium position it on the left side as long as the Wayland
+- // compositor may decide to position the nested window on the right side of
+- // the parent menu window, which results in showing it on a second display if
+- // more than one display is used.
+- if (parent_window_->shell_popup() && parent_window_->parent_window_ &&
+- (parent_window_->parent_window()->GetPlatformWindowState() !=
+- PlatformWindowState::kMaximized)) {
+- auto* top_level_window = parent_window_->parent_window_;
+- DCHECK(top_level_window && !top_level_window->shell_popup());
+- if (new_bounds_dip.x() <= 0 && top_level_window->GetPlatformWindowState() !=
+- PlatformWindowState::kMaximized) {
+- // 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_dip.width() -
+- (new_bounds_dip.width() + new_bounds_dip.x());
+- new_bounds_dip.set_x(new_x);
+- }
+- }
+- return gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_);
+-}
+-
+ WaylandWindow* WaylandWindow::GetTopLevelWindow() {
+ return parent_window_ ? parent_window_->GetTopLevelWindow() : this;
+ }
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
+index b9ee70d0ecd2..3eca745b38c4 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.h
++++ b/ui/ozone/platform/wayland/host/wayland_window.h
+@@ -30,7 +30,6 @@ namespace ui {
+ class BitmapCursorOzone;
+ class OSExchangeData;
+ class WaylandConnection;
+-class ShellPopupWrapper;
+
+ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ public:
+@@ -53,8 +52,10 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ void UpdateBufferScale(bool update_bounds);
+
+ wl_surface* surface() const { return surface_.get(); }
+- ShellPopupWrapper* shell_popup() const { return shell_popup_.get(); }
+
++ void set_parent_window(WaylandWindow* parent_window) {
++ parent_window_ = parent_window;
++ }
+ WaylandWindow* parent_window() const { return parent_window_; }
+
+ gfx::AcceleratedWidget GetWidget() const;
+@@ -75,6 +76,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ // Set a child of this window. It is very important in case of nested
+ // shell_popups as long as they must be destroyed in the back order.
+ void set_child_window(WaylandWindow* window) { child_window_ = window; }
++ WaylandWindow* child_window() const { return child_window_; }
+
+ // Set whether this window has an implicit grab (often referred to as capture
+ // in Chrome code). Implicit grabs happen while a pointer is down.
+@@ -82,11 +84,15 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ bool has_implicit_grab() const { return has_implicit_grab_; }
+
+ int32_t buffer_scale() const { return buffer_scale_; }
++ int32_t ui_scale() const { return ui_scale_; }
+
+ const base::flat_set<uint32_t>& entered_outputs_ids() const {
+ return entered_outputs_ids_;
+ }
+
++ // Returns current type of the window.
++ PlatformWindowType type() const { return type_; }
++
+ // PlatformWindow
+ void Show(bool inactive) override;
+ void Hide() override;
+@@ -131,9 +137,10 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated);
+- void HandlePopupConfigure(const gfx::Rect& bounds);
++ virtual void HandlePopupConfigure(const gfx::Rect& bounds);
+
+- void OnCloseRequest();
++ // Handles close requests.
++ virtual void OnCloseRequest();
+
+ // Notifies about drag/drop session events.
+ virtual void OnDragEnter(const gfx::PointF& point,
+@@ -156,23 +163,25 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ // Sets bounds in dip.
+ void SetBoundsDip(const gfx::Rect& bounds_dip);
+
++ // Gets a parent window for this window.
++ WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget);
++
++ // Sets the buffer scale.
++ void SetBufferScale(int32_t scale, bool update_bounds);
++
++ // Sets the ui scale.
++ void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; }
++
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale);
+
+ // Initializes the WaylandWindow with supplied properties.
+ bool Initialize(PlatformWindowInitProperties properties);
+
+- void SetBufferScale(int32_t scale, bool update_bounds);
+-
+- // Creates a popup window, which is visible as a menu window.
+- void CreateShellPopup();
+ // Creates (if necessary) and show subsurface window, to host
+ // tooltip's content.
+ void CreateAndShowTooltipSubSurface();
+
+- // Gets a parent window for this window.
+- WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget);
+-
+ // Returns a root parent window.
+ WaylandWindow* GetRootParentWindow();
+
+@@ -184,9 +193,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+
+ void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event);
+
+- // Returns bounds with origin relative to parent window's origin.
+- gfx::Rect AdjustPopupWindowPosition() const;
+-
+ WaylandWindow* GetTopLevelWindow();
+
+ // It's important to set opaque region for opaque windows (provides
+@@ -214,10 +220,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ wl::Object<wl_surface> surface_;
+ wl::Object<wl_subsurface> tooltip_subsurface_;
+
+- // Wrappers around xdg v5 and xdg v6 objects. WaylandWindow doesn't
+- // know anything about the version.
+- std::unique_ptr<ShellPopupWrapper> shell_popup_;
+-
+ // The current cursor bitmap (immutable).
+ scoped_refptr<BitmapCursorOzone> bitmap_;
+
+@@ -253,6 +255,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ // we ask its parent.
+ base::flat_set<uint32_t> entered_outputs_ids_;
+
++ // The type of the current WaylandWindow object.
++ ui::PlatformWindowType type_ = ui::PlatformWindowType::kWindow;
++
+ DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
+ };
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+index 892902e7f845..4c887fa3c1c8 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_factory.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+@@ -6,6 +6,7 @@
+
+ #include <memory>
+
++#include "ui/ozone/platform/wayland/host/wayland_popup.h"
+ #include "ui/ozone/platform/wayland/host/wayland_surface.h"
+ #include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+@@ -21,7 +22,7 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
+ case PlatformWindowType::kMenu:
+ case PlatformWindowType::kPopup:
+ // TODO(msisov): Add WaylandPopup.
+- window.reset(new WaylandWindow(delegate, connection));
++ window.reset(new WaylandPopup(delegate, connection));
+ break;
+ case PlatformWindowType::kTooltip:
+ // TODO(msisov): Add WaylandSubsurface.
+diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+index e85236ce47d7..62b54680e9e7 100644
+--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+@@ -12,10 +12,11 @@
+ #include "base/nix/xdg_util.h"
+ #include "ui/events/event_constants.h"
+ #include "ui/gfx/geometry/rect.h"
++#include "ui/ozone/platform/wayland/common/wayland_util.h"
+ #include "ui/ozone/platform/wayland/host/wayland_connection.h"
+ #include "ui/ozone/platform/wayland/host/wayland_pointer.h"
++#include "ui/ozone/platform/wayland/host/wayland_popup.h"
+ #include "ui/ozone/platform/wayland/host/wayland_surface.h"
+-#include "ui/ozone/platform/wayland/host/wayland_window.h"
+ #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+
+ namespace ui {
+@@ -268,38 +269,46 @@ XDGPopupWrapperImpl::~XDGPopupWrapperImpl() = default;
+
+ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
+ const gfx::Rect& bounds) {
+- if (connection->shell())
+- return InitializeStable(connection, bounds);
+- else if (connection->shell_v6())
+- return InitializeV6(connection, bounds);
+- NOTREACHED() << "Wrong shell protocol";
+- return false;
+-}
+-
+-bool XDGPopupWrapperImpl::InitializeStable(WaylandConnection* connection,
+- const gfx::Rect& bounds) {
+- static const struct xdg_popup_listener xdg_popup_listener = {
+- &XDGPopupWrapperImpl::ConfigureStable,
+- &XDGPopupWrapperImpl::PopupDoneStable,
+- };
++ if (!connection->shell() && !connection->shell_v6()) {
++ NOTREACHED() << "Wrong shell protocol";
++ return false;
++ }
+
+- XDGSurfaceWrapperImpl* parent_xdg_surface;
++ XDGSurfaceWrapperImpl* parent_xdg_surface = nullptr;
+ // If the parent window is a popup, the surface of that popup must be used as
+ // a parent.
+- if (wayland_window_->parent_window()->shell_popup()) {
+- XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>(
+- wayland_window_->parent_window()->shell_popup());
++ if (wl::IsMenuType(wayland_window_->parent_window()->type())) {
++ auto* wayland_popup =
++ static_cast<WaylandPopup*>(wayland_window_->parent_window());
++ XDGPopupWrapperImpl* popup =
++ static_cast<XDGPopupWrapperImpl*>(wayland_popup->shell_popup());
+ parent_xdg_surface = popup->xdg_surface();
+ } else {
+ WaylandSurface* wayland_surface =
+ static_cast<WaylandSurface*>(wayland_window_->parent_window());
+- parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>(
+- wayland_surface->shell_surface());
++ parent_xdg_surface =
++ static_cast<XDGSurfaceWrapperImpl*>(wayland_surface->shell_surface());
+ }
+
+- if (!parent_xdg_surface)
++ if (!xdg_surface_ || !parent_xdg_surface)
+ return false;
+
++ if (connection->shell())
++ return InitializeStable(connection, bounds, parent_xdg_surface);
++ else if (connection->shell_v6())
++ return InitializeV6(connection, bounds, parent_xdg_surface);
++ return false;
++}
++
++bool XDGPopupWrapperImpl::InitializeStable(
++ WaylandConnection* connection,
++ const gfx::Rect& bounds,
++ XDGSurfaceWrapperImpl* parent_xdg_surface) {
++ static const struct xdg_popup_listener xdg_popup_listener = {
++ &XDGPopupWrapperImpl::ConfigureStable,
++ &XDGPopupWrapperImpl::PopupDoneStable,
++ };
++
+ struct xdg_positioner* positioner = CreatePositionerStable(
+ connection, wayland_window_->parent_window(), bounds);
+ if (!positioner)
+@@ -369,7 +378,7 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
+ MenuType menu_type = MenuType::TYPE_UNKNOWN;
+ if (is_right_click_menu)
+ menu_type = MenuType::TYPE_RIGHT_CLICK;
+- else if (parent_window->shell_popup())
++ else if (wl::IsMenuType(parent_window->type()))
+ menu_type = MenuType::TYPE_3DOT_CHILD_MENU;
+ else
+ menu_type = MenuType::TYPE_3DOT_PARENT_MENU;
+@@ -390,33 +399,15 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
+ return positioner;
+ }
+
+-bool XDGPopupWrapperImpl::InitializeV6(WaylandConnection* connection,
+- const gfx::Rect& bounds) {
++bool XDGPopupWrapperImpl::InitializeV6(
++ WaylandConnection* connection,
++ const gfx::Rect& bounds,
++ XDGSurfaceWrapperImpl* parent_xdg_surface) {
+ static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
+ &XDGPopupWrapperImpl::ConfigureV6,
+ &XDGPopupWrapperImpl::PopupDoneV6,
+ };
+
+- if (!xdg_surface_)
+- return false;
+-
+- XDGSurfaceWrapperImpl* parent_xdg_surface;
+- // If the parent window is a popup, the surface of that popup must be used as
+- // a parent.
+- if (wayland_window_->parent_window()->shell_popup()) {
+- XDGPopupWrapperImpl* popup = reinterpret_cast<XDGPopupWrapperImpl*>(
+- wayland_window_->parent_window()->shell_popup());
+- parent_xdg_surface = popup->xdg_surface();
+- } else {
+- WaylandSurface* wayland_surface =
+- static_cast<WaylandSurface*>(wayland_window_->parent_window());
+- parent_xdg_surface = reinterpret_cast<XDGSurfaceWrapperImpl*>(
+- wayland_surface->shell_surface());
+- }
+-
+- if (!parent_xdg_surface)
+- return false;
+-
+ zxdg_positioner_v6* positioner =
+ CreatePositionerV6(connection, wayland_window_->parent_window(), bounds);
+ if (!positioner)
+@@ -488,7 +479,7 @@ zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6(
+ MenuType menu_type = MenuType::TYPE_UNKNOWN;
+ if (is_right_click_menu)
+ menu_type = MenuType::TYPE_RIGHT_CLICK;
+- else if (parent_window->shell_popup())
++ else if (wl::IsMenuType(parent_window->type()))
+ menu_type = MenuType::TYPE_3DOT_CHILD_MENU;
+ else
+ menu_type = MenuType::TYPE_3DOT_PARENT_MENU;
+diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+index 2a900818ff6a..c0479cfff7fb 100644
+--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
++++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+@@ -27,12 +27,16 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper {
+ const gfx::Rect& bounds) override;
+
+ private:
+- bool InitializeStable(WaylandConnection* connection, const gfx::Rect& bounds);
++ bool InitializeStable(WaylandConnection* connection,
++ const gfx::Rect& bounds,
++ XDGSurfaceWrapperImpl* parent_xdg_surface);
+ struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
+
+- bool InitializeV6(WaylandConnection* connection, const gfx::Rect& bounds);
++ bool InitializeV6(WaylandConnection* connection,
++ const gfx::Rect& bounds,
++ XDGSurfaceWrapperImpl* parent_xdg_surface);
+ struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
+--
+2.24.1
+
diff --git a/0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch b/0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch
new file mode 100644
index 000000000000..62ceae75d155
--- /dev/null
+++ b/0007-ozone-wayland-Extract-subsurface-from-WaylandWindow.patch
@@ -0,0 +1,347 @@
+From 33a754dd22a0fa37654b569232ffd606aaa5e3b9 Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Wed, 11 Dec 2019 10:04:19 +0000
+Subject: [PATCH 7/9] ozone/wayland: Extract subsurface from WaylandWindow
+
+This CL does not bring any functional changes, but rather moves
+the subsurface methods to WaylandSubsurface.
+
+Test: ozone_unittests
+Bug: 1028919
+Change-Id: I96dbf21267a80022779cd7eebeb56c96a243128b
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1960265
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Reviewed-by: Michael Spang <spang@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#723758}
+---
+ ui/ozone/platform/wayland/BUILD.gn | 2 +
+ .../wayland/host/wayland_subsurface.cc | 80 +++++++++++++++++++
+ .../wayland/host/wayland_subsurface.h | 37 +++++++++
+ .../platform/wayland/host/wayland_window.cc | 63 ++-------------
+ .../platform/wayland/host/wayland_window.h | 9 +--
+ .../wayland/host/wayland_window_factory.cc | 4 +-
+ 6 files changed, 127 insertions(+), 68 deletions(-)
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_subsurface.cc
+ create mode 100644 ui/ozone/platform/wayland/host/wayland_subsurface.h
+
+diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
+index 4bfe93352f34..f6f21cdb0161 100644
+--- a/ui/ozone/platform/wayland/BUILD.gn
++++ b/ui/ozone/platform/wayland/BUILD.gn
+@@ -93,6 +93,8 @@ source_set("wayland") {
+ "host/wayland_shm.h",
+ "host/wayland_shm_buffer.cc",
+ "host/wayland_shm_buffer.h",
++ "host/wayland_subsurface.cc",
++ "host/wayland_subsurface.h",
+ "host/wayland_surface.cc",
+ "host/wayland_surface.h",
+ "host/wayland_touch.cc",
+diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+new file mode 100644
+index 000000000000..d261b910fc97
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+@@ -0,0 +1,80 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
++
++#include "ui/ozone/platform/wayland/common/wayland_util.h"
++#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
++#include "ui/ozone/platform/wayland/host/wayland_connection.h"
++#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
++
++namespace ui {
++
++WaylandSubsurface::WaylandSubsurface(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection)
++ : WaylandWindow(delegate, connection) {}
++
++WaylandSubsurface::~WaylandSubsurface() = default;
++
++void WaylandSubsurface::Show(bool inactive) {
++ CreateSubsurface();
++ UpdateBufferScale(false);
++}
++
++void WaylandSubsurface::Hide() {
++ subsurface_.reset();
++
++ // Detach buffer from surface in order to completely shutdown menus and
++ // tooltips, and release resources.
++ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
++}
++
++bool WaylandSubsurface::IsVisible() const {
++ return !!subsurface_;
++}
++
++void WaylandSubsurface::CreateSubsurface() {
++ // Since Aura does not not provide a reference parent window, needed by
++ // Wayland, we get the current focused window to place and show the tooltips.
++ auto* parent_window =
++ connection()->wayland_window_manager()->GetCurrentFocusedWindow();
++
++ // Tooltip creation is an async operation. By the time Aura actually creates
++ // the tooltip, it is possible that the user has already moved the
++ // mouse/pointer out of the window that triggered the tooptip. In this case,
++ // parent_window is NULL.
++ if (!parent_window)
++ return;
++
++ wl_subcompositor* subcompositor = connection()->subcompositor();
++ DCHECK(subcompositor);
++ subsurface_.reset(wl_subcompositor_get_subsurface(subcompositor, surface(),
++ parent_window->surface()));
++
++ // Chromium positions tooltip windows in screen coordinates, but Wayland
++ // requires them to be in local surface coordinates a.k.a relative to parent
++ // window.
++ const auto parent_bounds_dip =
++ gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale());
++ auto new_bounds_dip =
++ wl::TranslateBoundsToParentCoordinates(GetBounds(), parent_bounds_dip);
++ auto bounds_px =
++ gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale() / buffer_scale());
++
++ DCHECK(subsurface_);
++ // Convert position to DIP.
++ wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(),
++ bounds_px.y() / buffer_scale());
++ wl_subsurface_set_desync(subsurface_.get());
++ wl_surface_commit(parent_window->surface());
++ connection()->ScheduleFlush();
++}
++
++bool WaylandSubsurface::OnInitialize(PlatformWindowInitProperties properties) {
++ // TODO(msisov): if the subsurface is not provided with a parent widget, then
++ // it must always use a focused window
++ return true;
++}
++
++} // namespace ui
+diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.h b/ui/ozone/platform/wayland/host/wayland_subsurface.h
+new file mode 100644
+index 000000000000..fd159a7bd465
+--- /dev/null
++++ b/ui/ozone/platform/wayland/host/wayland_subsurface.h
+@@ -0,0 +1,37 @@
++// Copyright 2019 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_
++#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_
++
++#include "ui/ozone/platform/wayland/host/wayland_window.h"
++
++namespace ui {
++
++class WaylandSubsurface : public WaylandWindow {
++ public:
++ WaylandSubsurface(PlatformWindowDelegate* delegate,
++ WaylandConnection* connection);
++ ~WaylandSubsurface() override;
++
++ // PlatformWindow overrides:
++ void Show(bool inactive) override;
++ void Hide() override;
++ bool IsVisible() const override;
++
++ private:
++ // WaylandWindow overrides:
++ bool OnInitialize(PlatformWindowInitProperties properties) override;
++
++ // Creates (if necessary) and shows a subsurface window.
++ void CreateSubsurface();
++
++ wl::Object<wl_subsurface> subsurface_;
++
++ DISALLOW_COPY_AND_ASSIGN(WaylandSubsurface);
++};
++
++} // namespace ui
++
++#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
+index 045f922a759e..c752ad3c0048 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window.cc
+@@ -75,45 +75,6 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
+ return gfx::kNullAcceleratedWidget;
+ return surface_.id();
+ }
+-
+-void WaylandWindow::CreateAndShowTooltipSubSurface() {
+- // Since Aura does not not provide a reference parent window, needed by
+- // Wayland, we get the current focused window to place and show the tooltips.
+- auto* parent_window =
+- connection_->wayland_window_manager()->GetCurrentFocusedWindow();
+-
+- // Tooltip creation is an async operation. By the time Aura actually creates
+- // the tooltip, it is possible that the user has already moved the
+- // mouse/pointer out of the window that triggered the tooptip. In this case,
+- // parent_window is NULL.
+- if (!parent_window)
+- return;
+-
+- wl_subcompositor* subcompositor = connection_->subcompositor();
+- DCHECK(subcompositor);
+- tooltip_subsurface_.reset(wl_subcompositor_get_subsurface(
+- subcompositor, surface_.get(), parent_window->surface()));
+-
+- // Chromium positions tooltip windows in screen coordinates, but Wayland
+- // requires them to be in local surface coordinates aka relative to parent
+- // window.
+- const auto parent_bounds_dip =
+- gfx::ScaleToRoundedRect(parent_window->GetBounds(), 1.0 / ui_scale_);
+- auto new_bounds_dip =
+- wl::TranslateBoundsToParentCoordinates(bounds_px_, parent_bounds_dip);
+- auto bounds_px =
+- gfx::ScaleToRoundedRect(new_bounds_dip, ui_scale_ / buffer_scale_);
+-
+- DCHECK(tooltip_subsurface_);
+- // 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::SetPointerFocus(bool focus) {
+ has_pointer_focus_ = focus;
+
+@@ -125,19 +86,11 @@ void WaylandWindow::SetPointerFocus(bool focus) {
+ }
+
+ void WaylandWindow::Show(bool inactive) {
+- DCHECK(is_tooltip_);
+- CreateAndShowTooltipSubSurface();
+-
+- UpdateBufferScale(false);
++ NOTREACHED();
+ }
+
+ void WaylandWindow::Hide() {
+- DCHECK(is_tooltip_);
+- tooltip_subsurface_.reset();
+-
+- // Detach buffer from surface in order to completely shutdown menus and
+- // tooltips, and release resources.
+- connection_->buffer_manager_host()->ResetSurfaceContents(GetWidget());
++ NOTREACHED();
+ }
+
+ void WaylandWindow::Close() {
+@@ -145,7 +98,8 @@ void WaylandWindow::Close() {
+ }
+
+ bool WaylandWindow::IsVisible() const {
+- return !!tooltip_subsurface_;
++ NOTREACHED();
++ return false;
+ }
+
+ void WaylandWindow::PrepareForShutdown() {}
+@@ -305,7 +259,7 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
+ // Parent window of the main menu window is not a menu, but rather an
+ // xdg surface.
+ DCHECK(!wl::IsMenuType(parent_window_->type()) ||
+- !parent_window_->is_tooltip_);
++ parent_window_->type() != PlatformWindowType::kTooltip);
+ auto* window =
+ connection_->wayland_window_manager()->GetCurrentFocusedWindow();
+ if (window) {
+@@ -377,9 +331,6 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
+
+ connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
+
+- if (type_ == ui::PlatformWindowType::kTooltip)
+- is_tooltip_ = true;
+-
+ if (!OnInitialize(std::move(properties)))
+ return false;
+
+@@ -544,10 +495,6 @@ bool WaylandWindow::IsOpaqueWindow() const {
+ return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow;
+ }
+
+-bool WaylandWindow::OnInitialize(PlatformWindowInitProperties properties) {
+- return true;
+-}
+-
+ // static
+ void WaylandWindow::Enter(void* data,
+ struct wl_surface* wl_surface,
+diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
+index 3eca745b38c4..08658f1df87c 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window.h
++++ b/ui/ozone/platform/wayland/host/wayland_window.h
+@@ -178,10 +178,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ // Initializes the WaylandWindow with supplied properties.
+ bool Initialize(PlatformWindowInitProperties properties);
+
+- // Creates (if necessary) and show subsurface window, to host
+- // tooltip's content.
+- void CreateAndShowTooltipSubSurface();
+-
+ // Returns a root parent window.
+ WaylandWindow* GetRootParentWindow();
+
+@@ -202,7 +198,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ bool IsOpaqueWindow() const;
+
+ // Additional initialization of derived classes.
+- virtual bool OnInitialize(PlatformWindowInitProperties properties);
++ virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0;
+
+ // wl_surface_listener
+ static void Enter(void* data,
+@@ -218,7 +214,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ WaylandWindow* child_window_ = nullptr;
+
+ wl::Object<wl_surface> surface_;
+- wl::Object<wl_subsurface> tooltip_subsurface_;
+
+ // The current cursor bitmap (immutable).
+ scoped_refptr<BitmapCursorOzone> bitmap_;
+@@ -243,8 +238,6 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+ // Stores current opacity of the window. Set on ::Initialize call.
+ ui::PlatformWindowOpacity opacity_;
+
+- bool is_tooltip_ = false;
+-
+ // For top level window, stores IDs of outputs that the window is currently
+ // rendered at.
+ //
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+index 4c887fa3c1c8..869c1d0aa1f8 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_factory.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+@@ -7,8 +7,8 @@
+ #include <memory>
+
+ #include "ui/ozone/platform/wayland/host/wayland_popup.h"
++#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
+ #include "ui/ozone/platform/wayland/host/wayland_surface.h"
+-#include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+ namespace ui {
+
+@@ -26,7 +26,7 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
+ break;
+ case PlatformWindowType::kTooltip:
+ // TODO(msisov): Add WaylandSubsurface.
+- window.reset(new WaylandWindow(delegate, connection));
++ window.reset(new WaylandSubsurface(delegate, connection));
+ break;
+ case PlatformWindowType::kWindow:
+ case PlatformWindowType::kBubble:
+--
+2.24.1
+
diff --git a/0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch b/0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch
new file mode 100644
index 000000000000..a6c9bc9f2714
--- /dev/null
+++ b/0008-ozone-wayland-Recreate-ShellSurface-and-ShellPopup-o.patch
@@ -0,0 +1,1148 @@
+From 8f007d6dd7e450f4661e49a7053ed64e4cafbc1a Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Thu, 12 Dec 2019 13:22:46 +0000
+Subject: [PATCH 8/9] ozone/wayland: Recreate ShellSurface and ShellPopup on
+ Show calls.
+
+In Wayland, there is no explicit method for showing surfaces. Instead,
+one must create/destroy resources to trigger mapping of the
+base wl_surface and show xdg surfaces and xdg popups on a screen.
+
+Actually, we have already been doing so for WaylandPopups and
+WaylandSubsurfaces, but WaylandSurface just ignored that.
+
+This CL brings the following changes:
+1) WaylandSurface: create ShellSurface on Show and destroy on Hide.
+If Show fails, tell the delegate to Close the window. Also, restore
+min and max size, title and app id on each Show call.
+2) WaylandPopup: do no create ShellPopup on Initialize, but rather
+wait until Show call comes.
+3) Tests: Instead of unretained implementation, use the template
+that creates resources and manages their lifetime automatically
+so that MockXdgPopup and MockXdgSurface could be destroyed
+automatically once the client destroyes the allocated resources.
+4) WaylandSubsurface: do not try to Show if the subsurface has already
+shown or do not try to Hide if the subsurface has already been
+hidden.
+5) Also added 3 tests to exercise above changes.
+
+SetsPropertiesOnShow
+
+Test: DestroysCreatesSurfaceOnHideShow, DestroysCreatesPopupsOnHideShow
+Bug: 578890
+Change-Id: Ifb873eb1b089775e945705b1254ac048eddbb4e8
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1961201
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Reviewed-by: Michael Spang <spang@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#724184}
+---
+ .../platform/wayland/host/wayland_popup.cc | 41 +++--
+ .../platform/wayland/host/wayland_popup.h | 2 +-
+ .../wayland/host/wayland_subsurface.cc | 6 +
+ .../platform/wayland/host/wayland_surface.cc | 78 +++++---
+ .../platform/wayland/host/wayland_surface.h | 18 +-
+ .../host/wayland_window_manager_unittests.cc | 13 +-
+ .../wayland/host/wayland_window_unittest.cc | 170 +++++++++++++++---
+ ui/ozone/platform/wayland/test/mock_surface.h | 18 +-
+ .../platform/wayland/test/mock_xdg_popup.cc | 10 +-
+ .../platform/wayland/test/mock_xdg_popup.h | 6 +-
+ .../platform/wayland/test/mock_xdg_shell.cc | 9 +-
+ .../platform/wayland/test/mock_xdg_surface.cc | 116 +++++++-----
+ .../platform/wayland/test/mock_xdg_surface.h | 69 ++++---
+ .../platform/wayland/test/wayland_test.cc | 2 +
+ 14 files changed, 402 insertions(+), 156 deletions(-)
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc
+index 45aac6e51bfc..98cadd54555c 100644
+--- a/ui/ozone/platform/wayland/host/wayland_popup.cc
++++ b/ui/ozone/platform/wayland/host/wayland_popup.cc
+@@ -18,9 +18,9 @@ WaylandPopup::WaylandPopup(PlatformWindowDelegate* delegate,
+
+ WaylandPopup::~WaylandPopup() = default;
+
+-void WaylandPopup::CreateShellPopup() {
++bool WaylandPopup::CreateShellPopup() {
+ if (GetBounds().IsEmpty())
+- return;
++ return false;
+
+ // TODO(jkim): Consider how to support DropArrow window on tabstrip.
+ // When it starts dragging, as described the protocol, https://goo.gl/1Mskq3,
+@@ -30,8 +30,8 @@ void WaylandPopup::CreateShellPopup() {
+ // a crash when aura::Window is destroyed.
+ // https://crbug.com/875164
+ if (connection()->IsDragInProgress()) {
+- LOG(ERROR) << "Wayland can't create a popup window during dragging.";
+- return;
++ LOG(WARNING) << "Wayland can't create a popup window during dragging.";
++ return false;
+ }
+
+ DCHECK(parent_window() && !shell_popup_);
+@@ -40,30 +40,40 @@ void WaylandPopup::CreateShellPopup() {
+
+ ShellObjectFactory factory;
+ shell_popup_ = factory.CreateShellPopupWrapper(connection(), this, bounds_px);
+- if (!shell_popup_)
+- CHECK(false) << "Failed to create Wayland shell popup";
++ if (!shell_popup_) {
++ LOG(ERROR) << "Failed to create Wayland shell popup";
++ return false;
++ }
+
+ parent_window()->set_child_window(this);
++ return true;
+ }
+
+ void WaylandPopup::Show(bool inactive) {
++ if (shell_popup_)
++ return;
++
+ set_keyboard_focus(true);
+
+- if (!shell_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.
+- SetBounds(gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale()));
+- CreateShellPopup();
+- connection()->ScheduleFlush();
++ // 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.
++ SetBounds(gfx::ScaleToRoundedRect(GetBounds(), 1.0 / ui_scale()));
++ if (!CreateShellPopup()) {
++ Close();
++ return;
+ }
+
+ UpdateBufferScale(false);
++ connection()->ScheduleFlush();
+ }
+
+ void WaylandPopup::Hide() {
++ if (!shell_popup_)
++ return;
++
+ if (child_window())
+ child_window()->Hide();
+
+@@ -155,7 +165,6 @@ bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
+ // If parent window is known in advanced, we may set the scale early.
+ SetBufferScale(parent_window()->buffer_scale(), false);
+ set_ui_scale(parent_window()->ui_scale());
+- CreateShellPopup();
+ return true;
+ }
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_popup.h b/ui/ozone/platform/wayland/host/wayland_popup.h
+index 2d45986ba36a..7bc48bb29a06 100644
+--- a/ui/ozone/platform/wayland/host/wayland_popup.h
++++ b/ui/ozone/platform/wayland/host/wayland_popup.h
+@@ -32,7 +32,7 @@ class WaylandPopup : public WaylandWindow {
+ bool OnInitialize(PlatformWindowInitProperties properties) override;
+
+ // Creates a popup window, which is visible as a menu window.
+- void CreateShellPopup();
++ bool CreateShellPopup();
+
+ // Returns bounds with origin relative to parent window's origin.
+ gfx::Rect AdjustPopupWindowPosition();
+diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+index d261b910fc97..94ca613ecaf1 100644
+--- a/ui/ozone/platform/wayland/host/wayland_subsurface.cc
++++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+@@ -18,11 +18,17 @@ WaylandSubsurface::WaylandSubsurface(PlatformWindowDelegate* delegate,
+ WaylandSubsurface::~WaylandSubsurface() = default;
+
+ void WaylandSubsurface::Show(bool inactive) {
++ if (subsurface_)
++ return;
++
+ CreateSubsurface();
+ UpdateBufferScale(false);
+ }
+
+ void WaylandSubsurface::Hide() {
++ if (!subsurface_)
++ return;
++
+ subsurface_.reset();
+
+ // Detach buffer from surface in order to completely shutdown menus and
+diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
+index cfd4349db885..b800a526e64e 100644
+--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
++++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
+@@ -10,6 +10,7 @@
+ #include "ui/gfx/native_widget_types.h"
+ #include "ui/ozone/platform/wayland/host/shell_object_factory.h"
+ #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
++#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
+ #include "ui/ozone/platform/wayland/host/wayland_connection.h"
+ #include "ui/platform_window/platform_window_handler/wm_drop_handler.h"
+
+@@ -35,11 +36,18 @@ WaylandSurface::~WaylandSurface() {
+ }
+ }
+
+-void WaylandSurface::CreateShellSurface() {
++bool WaylandSurface::CreateShellSurface() {
+ ShellObjectFactory factory;
+ shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this);
+- if (!shell_surface_)
+- CHECK(false) << "Failed to initialize Wayland shell surface";
++ if (!shell_surface_) {
++ LOG(ERROR) << "Failed to create a ShellSurface.";
++ return false;
++ }
++
++ shell_surface_->SetAppId(app_id_);
++ shell_surface_->SetTitle(window_title_);
++ SetSizeConstraints();
++ return true;
+ }
+
+ void WaylandSurface::ApplyPendingBounds() {
+@@ -77,12 +85,33 @@ void WaylandSurface::StartDrag(const ui::OSExchangeData& data,
+ }
+
+ void WaylandSurface::Show(bool inactive) {
++ if (shell_surface_)
++ return;
++
++ if (!CreateShellSurface()) {
++ Close();
++ return;
++ }
++
+ set_keyboard_focus(true);
+- // TODO(msisov): recreate |shell_surface_| on show calls.
++ UpdateBufferScale(false);
+ }
+
+ void WaylandSurface::Hide() {
+- // TODO(msisov): destroy |shell_surface_| on hide calls.
++ if (!shell_surface_)
++ return;
++
++ if (child_window()) {
++ child_window()->Hide();
++ set_child_window(nullptr);
++ }
++
++ shell_surface_.reset();
++ connection()->ScheduleFlush();
++
++ // Detach buffer from surface in order to completely shutdown menus and
++ // tooltips, and release resources.
++ connection()->buffer_manager_host()->ResetSurfaceContents(GetWidget());
+ }
+
+ bool WaylandSurface::IsVisible() const {
+@@ -92,9 +121,15 @@ bool WaylandSurface::IsVisible() const {
+ }
+
+ void WaylandSurface::SetTitle(const base::string16& title) {
+- DCHECK(shell_surface_);
+- shell_surface_->SetTitle(title);
+- connection()->ScheduleFlush();
++ if (window_title_ == title)
++ return;
++
++ window_title_ = title;
++
++ if (shell_surface_) {
++ shell_surface_->SetTitle(title);
++ connection()->ScheduleFlush();
++ }
+ }
+
+ void WaylandSurface::ToggleFullscreen() {
+@@ -178,15 +213,9 @@ void WaylandSurface::SizeConstraintsChanged() {
+ return;
+
+ DCHECK(delegate());
+- auto min_size = delegate()->GetMinimumSizeForWindow();
+- auto max_size = delegate()->GetMaximumSizeForWindow();
+-
+- if (min_size.has_value())
+- shell_surface_->SetMinSize(min_size->width(), min_size->height());
+- if (max_size.has_value())
+- shell_surface_->SetMaxSize(max_size->width(), max_size->height());
+-
+- connection()->ScheduleFlush();
++ min_size_ = delegate()->GetMinimumSizeForWindow();
++ max_size_ = delegate()->GetMaximumSizeForWindow();
++ SetSizeConstraints();
+ }
+
+ void WaylandSurface::HandleSurfaceConfigure(int32_t width,
+@@ -315,10 +344,8 @@ void WaylandSurface::OnDragSessionClose(uint32_t dnd_action) {
+ }
+
+ bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) {
+- CreateShellSurface();
+- if (shell_surface_ && !properties.wm_class_class.empty())
+- shell_surface_->SetAppId(properties.wm_class_class);
+- return !!shell_surface_;
++ app_id_ = properties.wm_class_class;
++ return true;
+ }
+
+ bool WaylandSurface::IsMinimized() const {
+@@ -345,4 +372,13 @@ WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() {
+ return static_cast<WmMoveResizeHandler*>(this);
+ }
+
++void WaylandSurface::SetSizeConstraints() {
++ if (min_size_.has_value())
++ shell_surface_->SetMinSize(min_size_->width(), min_size_->height());
++ if (max_size_.has_value())
++ shell_surface_->SetMaxSize(max_size_->width(), max_size_->height());
++
++ connection()->ScheduleFlush();
++}
++
+ } // namespace ui
+diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
+index 0f7204db3c48..677eaca6ef56 100644
+--- a/ui/ozone/platform/wayland/host/wayland_surface.h
++++ b/ui/ozone/platform/wayland/host/wayland_surface.h
+@@ -76,10 +76,13 @@ class WaylandSurface : public WaylandWindow,
+ void MaybeTriggerPendingStateChange();
+
+ // Creates a surface window, which is visible as a main window.
+- void CreateShellSurface();
++ bool CreateShellSurface();
+
+ WmMoveResizeHandler* AsWmMoveResizeHandler();
+
++ // Propagates the |min_size_| and |max_size_| to the ShellSurface.
++ void SetSizeConstraints();
++
+ // Wrappers around shell surface.
+ std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
+
+@@ -106,6 +109,19 @@ class WaylandSurface : public WaylandWindow,
+ bool is_active_ = false;
+ bool is_minimizing_ = false;
+
++ // Id of the chromium app passed through
++ // PlatformWindowInitProperties::wm_class_class. This is used by Wayland
++ // compositor to identify the app, unite it's windows into the same stack of
++ // windows and find *.desktop file to set various preferences including icons.
++ std::string app_id_;
++
++ // Title of the ShellSurface.
++ base::string16 window_title_;
++
++ // Max and min sizes of the WaylandSurface window.
++ base::Optional<gfx::Size> min_size_;
++ base::Optional<gfx::Size> max_size_;
++
+ DISALLOW_COPY_AND_ASSIGN(WaylandSurface);
+ };
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
+index 64a387723560..a4b1fc7d9436 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
+@@ -36,8 +36,11 @@ class WaylandWindowManagerTest : public WaylandTest {
+ PlatformWindowInitProperties properties;
+ properties.bounds = bounds;
+ properties.type = type;
+- return WaylandWindow::Create(delegate, connection_.get(),
+- std::move(properties));
++ auto window = WaylandWindow::Create(delegate, connection_.get(),
++ std::move(properties));
++ if (window)
++ window->Show(false);
++ return window;
+ }
+
+ WaylandWindowManager* manager_ = nullptr;
+@@ -87,6 +90,9 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) {
+
+ auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
+ kDefaultBounds, &delegate);
++ // When window is shown, it automatically gets keyboard focus. Reset it.
++ window_->set_keyboard_focus(false);
++ window1->set_keyboard_focus(false);
+
+ Sync();
+
+@@ -121,6 +127,9 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) {
+
+ auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
+ kDefaultBounds, &delegate);
++ // When window is shown, it automatically gets keyboard focus. Reset it.
++ window_->set_keyboard_focus(false);
++ window1->set_keyboard_focus(false);
+
+ Sync();
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+index 132f740b0eb1..f56b96690eea 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+@@ -128,11 +128,7 @@ class WaylandWindowTest : public WaylandTest {
+ }
+ }
+
+- // Depending on a shell version, xdg_surface_ or xdg_toplevel surface should
+- // get the mock calls. This method decided, which surface to use.
+- wl::MockXdgSurface* GetXdgSurface() {
+- return xdg_surface_->xdg_toplevel();
+- }
++ wl::MockXdgTopLevel* GetXdgToplevel() { return xdg_surface_->xdg_toplevel(); }
+
+ void AddStateToWlArray(uint32_t state, wl_array* states) {
+ *static_cast<uint32_t*>(wl_array_add(states, sizeof state)) = state;
+@@ -162,8 +158,11 @@ class WaylandWindowTest : public WaylandTest {
+ properties.type = type;
+ properties.parent_widget = parent_widget;
+
+- return WaylandWindow::Create(delegate, connection_.get(),
+- std::move(properties));
++ auto window = WaylandWindow::Create(delegate, connection_.get(),
++ std::move(properties));
++ if (window)
++ window->Show(false);
++ return window;
+ }
+
+ void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) {
+@@ -213,7 +212,7 @@ class WaylandWindowTest : public WaylandTest {
+ };
+
+ TEST_P(WaylandWindowTest, SetTitle) {
+- EXPECT_CALL(*GetXdgSurface(), SetTitle(StrEq("hello")));
++ EXPECT_CALL(*GetXdgToplevel(), SetTitle(StrEq("hello")));
+ window_->SetTitle(base::ASCIIToUTF16("hello"));
+ }
+
+@@ -229,7 +228,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+
+ auto active_maximized = MakeStateArray(
+ {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
+- EXPECT_CALL(*GetXdgSurface(), SetMaximized());
++ EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
+ kMaximizedBounds.height()));
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
+@@ -267,7 +266,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+ OnWindowStateChanged(Eq(PlatformWindowState::kNormal)));
+ EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
+- EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
++ EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
+ window_->Restore();
+ // Reinitialize wl_array, which removes previous old states.
+ auto active = InitializeWlArrayWithActivatedState();
+@@ -283,7 +282,7 @@ TEST_P(WaylandWindowTest, Minimize) {
+ SendConfigureEvent(0, 0, 1, states.get());
+ Sync();
+
+- EXPECT_CALL(*GetXdgSurface(), SetMinimized());
++ EXPECT_CALL(*GetXdgToplevel(), SetMinimized());
+ // Wayland compositor doesn't notify clients about minimized state, but rather
+ // if a window is not activated. Thus, a WaylandWindow marks itself as being
+ // minimized and as soon as a configuration event with not activated state
+@@ -319,7 +318,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
+
+ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
+
+- EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)));
+ window_->ToggleFullscreen();
+@@ -330,7 +329,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
+ SendConfigureEvent(0, 0, 2, states.get());
+ Sync();
+
+- EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
++ EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PlatformWindowState::kNormal)));
+ window_->Restore();
+@@ -347,7 +346,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) {
+
+ // The state must not be changed to the fullscreen before the surface is
+ // activated.
+- EXPECT_CALL(*GetXdgSurface(), SetFullscreen()).Times(0);
++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->ToggleFullscreen();
+ // The state of the window must still be a normal one.
+@@ -357,7 +356,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) {
+
+ // Once the surface will be activated, the window will automatically trigger
+ // the state change.
+- EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)));
+
+@@ -391,7 +390,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
+
+ auto active_maximized = MakeStateArray(
+ {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
+- EXPECT_CALL(*GetXdgSurface(), SetMaximized());
++ EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
+ kMaximizedBounds.height()));
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
+@@ -404,7 +403,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
+ Sync();
+ VerifyAndClearExpectations();
+
+- EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
++ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
+ kMaximizedBounds.height()));
+ EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
+@@ -419,8 +418,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+ kNormalBounds.height()));
+- EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
+- EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
++ EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
++ EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
+ EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PlatformWindowState::kNormal)));
+@@ -841,7 +840,7 @@ TEST_P(WaylandWindowTest, CanDispatchEventToMenuWindowNested) {
+ }
+
+ TEST_P(WaylandWindowTest, DispatchWindowMove) {
+- EXPECT_CALL(*GetXdgSurface(), Move(_));
++ EXPECT_CALL(*GetXdgToplevel(), Move(_));
+ ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(HTCAPTION, gfx::Point());
+ }
+
+@@ -855,7 +854,7 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) {
+ for (const int value : hit_test_values) {
+ {
+ uint32_t direction = wl::IdentifyDirection(*(connection_.get()), value);
+- EXPECT_CALL(*GetXdgSurface(), Resize(_, Eq(direction)));
++ EXPECT_CALL(*GetXdgToplevel(), Resize(_, Eq(direction)));
+ wm_move_resize_handler->DispatchHostWindowDragMovement(value,
+ gfx::Point());
+ }
+@@ -1092,7 +1091,7 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
+ // shown on another display.
+ auto active_maximized = MakeStateArray(
+ {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
+- EXPECT_CALL(*GetXdgSurface(), SetMaximized());
++ EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
+
+ window_->Maximize();
+ SendConfigureEvent(2493, 1413, 1, active_maximized.get());
+@@ -1252,9 +1251,9 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) {
+ EXPECT_CALL(delegate_, GetMaximumSizeForWindow())
+ .WillOnce(Return(max_size));
+
+- EXPECT_CALL(*GetXdgSurface(), SetMinSize(100, 200))
++ EXPECT_CALL(*GetXdgToplevel(), SetMinSize(100, 200))
+ .Times(has_min_size ? 1 : 0);
+- EXPECT_CALL(*GetXdgSurface(), SetMaxSize(300, 400))
++ EXPECT_CALL(*GetXdgToplevel(), SetMaxSize(300, 400))
+ .Times(has_max_size ? 1 : 0);
+
+ window_->SizeConstraintsChanged();
+@@ -1265,6 +1264,129 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) {
+ }
+ }
+
++TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) {
++ MockPlatformWindowDelegate delegate;
++ auto window = CreateWaylandWindowWithParams(
++ PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
++ gfx::Rect(0, 0, 100, 100), &delegate);
++ ASSERT_TRUE(window);
++
++ Sync();
++
++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
++ EXPECT_TRUE(mock_surface->xdg_surface());
++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel());
++
++ Sync();
++
++ window->Hide();
++
++ Sync();
++
++ EXPECT_FALSE(mock_surface->xdg_surface());
++
++ window->Show(false);
++
++ Sync();
++
++ EXPECT_TRUE(mock_surface->xdg_surface());
++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel());
++}
++
++TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) {
++ MockPlatformWindowDelegate delegate;
++ auto window = CreateWaylandWindowWithParams(
++ PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50),
++ &delegate);
++ ASSERT_TRUE(window);
++
++ Sync();
++
++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
++ EXPECT_TRUE(mock_surface->xdg_surface());
++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup());
++
++ Sync();
++
++ window->Hide();
++
++ Sync();
++
++ EXPECT_FALSE(mock_surface->xdg_surface());
++
++ window->Show(false);
++
++ Sync();
++
++ EXPECT_TRUE(mock_surface->xdg_surface());
++ EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup());
++}
++
++// Tests that if the window gets hidden and shown again, the title, app id and
++// size constraints remain the same.
++TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
++ constexpr char kAppId[] = "wayland_test";
++ const base::string16 kTitle(base::UTF8ToUTF16("WaylandWindowTest"));
++
++ PlatformWindowInitProperties properties;
++ properties.bounds = gfx::Rect(0, 0, 100, 100);
++ properties.type = PlatformWindowType::kWindow;
++ properties.wm_class_class = kAppId;
++
++ MockPlatformWindowDelegate delegate;
++ auto window = WaylandWindow::Create(&delegate, connection_.get(),
++ std::move(properties));
++ DCHECK(window);
++ window->Show(false);
++
++ Sync();
++
++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
++ auto* mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel();
++
++ // Only app id must be set now.
++ EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
++ EXPECT_TRUE(mock_xdg_toplevel->title().empty());
++ EXPECT_TRUE(mock_xdg_toplevel->min_size().IsEmpty());
++ EXPECT_TRUE(mock_xdg_toplevel->max_size().IsEmpty());
++
++ // Now, propagate size constraints and title.
++ base::Optional<gfx::Size> min_size(gfx::Size(1, 1));
++ base::Optional<gfx::Size> max_size(gfx::Size(100, 100));
++ EXPECT_CALL(delegate, GetMinimumSizeForWindow()).WillOnce(Return(min_size));
++ EXPECT_CALL(delegate, GetMaximumSizeForWindow()).WillOnce(Return(max_size));
++
++ EXPECT_CALL(*mock_xdg_toplevel,
++ SetMinSize(min_size.value().width(), min_size.value().height()));
++ EXPECT_CALL(*mock_xdg_toplevel,
++ SetMaxSize(max_size.value().width(), max_size.value().height()));
++ EXPECT_CALL(*mock_xdg_toplevel, SetTitle(base::UTF16ToUTF8(kTitle)));
++
++ window->SetTitle(kTitle);
++ window->SizeConstraintsChanged();
++
++ Sync();
++
++ window->Hide();
++
++ Sync();
++
++ window->Show(false);
++
++ Sync();
++
++ mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel();
++
++ // We can't mock all those methods above as long as the xdg_toplevel is
++ // created and destroyed on each show and hide call. However, it is the same
++ // WaylandSurface object that cached the values we set and must restore them
++ // on Show().
++ EXPECT_EQ(mock_xdg_toplevel->min_size(), min_size.value());
++ EXPECT_EQ(mock_xdg_toplevel->max_size(), max_size.value());
++ EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
++ EXPECT_EQ(mock_xdg_toplevel->title(), base::UTF16ToUTF8(kTitle));
++}
++
+ INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandWindowTest,
+ ::testing::Values(kXdgShellStable));
+diff --git a/ui/ozone/platform/wayland/test/mock_surface.h b/ui/ozone/platform/wayland/test/mock_surface.h
+index 27f7a2c09aab..47dc4680d50b 100644
+--- a/ui/ozone/platform/wayland/test/mock_surface.h
++++ b/ui/ozone/platform/wayland/test/mock_surface.h
+@@ -42,15 +42,10 @@ class MockSurface : public ServerObject {
+ MOCK_METHOD4(DamageBuffer,
+ void(int32_t x, int32_t y, int32_t width, int32_t height));
+
+- void set_xdg_surface(std::unique_ptr<MockXdgSurface> xdg_surface) {
+- xdg_surface_ = std::move(xdg_surface);
++ void set_xdg_surface(MockXdgSurface* xdg_surface) {
++ xdg_surface_ = xdg_surface;
+ }
+- MockXdgSurface* xdg_surface() const { return xdg_surface_.get(); }
+-
+- void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) {
+- xdg_popup_ = std::move(xdg_popup);
+- }
+- MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); }
++ MockXdgSurface* xdg_surface() const { return xdg_surface_; }
+
+ void set_sub_surface(TestSubSurface* sub_surface) {
+ sub_surface_ = sub_surface;
+@@ -62,17 +57,14 @@ class MockSurface : public ServerObject {
+ frame_callback_ = callback_resource;
+ }
+
+- bool has_role() const {
+- return !!xdg_surface_ || !!xdg_popup_ || !!sub_surface_;
+- }
++ bool has_role() const { return !!xdg_surface_ || !!sub_surface_; }
+
+ void AttachNewBuffer(wl_resource* buffer_resource, int32_t x, int32_t y);
+ void ReleasePrevAttachedBuffer();
+ void SendFrameCallback();
+
+ private:
+- std::unique_ptr<MockXdgSurface> xdg_surface_;
+- std::unique_ptr<MockXdgPopup> xdg_popup_;
++ MockXdgSurface* xdg_surface_ = nullptr;
+ TestSubSurface* sub_surface_ = nullptr;
+
+ wl_resource* frame_callback_ = nullptr;
+diff --git a/ui/ozone/platform/wayland/test/mock_xdg_popup.cc b/ui/ozone/platform/wayland/test/mock_xdg_popup.cc
+index ebf449ca3e55..4a92c79edab0 100644
+--- a/ui/ozone/platform/wayland/test/mock_xdg_popup.cc
++++ b/ui/ozone/platform/wayland/test/mock_xdg_popup.cc
+@@ -4,6 +4,8 @@
+
+ #include "ui/ozone/platform/wayland/test/mock_xdg_popup.h"
+
++#include "ui/ozone/platform/wayland/test/mock_xdg_surface.h"
++
+ namespace wl {
+
+ namespace {
+@@ -27,9 +29,11 @@ const struct zxdg_popup_v6_interface kZxdgPopupV6Impl = {
+ &Grab, // grab
+ };
+
+-MockXdgPopup::MockXdgPopup(wl_resource* resource, const void* implementation)
+- : ServerObject(resource) {
+- SetImplementationUnretained(resource, implementation, this);
++MockXdgPopup::MockXdgPopup(wl_resource* resource, wl_resource* surface)
++ : ServerObject(resource), surface_(surface) {
++ auto* mock_xdg_surface = GetUserDataAs<MockXdgSurface>(surface_);
++ if (mock_xdg_surface)
++ mock_xdg_surface->set_xdg_popup(nullptr);
+ }
+
+ MockXdgPopup::~MockXdgPopup() {}
+diff --git a/ui/ozone/platform/wayland/test/mock_xdg_popup.h b/ui/ozone/platform/wayland/test/mock_xdg_popup.h
+index 27b02361d897..61a805130200 100644
+--- a/ui/ozone/platform/wayland/test/mock_xdg_popup.h
++++ b/ui/ozone/platform/wayland/test/mock_xdg_popup.h
+@@ -24,7 +24,7 @@ extern const struct zxdg_popup_v6_interface kZxdgPopupV6Impl;
+
+ class MockXdgPopup : public ServerObject {
+ public:
+- MockXdgPopup(wl_resource* resource, const void* implementation);
++ MockXdgPopup(wl_resource* resource, wl_resource* surface);
+ ~MockXdgPopup() override;
+
+ MOCK_METHOD1(Grab, void(uint32_t serial));
+@@ -42,9 +42,11 @@ class MockXdgPopup : public ServerObject {
+ }
+
+ private:
+- // Position of the popup. Used only with V6.
+ struct TestPositioner::PopupPosition position_;
+
++ // Ground surface for this popup.
++ wl_resource* surface_ = nullptr;
++
+ DISALLOW_COPY_AND_ASSIGN(MockXdgPopup);
+ };
+
+diff --git a/ui/ozone/platform/wayland/test/mock_xdg_shell.cc b/ui/ozone/platform/wayland/test/mock_xdg_shell.cc
+index 1ba63d431015..cd76626a1245 100644
+--- a/ui/ozone/platform/wayland/test/mock_xdg_shell.cc
++++ b/ui/ozone/platform/wayland/test/mock_xdg_shell.cc
+@@ -29,15 +29,16 @@ void GetXdgSurfaceImpl(wl_client* client,
+ wl_resource_post_error(resource, xdg_error, "surface already has a role");
+ return;
+ }
+- wl_resource* xdg_surface_resource = wl_resource_create(
+- client, interface, wl_resource_get_version(resource), id);
+
++ wl_resource* xdg_surface_resource =
++ CreateResourceWithImpl<::testing::NiceMock<MockXdgSurface>>(
++ client, interface, wl_resource_get_version(resource), implementation,
++ id, surface_resource);
+ if (!xdg_surface_resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+- surface->set_xdg_surface(
+- std::make_unique<MockXdgSurface>(xdg_surface_resource, implementation));
++ surface->set_xdg_surface(GetUserDataAs<MockXdgSurface>(xdg_surface_resource));
+ }
+
+ void CreatePositioner(wl_client* client,
+diff --git a/ui/ozone/platform/wayland/test/mock_xdg_surface.cc b/ui/ozone/platform/wayland/test/mock_xdg_surface.cc
+index 35963f84b963..d0bd03add2bd 100644
+--- a/ui/ozone/platform/wayland/test/mock_xdg_surface.cc
++++ b/ui/ozone/platform/wayland/test/mock_xdg_surface.cc
+@@ -4,6 +4,7 @@
+
+ #include <xdg-shell-unstable-v6-server-protocol.h>
+
++#include "ui/ozone/platform/wayland/test/mock_surface.h"
+ #include "ui/ozone/platform/wayland/test/mock_xdg_popup.h"
+ #include "ui/ozone/platform/wayland/test/mock_xdg_surface.h"
+ #include "ui/ozone/platform/wayland/test/test_positioner.h"
+@@ -11,18 +12,26 @@
+ namespace wl {
+
+ void SetTitle(wl_client* client, wl_resource* resource, const char* title) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetTitle(title);
++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource);
++ // As it this can be envoked during construction of the XdgSurface, cache the
++ // result so that tests are able to access that information.
++ toplevel->set_title(title);
++ toplevel->SetTitle(toplevel->title());
+ }
+
+ void SetAppId(wl_client* client, wl_resource* resource, const char* app_id) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetAppId(app_id);
++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource);
++ toplevel->SetAppId(app_id);
++ // As it this can be envoked during construction of the XdgSurface, cache the
++ // result so that tests are able to access that information.
++ toplevel->set_app_id(app_id);
+ }
+
+ void Move(wl_client* client,
+ wl_resource* resource,
+ wl_resource* seat,
+ uint32_t serial) {
+- GetUserDataAs<MockXdgSurface>(resource)->Move(serial);
++ GetUserDataAs<MockXdgTopLevel>(resource)->Move(serial);
+ }
+
+ void Resize(wl_client* client,
+@@ -30,7 +39,7 @@ void Resize(wl_client* client,
+ wl_resource* seat,
+ uint32_t serial,
+ uint32_t edges) {
+- GetUserDataAs<MockXdgSurface>(resource)->Resize(serial, edges);
++ GetUserDataAs<MockXdgTopLevel>(resource)->Resize(serial, edges);
+ }
+
+ void AckConfigure(wl_client* client, wl_resource* resource, uint32_t serial) {
+@@ -48,25 +57,47 @@ void SetWindowGeometry(wl_client* client,
+ }
+
+ void SetMaximized(wl_client* client, wl_resource* resource) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetMaximized();
++ GetUserDataAs<MockXdgTopLevel>(resource)->SetMaximized();
+ }
+
+ void UnsetMaximized(wl_client* client, wl_resource* resource) {
+- GetUserDataAs<MockXdgSurface>(resource)->UnsetMaximized();
++ GetUserDataAs<MockXdgTopLevel>(resource)->UnsetMaximized();
+ }
+
+ void SetFullscreen(wl_client* client,
+ wl_resource* resource,
+ wl_resource* output) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetFullscreen();
++ GetUserDataAs<MockXdgTopLevel>(resource)->SetFullscreen();
+ }
+
+ void UnsetFullscreen(wl_client* client, wl_resource* resource) {
+- GetUserDataAs<MockXdgSurface>(resource)->UnsetFullscreen();
++ GetUserDataAs<MockXdgTopLevel>(resource)->UnsetFullscreen();
+ }
+
+ void SetMinimized(wl_client* client, wl_resource* resource) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetMinimized();
++ GetUserDataAs<MockXdgTopLevel>(resource)->SetMinimized();
++}
++
++void SetMaxSize(wl_client* client,
++ wl_resource* resource,
++ int32_t width,
++ int32_t height) {
++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource);
++ toplevel->SetMaxSize(width, height);
++ // As it this can be envoked during construction of the XdgSurface, cache the
++ // result so that tests are able to access that information.
++ toplevel->set_max_size(gfx::Size(width, height));
++}
++
++void SetMinSize(wl_client* client,
++ wl_resource* resource,
++ int32_t width,
++ int32_t height) {
++ auto* toplevel = GetUserDataAs<MockXdgTopLevel>(resource);
++ toplevel->SetMinSize(width, height);
++ // As it this can be envoked during construction of the XdgSurface, cache the
++ // result so that tests are able to access that information.
++ toplevel->set_min_size(gfx::Size(width, height));
+ }
+
+ void GetTopLevel(wl_client* client, wl_resource* resource, uint32_t id) {
+@@ -120,13 +151,22 @@ void GetXdgPopup(struct wl_client* client,
+ return;
+ }
+
+- wl_resource* xdg_popup_resource = wl_resource_create(
+- client, &xdg_popup_interface, wl_resource_get_version(resource), id);
++ wl_resource* xdg_popup_resource =
++ CreateResourceWithImpl<::testing::NiceMock<MockXdgPopup>>(
++ client, &xdg_popup_interface, wl_resource_get_version(resource),
++ &kXdgPopupImpl, id, resource);
++
++ if (!xdg_popup_resource) {
++ wl_client_post_no_memory(client);
++ return;
++ }
++
++ auto* mock_xdg_popup = GetUserDataAs<MockXdgPopup>(xdg_popup_resource);
++ DCHECK(mock_xdg_popup);
++
+ auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource);
+ DCHECK(positioner);
+
+- auto mock_xdg_popup =
+- std::make_unique<MockXdgPopup>(xdg_popup_resource, &kXdgPopupImpl);
+ mock_xdg_popup->set_position(positioner->position());
+ if (mock_xdg_popup->size().IsEmpty() ||
+ mock_xdg_popup->anchor_rect().IsEmpty()) {
+@@ -135,7 +175,7 @@ void GetXdgPopup(struct wl_client* client,
+ return;
+ }
+
+- mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup));
++ mock_xdg_surface->set_xdg_popup(mock_xdg_popup);
+ }
+
+ void GetZXdgPopupV6(struct wl_client* client,
+@@ -156,13 +196,22 @@ void GetZXdgPopupV6(struct wl_client* client,
+ return;
+ }
+
+- wl_resource* xdg_popup_resource = wl_resource_create(
+- client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), id);
++ wl_resource* xdg_popup_resource =
++ CreateResourceWithImpl<::testing::NiceMock<MockXdgPopup>>(
++ client, &zxdg_popup_v6_interface, wl_resource_get_version(resource),
++ &kZxdgPopupV6Impl, id, resource);
++
++ if (!xdg_popup_resource) {
++ wl_client_post_no_memory(client);
++ return;
++ }
++
++ auto* mock_xdg_popup = GetUserDataAs<MockXdgPopup>(xdg_popup_resource);
++ DCHECK(mock_xdg_popup);
++
+ auto* positioner = GetUserDataAs<TestPositioner>(positioner_resource);
+ DCHECK(positioner);
+
+- auto mock_xdg_popup =
+- std::make_unique<MockXdgPopup>(xdg_popup_resource, &kZxdgPopupV6Impl);
+ mock_xdg_popup->set_position(positioner->position());
+ if (mock_xdg_popup->size().IsEmpty() ||
+ mock_xdg_popup->anchor_rect().IsEmpty()) {
+@@ -171,21 +220,7 @@ void GetZXdgPopupV6(struct wl_client* client,
+ return;
+ }
+
+- mock_xdg_surface->set_xdg_popup(std::move(mock_xdg_popup));
+-}
+-
+-void SetMaxSize(wl_client* client,
+- wl_resource* resource,
+- int32_t width,
+- int32_t height) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetMaxSize(width, height);
+-}
+-
+-void SetMinSize(wl_client* client,
+- wl_resource* resource,
+- int32_t width,
+- int32_t height) {
+- GetUserDataAs<MockXdgSurface>(resource)->SetMinSize(width, height);
++ mock_xdg_surface->set_xdg_popup(mock_xdg_popup);
+ }
+
+ const struct xdg_surface_interface kMockXdgSurfaceImpl = {
+@@ -238,17 +273,18 @@ const struct zxdg_toplevel_v6_interface kMockZxdgToplevelV6Impl = {
+ &SetMinimized, // set_minimized
+ };
+
+-MockXdgSurface::MockXdgSurface(wl_resource* resource,
+- const void* implementation)
+- : ServerObject(resource) {
+- SetImplementationUnretained(resource, implementation, this);
+-}
++MockXdgSurface::MockXdgSurface(wl_resource* resource, wl_resource* surface)
++ : ServerObject(resource), surface_(surface) {}
+
+-MockXdgSurface::~MockXdgSurface() {}
++MockXdgSurface::~MockXdgSurface() {
++ auto* mock_surface = GetUserDataAs<MockSurface>(surface_);
++ if (mock_surface)
++ mock_surface->set_xdg_surface(nullptr);
++}
+
+ MockXdgTopLevel::MockXdgTopLevel(wl_resource* resource,
+ const void* implementation)
+- : MockXdgSurface(resource, implementation) {
++ : ServerObject(resource) {
+ SetImplementationUnretained(resource, implementation, this);
+ }
+
+diff --git a/ui/ozone/platform/wayland/test/mock_xdg_surface.h b/ui/ozone/platform/wayland/test/mock_xdg_surface.h
+index 20e0f96bdfcb..c41a6ed8fa32 100644
+--- a/ui/ozone/platform/wayland/test/mock_xdg_surface.h
++++ b/ui/ozone/platform/wayland/test/mock_xdg_surface.h
+@@ -30,60 +30,71 @@ class MockXdgTopLevel;
+ // UI.
+ class MockXdgSurface : public ServerObject {
+ public:
+- MockXdgSurface(wl_resource* resource, const void* implementation);
++ MockXdgSurface(wl_resource* resource, wl_resource* surface);
+ ~MockXdgSurface() override;
+
+- // These mock methods are shared between xdg_surface and zxdg_toplevel
+- // surface.
+- MOCK_METHOD1(SetParent, void(wl_resource* parent));
+- MOCK_METHOD1(SetTitle, void(const char* title));
+- MOCK_METHOD1(SetAppId, void(const char* app_id));
+- MOCK_METHOD1(Move, void(uint32_t serial));
+- MOCK_METHOD2(Resize, void(uint32_t serial, uint32_t edges));
+ MOCK_METHOD1(AckConfigure, void(uint32_t serial));
+ MOCK_METHOD4(SetWindowGeometry,
+ void(int32_t x, int32_t y, int32_t width, int32_t height));
+- MOCK_METHOD0(SetMaximized, void());
+- MOCK_METHOD0(UnsetMaximized, void());
+- MOCK_METHOD0(SetFullscreen, void());
+- MOCK_METHOD0(UnsetFullscreen, void());
+- MOCK_METHOD0(SetMinimized, void());
+-
+- // These methods are for zxdg_toplevel only.
+- MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t height));
+- MOCK_METHOD2(SetMinSize, void(int32_t width, int32_t height));
+
+ void set_xdg_toplevel(std::unique_ptr<MockXdgTopLevel> xdg_toplevel) {
+ xdg_toplevel_ = std::move(xdg_toplevel);
+ }
+ MockXdgTopLevel* xdg_toplevel() const { return xdg_toplevel_.get(); }
+
+- void set_xdg_popup(std::unique_ptr<MockXdgPopup> xdg_popup) {
+- xdg_popup_ = std::move(xdg_popup);
+- }
+- MockXdgPopup* xdg_popup() const { return xdg_popup_.get(); }
++ void set_xdg_popup(MockXdgPopup* xdg_popup) { xdg_popup_ = xdg_popup; }
++ MockXdgPopup* xdg_popup() const { return xdg_popup_; }
+
+ private:
+- // Used when xdg v6 is used.
++ // Has either toplevel role..
+ std::unique_ptr<MockXdgTopLevel> xdg_toplevel_;
++ // Or popup role.
++ MockXdgPopup* xdg_popup_ = nullptr;
+
+- std::unique_ptr<MockXdgPopup> xdg_popup_;
++ // MockSurface that is the ground for this xdg_surface.
++ wl_resource* surface_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(MockXdgSurface);
+ };
+
+ // Manage zxdg_toplevel for providing desktop UI.
+-class MockXdgTopLevel : public MockXdgSurface {
++class MockXdgTopLevel : public ServerObject {
+ public:
+- explicit MockXdgTopLevel(wl_resource* resource, const void* implementation);
++ MockXdgTopLevel(wl_resource* resource, const void* implementation);
+ ~MockXdgTopLevel() override;
+
+- // TODO(msisov): mock other zxdg_toplevel specific methods once
+- // implementation
+- // is done. example: MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t
+- // height());
++ MOCK_METHOD1(SetParent, void(wl_resource* parent));
++ MOCK_METHOD1(SetTitle, void(const std::string& title));
++ MOCK_METHOD1(SetAppId, void(const char* app_id));
++ MOCK_METHOD1(Move, void(uint32_t serial));
++ MOCK_METHOD2(Resize, void(uint32_t serial, uint32_t edges));
++ MOCK_METHOD0(SetMaximized, void());
++ MOCK_METHOD0(UnsetMaximized, void());
++ MOCK_METHOD0(SetFullscreen, void());
++ MOCK_METHOD0(UnsetFullscreen, void());
++ MOCK_METHOD0(SetMinimized, void());
++ MOCK_METHOD2(SetMaxSize, void(int32_t width, int32_t height));
++ MOCK_METHOD2(SetMinSize, void(int32_t width, int32_t height));
++
++ const std::string& app_id() const { return app_id_; }
++ void set_app_id(const char* app_id) { app_id_ = std::string(app_id); }
++
++ std::string title() const { return title_; }
++ void set_title(const char* title) { title_ = std::string(title); }
++
++ const gfx::Size& min_size() const { return min_size_; }
++ void set_min_size(const gfx::Size& min_size) { min_size_ = min_size; }
++
++ const gfx::Size& max_size() const { return max_size_; }
++ void set_max_size(const gfx::Size& max_size) { max_size_ = max_size; }
+
+ private:
++ gfx::Size min_size_;
++ gfx::Size max_size_;
++
++ std::string title_;
++ std::string app_id_;
++
+ DISALLOW_COPY_AND_ASSIGN(MockXdgTopLevel);
+ };
+
+diff --git a/ui/ozone/platform/wayland/test/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc
+index 2543981d8c38..2866ab6a07f8 100644
+--- a/ui/ozone/platform/wayland/test/wayland_test.cc
++++ b/ui/ozone/platform/wayland/test/wayland_test.cc
+@@ -55,6 +55,8 @@ void WaylandTest::SetUp() {
+ std::move(properties));
+ ASSERT_NE(widget_, gfx::kNullAcceleratedWidget);
+
++ window_->Show(false);
++
+ // Wait for the client to flush all pending requests from initialization.
+ base::RunLoop().RunUntilIdle();
+
+--
+2.24.1
+
diff --git a/0009-ozone-wayland-window-state-change-must-be-synchronou.patch b/0009-ozone-wayland-window-state-change-must-be-synchronou.patch
new file mode 100644
index 000000000000..1386e82e4e62
--- /dev/null
+++ b/0009-ozone-wayland-window-state-change-must-be-synchronou.patch
@@ -0,0 +1,665 @@
+From f70d9e1475b402cc70ff0b4539c26ff86ef1116c Mon Sep 17 00:00:00 2001
+From: Maksim Sisov <msisov@igalia.com>
+Date: Tue, 7 Jan 2020 18:17:05 +0000
+Subject: [PATCH 9/9] ozone/wayland: window state change must be synchronous.
+
+This CL fixes two issues:
+
+1) After we changed to only create ShellSurfaces after Show calls, starting the
+browser with maximized or fullscreen modes broke. That is, in Wayland, it
+is required to assign a role to wl_surface and make higher level objects like
+xdg_surface and xdg_toplevel that are used by desktop xdg shell.
+
+State manipulation can only be done through those higher level objects and
+we must defer setting state to maximized/fullscreen until they are created.
+
+2) Also, this CL changes the intermidiate result of state changes: now, all of
+them are considered synchronous and if Wayland decides to change the state
+to something else, the state will be overriden and OnWindowStateChange will
+be called. Otherwise, if it was the client, who changed the state, no
+notification is sent.
+
+Test: StartMaximized, StartWithFullscreen, CompositorSideChanges
+Bug: 1033525
+
+Change-Id: I89728297d572d62db59f2d3b1628f2d735dbd4b0
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1965031
+Reviewed-by: Michael Spang <spang@chromium.org>
+Commit-Queue: Maksim Sisov <msisov@igalia.com>
+Cr-Commit-Position: refs/heads/master@{#728996}
+---
+ .../platform/wayland/host/wayland_surface.cc | 173 ++++++--------
+ .../platform/wayland/host/wayland_surface.h | 17 +-
+ .../wayland/host/wayland_window_unittest.cc | 212 +++++++++++++++---
+ 3 files changed, 249 insertions(+), 153 deletions(-)
+
+diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
+index b800a526e64e..c90e499fc796 100644
+--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
++++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
+@@ -19,8 +19,7 @@ namespace ui {
+ WaylandSurface::WaylandSurface(PlatformWindowDelegate* delegate,
+ WaylandConnection* connection)
+ : WaylandWindow(delegate, connection),
+- state_(PlatformWindowState::kNormal),
+- pending_state_(PlatformWindowState::kUnknown) {
++ state_(PlatformWindowState::kNormal) {
+ // Set a class property key, which allows |this| to be used for interactive
+ // events, e.g. move or resize.
+ SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
+@@ -47,6 +46,7 @@ bool WaylandSurface::CreateShellSurface() {
+ shell_surface_->SetAppId(app_id_);
+ shell_surface_->SetTitle(window_title_);
+ SetSizeConstraints();
++ TriggerStateChanges();
+ return true;
+ }
+
+@@ -117,7 +117,7 @@ void WaylandSurface::Hide() {
+ bool WaylandSurface::IsVisible() const {
+ // X and Windows return true if the window is minimized. For consistency, do
+ // the same.
+- return !!shell_surface_ || IsMinimized();
++ return !!shell_surface_ || state_ == PlatformWindowState::kMinimized;
+ }
+
+ void WaylandSurface::SetTitle(const base::string16& title) {
+@@ -133,74 +133,36 @@ void WaylandSurface::SetTitle(const base::string16& title) {
+ }
+
+ void WaylandSurface::ToggleFullscreen() {
+- DCHECK(shell_surface_);
+-
+- // There are some cases, when Chromium triggers a fullscreen state change
+- // before the surface is activated. In such cases, Wayland may ignore state
+- // changes and such flags as --kiosk or --start-fullscreen will be ignored.
+- // To overcome this, set a pending state, and once the surface is activated,
+- // trigger the change.
+- if (!is_active_) {
+- DCHECK(!IsFullscreen());
+- pending_state_ = PlatformWindowState::kFullScreen;
+- return;
+- }
+-
+ // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
+- // if shell_surface_set_fullscreen() is not provided with wl_output, it's up
++ // if xdg_toplevel_set_fullscreen() is not provided with wl_output, it's up
+ // to the compositor to choose which display will be used to map this surface.
+- if (!IsFullscreen()) {
+- // Fullscreen state changes have to be handled manually and then checked
+- // against configuration events, which come from a compositor. The reason
+- // of manually changing the |state_| is that the compositor answers about
+- // state changes asynchronously, which leads to a wrong return value in
+- // DesktopWindowTreeHostPlatform::IsFullscreen, for example, and media
+- // files can never be set to fullscreen.
+- state_ = PlatformWindowState::kFullScreen;
+- shell_surface_->SetFullscreen();
++
++ // We must track the previous state to correctly say our state as long as it
++ // can be the maximized instead of normal one.
++ PlatformWindowState new_state = PlatformWindowState::kUnknown;
++ if (state_ == PlatformWindowState::kFullScreen) {
++ if (previous_state_ == PlatformWindowState::kMaximized)
++ new_state = previous_state_;
++ else
++ new_state = PlatformWindowState::kNormal;
+ } else {
+- // Check the comment above. If it's not handled synchronously, media files
+- // may not leave the fullscreen mode.
+- state_ = PlatformWindowState::kUnknown;
+- shell_surface_->UnSetFullscreen();
++ new_state = PlatformWindowState::kFullScreen;
+ }
+
+- connection()->ScheduleFlush();
++ SetWindowState(new_state);
+ }
+
+ void WaylandSurface::Maximize() {
+- DCHECK(shell_surface_);
+-
+- if (IsFullscreen())
+- ToggleFullscreen();
+-
+- shell_surface_->SetMaximized();
+- connection()->ScheduleFlush();
++ SetWindowState(PlatformWindowState::kMaximized);
+ }
+
+ void WaylandSurface::Minimize() {
+- DCHECK(shell_surface_);
+- DCHECK(!is_minimizing_);
+- // Wayland doesn't explicitly say if a window is minimized. Instead, it
+- // notifies that the window is not activated. But there are many cases, when
+- // the window is not minimized and deactivated. In order to properly record
+- // the minimized state, mark this window as being minimized. And as soon as a
+- // configuration event comes, check if the window has been deactivated and has
+- // |is_minimizing_| set.
+- is_minimizing_ = true;
+- shell_surface_->SetMinimized();
+- connection()->ScheduleFlush();
++ SetWindowState(PlatformWindowState::kMinimized);
+ }
+
+ void WaylandSurface::Restore() {
+ DCHECK(shell_surface_);
+-
+- // Unfullscreen the window if it is fullscreen.
+- if (IsFullscreen())
+- ToggleFullscreen();
+-
+- shell_surface_->UnSetMaximized();
+- connection()->ScheduleFlush();
++ SetWindowState(PlatformWindowState::kNormal);
+ }
+
+ PlatformWindowState WaylandSurface::GetPlatformWindowState() const {
+@@ -223,34 +185,21 @@ void WaylandSurface::HandleSurfaceConfigure(int32_t width,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
+- // Propagate the window state information to the client.
++ // Store the old state to propagte state changes if Wayland decides to change
++ // the state to something else.
+ PlatformWindowState old_state = state_;
+-
+- // Ensure that manually handled state changes to fullscreen correspond to the
+- // configuration events from a compositor.
+- DCHECK_EQ(is_fullscreen, IsFullscreen());
+-
+- // There are two cases, which must be handled for the minimized state.
+- // The first one is the case, when the surface goes into the minimized state
+- // (check comment in WaylandSurface::Minimize), and the second case is when
+- // the surface still has been minimized, but another configuration event with
+- // !is_activated comes. For this, check if the WaylandSurface has been
+- // minimized before and !is_activated is sent.
+- if ((is_minimizing_ || IsMinimized()) && !is_activated) {
+- is_minimizing_ = false;
++ if (state_ == PlatformWindowState::kMinimized && !is_activated) {
+ state_ = PlatformWindowState::kMinimized;
+ } else if (is_fullscreen) {
+- // To ensure the |delegate()| is notified about state changes to fullscreen,
+- // assume the old_state is UNKNOWN (check comment in ToggleFullscreen).
+- old_state = PlatformWindowState::kUnknown;
+- DCHECK(state_ == PlatformWindowState::kFullScreen);
++ state_ = PlatformWindowState::kFullScreen;
+ } else if (is_maximized) {
+ state_ = PlatformWindowState::kMaximized;
+ } else {
+ state_ = PlatformWindowState::kNormal;
+ }
++
+ const bool state_changed = old_state != state_;
+- const bool is_normal = !IsFullscreen() && !IsMaximized();
++ const bool is_normal = state_ == PlatformWindowState::kNormal;
+
+ // Update state before notifying delegate.
+ const bool did_active_change = is_active_ != is_activated;
+@@ -281,28 +230,17 @@ void WaylandSurface::HandleSurfaceConfigure(int32_t width,
+ 1.0 / buffer_scale()));
+ }
+
+- if (state_changed) {
+- // The |restored_bounds_| are used when the window gets back to normal
+- // state after it went maximized or fullscreen. So we reset these if the
+- // window has just become normal and store the current bounds if it is
+- // either going out of normal state or simply changes the state and we don't
+- // have any meaningful value stored.
+- if (is_normal) {
+- SetRestoredBoundsInPixels({});
+- } else if (old_state == PlatformWindowState::kNormal ||
+- GetRestoredBoundsInPixels().IsEmpty()) {
+- SetRestoredBoundsInPixels(GetBounds());
+- }
++ // Store the restored bounds of current state differs from the normal state.
++ // It can be client or compositor side change from normal to something else.
++ // Thus, we must store previous bounds to restore later.
++ SetOrResetRestoredBounds();
++ ApplyPendingBounds();
+
++ if (state_changed)
+ delegate()->OnWindowStateChanged(state_);
+- }
+-
+- ApplyPendingBounds();
+
+ if (did_active_change)
+ delegate()->OnActivationChanged(is_active_);
+-
+- MaybeTriggerPendingStateChange();
+ }
+
+ void WaylandSurface::OnDragEnter(const gfx::PointF& point,
+@@ -348,24 +286,34 @@ bool WaylandSurface::OnInitialize(PlatformWindowInitProperties properties) {
+ return true;
+ }
+
+-bool WaylandSurface::IsMinimized() const {
+- return state_ == PlatformWindowState::kMinimized;
+-}
++void WaylandSurface::TriggerStateChanges() {
++ if (!shell_surface_)
++ return;
+
+-bool WaylandSurface::IsMaximized() const {
+- return state_ == PlatformWindowState::kMaximized;
+-}
++ if (state_ == PlatformWindowState::kFullScreen)
++ shell_surface_->SetFullscreen();
++ else
++ shell_surface_->UnSetFullscreen();
++
++ // Call UnSetMaximized only if current state is normal. Otherwise, if the
++ // current state is fullscreen and the previous is maximized, calling
++ // UnSetMaximized may result in wrong restored window position that clients
++ // are not allowed to know about.
++ if (state_ == PlatformWindowState::kMaximized)
++ shell_surface_->SetMaximized();
++ else if (state_ == PlatformWindowState::kNormal)
++ shell_surface_->UnSetMaximized();
++
++ if (state_ == PlatformWindowState::kMinimized)
++ shell_surface_->SetMinimized();
+
+-bool WaylandSurface::IsFullscreen() const {
+- return state_ == PlatformWindowState::kFullScreen;
++ connection()->ScheduleFlush();
+ }
+
+-void WaylandSurface::MaybeTriggerPendingStateChange() {
+- if (pending_state_ == PlatformWindowState::kUnknown || !is_active_)
+- return;
+- DCHECK_EQ(pending_state_, PlatformWindowState::kFullScreen);
+- pending_state_ = PlatformWindowState::kUnknown;
+- ToggleFullscreen();
++void WaylandSurface::SetWindowState(PlatformWindowState state) {
++ previous_state_ = state_;
++ state_ = state;
++ TriggerStateChanges();
+ }
+
+ WmMoveResizeHandler* WaylandSurface::AsWmMoveResizeHandler() {
+@@ -381,4 +329,17 @@ void WaylandSurface::SetSizeConstraints() {
+ connection()->ScheduleFlush();
+ }
+
++void WaylandSurface::SetOrResetRestoredBounds() {
++ // The |restored_bounds_| are used when the window gets back to normal
++ // state after it went maximized or fullscreen. So we reset these if the
++ // window has just become normal and store the current bounds if it is
++ // either going out of normal state or simply changes the state and we don't
++ // have any meaningful value stored.
++ if (GetPlatformWindowState() == PlatformWindowState::kNormal) {
++ SetRestoredBoundsInPixels({});
++ } else if (GetRestoredBoundsInPixels().IsEmpty()) {
++ SetRestoredBoundsInPixels(GetBounds());
++ }
++}
++
+ } // namespace ui
+diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
+index 677eaca6ef56..ceda32d24a7c 100644
+--- a/ui/ozone/platform/wayland/host/wayland_surface.h
++++ b/ui/ozone/platform/wayland/host/wayland_surface.h
+@@ -69,11 +69,8 @@ class WaylandSurface : public WaylandWindow,
+ void OnDragSessionClose(uint32_t dnd_action) override;
+ bool OnInitialize(PlatformWindowInitProperties properties) override;
+
+- bool IsMinimized() const;
+- bool IsMaximized() const;
+- bool IsFullscreen() const;
+-
+- void MaybeTriggerPendingStateChange();
++ void TriggerStateChanges();
++ void SetWindowState(PlatformWindowState state);
+
+ // Creates a surface window, which is visible as a main window.
+ bool CreateShellSurface();
+@@ -83,6 +80,8 @@ class WaylandSurface : public WaylandWindow,
+ // Propagates the |min_size_| and |max_size_| to the ShellSurface.
+ void SetSizeConstraints();
+
++ void SetOrResetRestoredBounds();
++
+ // Wrappers around shell surface.
+ std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
+
+@@ -100,14 +99,12 @@ class WaylandSurface : public WaylandWindow,
+ // handler that receives DIP from Wayland.
+ gfx::Rect pending_bounds_dip_;
+
+- // Stores current states of the window.
++ // Contains the current state of the window.
+ PlatformWindowState state_;
+- // Stores a pending state of the window, which is used before the surface is
+- // activated.
+- PlatformWindowState pending_state_;
++ // Contains the previous state of the window.
++ PlatformWindowState previous_state_;
+
+ bool is_active_ = false;
+- bool is_minimizing_ = false;
+
+ // Id of the chromium app passed through
+ // PlatformWindowInitProperties::wm_class_class. This is used by Wayland
+diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+index f56b96690eea..c72d27edff66 100644
+--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
++++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+@@ -233,8 +233,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+ kMaximizedBounds.height()));
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
+ EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->Maximize();
+ SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 1,
+ active_maximized.get());
+@@ -262,8 +261,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+ kNormalBounds.height()));
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kNormal)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
+ EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
+@@ -283,19 +281,21 @@ TEST_P(WaylandWindowTest, Minimize) {
+ Sync();
+
+ EXPECT_CALL(*GetXdgToplevel(), SetMinimized());
+- // Wayland compositor doesn't notify clients about minimized state, but rather
+- // if a window is not activated. Thus, a WaylandWindow marks itself as being
+- // minimized and as soon as a configuration event with not activated state
+- // comes, its state is changed to minimized. This EXPECT_CALL ensures this
+- // behaviour.
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kMinimized)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->Minimize();
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
++
+ // Reinitialize wl_array, which removes previous old states.
+ states = ScopedWlArray();
+ SendConfigureEvent(0, 0, 2, states.get());
+ Sync();
+
++ // Wayland compositor doesn't notify clients about minimized state, but rather
++ // if a window is not activated. Thus, a WaylandSurface marks itself as being
++ // minimized and and sets state to minimized. Thus, the state mustn't change
++ // after the configuration event is sent.
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
++
+ // Send one additional empty configuration event (which means the surface is
+ // not maximized, fullscreen or activated) to ensure, WaylandWindow stays in
+ // the same minimized state and doesn't notify its delegate.
+@@ -319,8 +319,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
+ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
+
+ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->ToggleFullscreen();
+ // Make sure than WaylandWindow manually handles fullscreen states. Check the
+ // comment in the WaylandWindow::ToggleFullscreen.
+@@ -330,51 +329,181 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
+ Sync();
+
+ EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kNormal)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->Restore();
+- EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kUnknown);
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
+ // Reinitialize wl_array, which removes previous old states.
+ states = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 3, states.get());
+ Sync();
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
+ }
+
+ TEST_P(WaylandWindowTest, StartWithFullscreen) {
++ MockPlatformWindowDelegate delegate;
++ PlatformWindowInitProperties properties;
++ properties.bounds = gfx::Rect(0, 0, 100, 100);
++ properties.type = PlatformWindowType::kWindow;
++ // We need to create a window avoid calling Show() on it as it is what upper
++ // views layer does - when Widget initialize DesktopWindowTreeHost, the Show()
++ // is called later down the road, but Maximize may be called earlier. We
++ // cannot process them and set a pending state instead, because ShellSurface
++ // is not created by that moment.
++ auto window = WaylandWindow::Create(&delegate, connection_.get(),
++ std::move(properties));
++
++ Sync();
++
++ // Make sure the window is initialized to normal state from the beginning.
++ EXPECT_EQ(PlatformWindowState::kNormal, window->GetPlatformWindowState());
++
++ // The state must not be changed to the fullscreen before the surface is
++ // activated.
++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
++ EXPECT_FALSE(mock_surface->xdg_surface());
++ EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
++ window->ToggleFullscreen();
++ // The state of the window must already be fullscreen one.
++ EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen);
++
++ Sync();
++
++ // We mustn't receive any state changes if that does not differ from the last
++ // state.
++ EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
++
++ // Activate the surface.
++ ScopedWlArray states = InitializeWlArrayWithActivatedState();
++ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
++ SendConfigureEvent(0, 0, 1, states.get());
++
++ Sync();
++
++ // It must be still the same state.
++ EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen);
++}
++
++TEST_P(WaylandWindowTest, StartMaximized) {
++ MockPlatformWindowDelegate delegate;
++ PlatformWindowInitProperties properties;
++ properties.bounds = gfx::Rect(0, 0, 100, 100);
++ properties.type = PlatformWindowType::kWindow;
++ // We need to create a window avoid calling Show() on it as it is what upper
++ // views layer does - when Widget initialize DesktopWindowTreeHost, the Show()
++ // is called later down the road, but Maximize may be called earlier. We
++ // cannot process them and set a pending state instead, because ShellSurface
++ // is not created by that moment.
++ auto window = WaylandWindow::Create(&delegate, connection_.get(),
++ std::move(properties));
++
++ Sync();
++
+ // Make sure the window is initialized to normal state from the beginning.
+ EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
+
+ // The state must not be changed to the fullscreen before the surface is
+ // activated.
+- EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()).Times(0);
++ auto* mock_surface = server_.GetObject<wl::MockSurface>(window->GetWidget());
++ EXPECT_FALSE(mock_surface->xdg_surface());
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+- window_->ToggleFullscreen();
+- // The state of the window must still be a normal one.
+- EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
++
++ window_->Maximize();
++ // The state of the window must already be fullscreen one.
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
+
+ Sync();
+
+- // Once the surface will be activated, the window will automatically trigger
+- // the state change.
+- EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)));
++ // Once the surface will be activated, the window state mustn't be changed
++ // and retain the same.
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
+
+ // Activate the surface.
+ ScopedWlArray states = InitializeWlArrayWithActivatedState();
++ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
+ SendConfigureEvent(0, 0, 1, states.get());
+
+ Sync();
+
+- // The wayland window manually handles the fullscreen state changes, and it
+- // must change to a fullscreen before the state change is confirmed by the
+- // wayland. See comment in the WaylandWindow::ToggleFullscreen.
+- EXPECT_EQ(window_->GetPlatformWindowState(),
+- PlatformWindowState::kFullScreen);
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
++}
+
+- AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
++TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
++ auto normal_bounds = window_->GetBounds();
++
++ ScopedWlArray states = InitializeWlArrayWithActivatedState();
++ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
++ SendConfigureEvent(2000, 2000, 1, states.get());
++
++ EXPECT_CALL(delegate_,
++ OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000));
++
++ Sync();
++
++ EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
++
++ // Unmaximize
++ states = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 2, states.get());
+
++ EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
++ normal_bounds.height()));
++
++ // Now, set to fullscreen.
++ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
++ SendConfigureEvent(2005, 2005, 3, states.get());
++ EXPECT_CALL(delegate_,
++ OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005));
++
++ Sync();
++
++ // Unfullscreen
++ states = InitializeWlArrayWithActivatedState();
++ SendConfigureEvent(0, 0, 4, states.get());
++
++ EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
++ normal_bounds.height()));
++
++ Sync();
++
++ // Now, maximize, fullscreen and restore.
++ states = InitializeWlArrayWithActivatedState();
++ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
++ SendConfigureEvent(2000, 2000, 1, states.get());
++
++ EXPECT_CALL(delegate_,
++ OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000));
++
++ Sync();
++
++ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
++ SendConfigureEvent(2005, 2005, 1, states.get());
++
++ EXPECT_CALL(delegate_,
++ OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005));
++
++ // Restore
++ states = InitializeWlArrayWithActivatedState();
++ SendConfigureEvent(0, 0, 4, states.get());
++
++ EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
++ .Times(1);
++ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
++ normal_bounds.height()));
++
+ Sync();
+ }
+
+@@ -395,25 +524,33 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
+ kMaximizedBounds.height()));
+ EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
+ EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->Maximize();
++ // State changes are synchronous.
++ EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
+ SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 2,
+ active_maximized.get());
+ Sync();
++ // Verify that the state has not been changed.
++ EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
+ VerifyAndClearExpectations();
+
+ EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
+ kMaximizedBounds.height()));
+ EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->ToggleFullscreen();
++ // State changes are synchronous.
++ EXPECT_EQ(PlatformWindowState::kFullScreen,
++ window_->GetPlatformWindowState());
+ AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, active_maximized.get());
+ SendConfigureEvent(kMaximizedBounds.width(), kMaximizedBounds.height(), 3,
+ active_maximized.get());
+ Sync();
++ // Verify that the state has not been changed.
++ EXPECT_EQ(PlatformWindowState::kFullScreen,
++ window_->GetPlatformWindowState());
+ VerifyAndClearExpectations();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+@@ -421,13 +558,14 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
+ EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
+ EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
+ EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
+- EXPECT_CALL(delegate_,
+- OnWindowStateChanged(Eq(PlatformWindowState::kNormal)));
++ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->Restore();
++ EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
+ // Reinitialize wl_array, which removes previous old states.
+ auto active = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 4, active.get());
+ Sync();
++ EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
+ }
+
+ TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
+--
+2.24.1
+
diff --git a/PKGBUILD b/PKGBUILD
index 9dd12a718605..db32f93c3f95 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -5,7 +5,7 @@
# Contributor: Daniel J Griffiths <ghost1227@archlinux.us>
pkgname=chromium-ozone
-pkgver=79.0.3945.117
+pkgver=80.0.3987.42
pkgrel=1
_launcher_ver=6
pkgdesc="Chromium built with patches for wayland support via Ozone"
@@ -27,27 +27,21 @@ optdepends=('pepper-flash: support for Flash content'
install=chromium.install
source=(https://commondatastorage.googleapis.com/chromium-browser-official/chromium-$pkgver.tar.xz
chromium-launcher-$_launcher_ver.tar.gz::https://github.com/foutrelis/chromium-launcher/archive/v$_launcher_ver.tar.gz
- launch_manager.h-uses-std-vector.patch
- include-algorithm-to-use-std-lower_bound.patch
0001-Add-missing-algorithm-header-in-bitmap_cursor_factor.patch
- 0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch
- icu65.patch
+ 0001-cros-search-service-Include-cmath-for-std-pow.patch
+ 0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch
chromium-system-icu.patch
chromium-system-zlib.patch
- chromium-system-hb.patch
fix-spammy-unique-font-matching-log.patch
chromium-widevine.patch
chromium-skia-harmony.patch)
-sha256sums=('4d960e8bd790cc1c8e7f0632790424957c4996a8a91b9d899eb572acec854ef1'
+sha256sums=('160c02ed00d45a074246c8984144a35b092102e9b9a31e2bc9c2dad49f297945'
'04917e3cd4307d8e31bfb0027a5dce6d086edb10ff8a716024fbb8bb0c7dccf1'
- 'bd0fae907c451252e91c4cbf1ad301716bc9f8a4644ecc60e9590a64197477d3'
- '1f906676563e866e2b59719679e76e0b2f7f082f48ef0593e86da0351a586c73'
'716c28bed9f6e9c32e3617e125c1b04806700aef691763923cd4ed14b8d23279'
- '9e9e5c66d4555c787736c5d5d5fcef8b5e14d913b138041c9c90d1976ee46845'
- '1de9bdbfed482295dda45c7d4e323cee55a34e42f66b892da1c1a778682b7a41'
+ '4c892f046ab10df609aa39d9985248d368c77306783a64d335ff713dabad60b0'
+ 'a44ed59db5258221ee187dc2501040e5ebfc5c1353ac98d4313ac6a12ae32d1f'
'e73cc2ee8d3ea35aab18c478d76fdfc68ca4463e1e10306fa1e738c03b3f26b5'
'eb67eda4945a89c3b90473fa8dc20637511ca4dcb58879a8ed6bf403700ca9c8'
- 'c0ad3fa426cb8fc1a237ddc6309a6b2dd4055bbe41dd07f50071ee61f969b81a'
'6fbffe59b886195b92c9a55137cef83021c16593f49714acb20023633e3ebb19'
'709e2fddba3c1f2ed4deb3a239fc0479bfa50c46e054e7f32db4fb1365fed070'
'771292942c0901092a402cc60ee883877a99fb804cb54d568c8c6c94565a48e1')
@@ -66,7 +60,7 @@ declare -gA _system_libs=(
#[libpng]=libpng # https://crbug.com/752403#c10
#[libvpx]=libvpx # https://github.com/webmproject/libvpx/commit/5a0242ba5c
[libwebp]=libwebp
- [libxml]=libxml2
+ # [libxml]=libxml2
[libxslt]=libxslt
[opus]=opus
[re2]=re2
@@ -87,13 +81,12 @@ _google_api_key=AIzaSyDwr302FpOSkGRpLlUpPThNTDPbXcIn_FM
_google_default_client_id=413772536636.apps.googleusercontent.com
_google_default_client_secret=0ZChLK6AxeA3Isu96MkwqDR4
-# Branch point: 706915
+# Branch point: 722274
# Extra commits related specifically to wayland support:
# These consist of the above commits and their dependencies
# generated with `git-deps -r -e <release tag> <commit>^! ...` (in reverse order)
_bugfix_patches=(
- '0001-ozone-wayland-Complete-submission-of-a-buffer-submit.patch'
)
prepare() {
@@ -109,21 +102,17 @@ prepare() {
third_party/blink/renderer/core/xml/parser/xml_document_parser.cc \
third_party/libxml/chromium/libxml_utils.cc
- # https://crbug.com/819294
- patch -Np1 -i ../launch_manager.h-uses-std-vector.patch
- patch -Np1 -i ../include-algorithm-to-use-std-lower_bound.patch
+ # build fixes
patch -Np1 -i ../0001-Add-missing-algorithm-header-in-bitmap_cursor_factor.patch
-
- # https://crbug.com/1014272
- patch -Np1 -i ../icu65.patch
-
+ patch -Np1 -i ../0001-cros-search-service-Include-cmath-for-std-pow.patch
+ patch -Np1 -i ../0001-BookmarkModelMerger-Move-RemoteTreeNode-declaration-.patch
+
# Fixes from Gentoo
patch -Np1 -i ../chromium-system-icu.patch
patch -Np1 -i ../chromium-system-zlib.patch
- patch -Np1 -i ../chromium-system-hb.patch
# https://crbug.com/1005508
- patch -Np1 -i ../fix-spammy-unique-font-matching-log.patch
+ # patch -Np1 -i ../fix-spammy-unique-font-matching-log.patch
# Load bundled Widevine CDM if available (see chromium-widevine in the AUR)
# M79 is supposed to download it as a component but it doesn't seem to work
diff --git a/chromium-system-hb.patch b/chromium-system-hb.patch
deleted file mode 100644
index 83e0621777f1..000000000000
--- a/chromium-system-hb.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff --git a/components/paint_preview/common/subset_font.cc b/components/paint_preview/common/subset_font.cc
-index a218d63..6a5bdae 100644
---- a/components/paint_preview/common/subset_font.cc
-+++ b/components/paint_preview/common/subset_font.cc
-@@ -10,11 +10,12 @@
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/macros.h"
--#include "third_party/harfbuzz-ng/src/src/hb-subset.h"
--#include "third_party/harfbuzz-ng/src/src/hb.h"
- #include "third_party/skia/include/core/SkStream.h"
- #include "third_party/skia/include/core/SkTypeface.h"
-
-+#include <hb-subset.h>
-+#include <hb.h>
-+
- namespace paint_preview {
-
- namespace {
diff --git a/icu65.patch b/icu65.patch
deleted file mode 100644
index 811d56286a98..000000000000
--- a/icu65.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 5679c3c191ed62b62d8db22f1657a296ee9bfe8e Mon Sep 17 00:00:00 2001
-From: Frank Tang <ftang@chromium.org>
-Date: Wed, 30 Oct 2019 22:49:47 +0000
-Subject: [PATCH] Update ICU to 65.1 from 64 and fix broken tests
-
-ICU 65-1 release note
-http://site.icu-project.org/download/65
-
-CLDR 36 release blog
-http://blog.unicode.org/2019/10/unicode-cldr-version-36-languagelocale.html
-
-Most of the test expectation change is due to CLDR 36 update
-of Grapheme Cluster for Indic languages
-See the following for related changes in ICU 65.1 in this area:
-https://unicode-org.atlassian.net/browse/CLDR-10994
-https://unicode-org.atlassian.net/browse/ICU-13637
-https://github.com/unicode-org/cldr/blob/master/common/properties/segments/readme.txt
-
-Bug: chromium:1014272, chromium:1017047
-Change-Id: I9fc6d4620bf2a4c189940d06d8c79893502db3dd
-Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng_disabled
-Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1866059
-Reviewed-by: Jungshik Shin <jshin@chromium.org>
-Reviewed-by: Doug Turner <dougt@chromium.org>
-Reviewed-by: Michael Wasserman <msw@chromium.org>
-Reviewed-by: Kent Tamura <tkent@chromium.org>
-Reviewed-by: Trent Apted <tapted@chromium.org>
-Reviewed-by: Mason Freed <masonfreed@chromium.org>
-Commit-Queue: Frank Tang <ftang@chromium.org>
-Cr-Commit-Position: refs/heads/master@{#711027}
----
- third_party/blink/renderer/core/dom/document.cc | 2 +-
- ui/gfx/render_text_harfbuzz.cc | 5 ++++-
- 2 files changed, 5 insertions(+), 2 deletions(-)
-
-diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
-index 511aac29086..f188cf548a6 100644
---- a/third_party/blink/renderer/core/dom/document.cc
-+++ b/third_party/blink/renderer/core/dom/document.cc
-@@ -6191,7 +6191,7 @@ static ParseQualifiedNameResult ParseQualifiedNameInternal(
-
- for (unsigned i = 0; i < length;) {
- UChar32 c;
-- U16_NEXT(characters, i, length, c)
-+ U16_NEXT(characters, i, length, c);
- if (c == ':') {
- if (saw_colon)
- return ParseQualifiedNameResult(kQNMultipleColons);
-diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
-index 50e86af6b97..0339ff3ff8e 100644
---- a/ui/gfx/render_text_harfbuzz.cc
-+++ b/ui/gfx/render_text_harfbuzz.cc
-@@ -971,7 +971,10 @@ RangeF TextRunHarfBuzz::GetGraphemeBounds(RenderTextHarfBuzz* render_text,
- ++total;
- }
- }
-- DCHECK_GT(total, 0);
-+ // With ICU 65.1, DCHECK_GT() below fails.
-+ // See https://crbug.com/1017047 for more details.
-+ //
-+ // DCHECK_GT(total, 0);
-
- // It's possible for |text_index| to point to a diacritical mark, at the end
- // of |chars|. In this case all the grapheme boundaries come before it. Just
diff --git a/include-algorithm-to-use-std-lower_bound.patch b/include-algorithm-to-use-std-lower_bound.patch
deleted file mode 100644
index dc376321ffc4..000000000000
--- a/include-algorithm-to-use-std-lower_bound.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From f7c177d35242311ea7a2cf49a0980c61664f27ba Mon Sep 17 00:00:00 2001
-From: Jose Dapena Paz <jose.dapena@lge.com>
-Date: Fri, 25 Oct 2019 15:07:09 +0000
-Subject: [PATCH] IWYU: include algorithm to use std::lower_bound in
- ui/gfx/font.cc
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Fix GCC build because of missing include:
-../../ui/gfx/font.cc: In function ‘gfx::Font::Weight gfx::FontWeightFromInt(int)’:
-../../ui/gfx/font.cc:114:8: error: no matching function for call to ‘lower_bound(const gfx::Font::Weight*, const gfx::Font::Weight*, int&, gfx::FontWeightFromInt(int)::<lambda(const gfx::Font::Weight&, const int&)>)’
- });
- ^
-In file included from /usr/include/c++/8/bits/char_traits.h:39,
- from /usr/include/c++/8/string:40,
- from ../../ui/gfx/font.h:8,
- from ../../ui/gfx/font.cc:5:
-/usr/include/c++/8/bits/stl_algobase.h:984:5: note: candidate: ‘template<class _ForwardIterator, class _Tp> _ForwardIterator std::lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&)’
- lower_bound(_ForwardIterator __first, _ForwardIterator __last,
- ^~~~~~~~~~~
-/usr/include/c++/8/bits/stl_algobase.h:984:5: note: template argument deduction/substitution failed:
-../../ui/gfx/font.cc:114:8: note: candidate expects 3 arguments, 4 provided
- });
- ^
-
-Bug: 819294
-Change-Id: Ic59dcf3a06bdd54d1d426c08a61624873a0ff30c
-Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1879909
-Commit-Queue: Alexei Svitkine <asvitkine@chromium.org>
-Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
-Cr-Commit-Position: refs/heads/master@{#709472}
----
- ui/gfx/font.cc | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/ui/gfx/font.cc b/ui/gfx/font.cc
-index 21367fd7297..92b159e13d1 100644
---- a/ui/gfx/font.cc
-+++ b/ui/gfx/font.cc
-@@ -4,6 +4,8 @@
-
- #include "ui/gfx/font.h"
-
-+#include <algorithm>
-+
- #include "base/strings/utf_string_conversions.h"
- #include "build/build_config.h"
- #include "ui/gfx/platform_font.h"
diff --git a/launch_manager.h-uses-std-vector.patch b/launch_manager.h-uses-std-vector.patch
deleted file mode 100644
index 72abe9b9ce69..000000000000
--- a/launch_manager.h-uses-std-vector.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 97eb905ba262382bc3583078761c68f4452aea71 Mon Sep 17 00:00:00 2001
-From: Jose Dapena Paz <jose.dapena@lge.com>
-Date: Fri, 25 Oct 2019 09:27:53 +0000
-Subject: [PATCH] IWYU: launch_manager.h uses std::vector
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add #include <vector> for using std::vector. This fixes GCC build.
-
-./../chrome/browser/apps/launch_service/launch_manager.h:46:15: error: ‘vector’ in namespace ‘std’ does not name a template type
- static std::vector<base::FilePath> GetLaunchFilesFromCommandLine(
- ^~~~~~
-
-Bug: 819294
-Change-Id: I02ec3a2914a8fbe3aa0041017a0228f4b0ca1ec9
-Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1879289
-Reviewed-by: Alexey Baskakov <loyso@chromium.org>
-Commit-Queue: José Dapena Paz <jose.dapena@lge.com>
-Cr-Commit-Position: refs/heads/master@{#709411}
----
- chrome/browser/apps/launch_service/launch_manager.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/chrome/browser/apps/launch_service/launch_manager.h b/chrome/browser/apps/launch_service/launch_manager.h
-index 00aeb9d9c2a..76570ead0f9 100644
---- a/chrome/browser/apps/launch_service/launch_manager.h
-+++ b/chrome/browser/apps/launch_service/launch_manager.h
-@@ -6,6 +6,7 @@
- #define CHROME_BROWSER_APPS_LAUNCH_SERVICE_LAUNCH_MANAGER_H_
-
- #include <string>
-+#include <vector>
-
- #include "base/macros.h"
-