Commit 2245429e authored by Kramer Ge's avatar Kramer Ge Committed by Commit Bot

[ozone/wayland] Add wp_viewporter to Ozone Wayland implementation.

With overlay forwarding using wl_subsurface, a wl_buffer can be cropped
and scaled to fit a display_rect. This CL adds the extension
wp_viewporter to enable crop&scale, as well as buffer_transform.
When calculating surface-local damage, take into account
buffer_transform, crop and scale.

This is 5/? CL for overlay forwarding using wl_subsurface.

Bug: 1063865
Change-Id: I5cd0a28b7043557aeca0664f59152fd05eadf885
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2327636Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Reviewed-by: default avatarMaksim Sisov (GMT+3) <msisov@igalia.com>
Commit-Queue: Kramer Ge <fangzhoug@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810259}
parent b9747055
......@@ -157,6 +157,7 @@ source_set("wayland") {
"//third_party/wayland-protocols:linux_explicit_synchronization_protocol",
"//third_party/wayland-protocols:presentation_time_protocol",
"//third_party/wayland-protocols:text_input_protocol",
"//third_party/wayland-protocols:viewporter_protocol",
"//third_party/wayland-protocols:wayland_drm_protocol",
"//third_party/wayland-protocols:xdg_decoration_protocol",
"//third_party/wayland-protocols:xdg_foreign",
......@@ -298,6 +299,10 @@ source_set("test_support") {
"test/test_subsurface.h",
"test/test_touch.cc",
"test/test_touch.h",
"test/test_viewport.cc",
"test/test_viewport.h",
"test/test_viewporter.cc",
"test/test_viewporter.h",
"test/test_wayland_server_thread.cc",
"test/test_wayland_server_thread.h",
"test/test_xdg_popup.cc",
......@@ -320,6 +325,7 @@ source_set("test_support") {
"//third_party/wayland-protocols:linux_dmabuf_protocol",
"//third_party/wayland-protocols:presentation_time_protocol",
"//third_party/wayland-protocols:text_input_protocol",
"//third_party/wayland-protocols:viewporter_protocol",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/gfx/geometry:geometry",
]
......
......@@ -11,6 +11,7 @@
#include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
#include <presentation-time-client-protocol.h>
#include <text-input-unstable-v1-client-protocol.h>
#include <viewporter-client-protocol.h>
#include <wayland-drm-client-protocol.h>
#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-foreign-unstable-v1-client-protocol.h>
......@@ -182,6 +183,15 @@ const wl_interface* ObjectTraits<struct wp_presentation_feedback>::interface =
void (*ObjectTraits<struct wp_presentation_feedback>::deleter)(
struct wp_presentation_feedback*) = &wp_presentation_feedback_destroy;
const wl_interface* ObjectTraits<wp_viewport>::interface =
&wp_viewport_interface;
void (*ObjectTraits<wp_viewport>::deleter)(wp_viewport*) = &wp_viewport_destroy;
const wl_interface* ObjectTraits<wp_viewporter>::interface =
&wp_viewporter_interface;
void (*ObjectTraits<wp_viewporter>::deleter)(wp_viewporter*) =
&wp_viewporter_destroy;
const wl_interface* ObjectTraits<xdg_wm_base>::interface =
&xdg_wm_base_interface;
void (*ObjectTraits<xdg_wm_base>::deleter)(xdg_wm_base*) = &xdg_wm_base_destroy;
......
......@@ -35,6 +35,8 @@ struct wl_surface;
struct wl_touch;
struct wp_presentation;
struct wp_presentation_feedback;
struct wp_viewport;
struct wp_viewporter;
struct xdg_wm_base;
struct xdg_surface;
struct xdg_toplevel;
......@@ -239,6 +241,18 @@ struct ObjectTraits<wp_presentation_feedback> {
static void (*deleter)(wp_presentation_feedback*);
};
template <>
struct ObjectTraits<wp_viewport> {
static const wl_interface* interface;
static void (*deleter)(wp_viewport*);
};
template <>
struct ObjectTraits<wp_viewporter> {
static const wl_interface* interface;
static void (*deleter)(wp_viewporter*);
};
template <>
struct ObjectTraits<xdg_wm_base> {
static const wl_interface* interface;
......
......@@ -157,6 +157,98 @@ gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
child_bounds.size());
}
wl_output_transform ToWaylandTransform(gfx::OverlayTransform transform) {
switch (transform) {
case gfx::OVERLAY_TRANSFORM_NONE:
return WL_OUTPUT_TRANSFORM_NORMAL;
case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
return WL_OUTPUT_TRANSFORM_FLIPPED;
case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
return WL_OUTPUT_TRANSFORM_FLIPPED_180;
case gfx::OVERLAY_TRANSFORM_ROTATE_90:
return WL_OUTPUT_TRANSFORM_90;
case gfx::OVERLAY_TRANSFORM_ROTATE_180:
return WL_OUTPUT_TRANSFORM_180;
case gfx::OVERLAY_TRANSFORM_ROTATE_270:
return WL_OUTPUT_TRANSFORM_270;
default:
break;
}
NOTREACHED();
return WL_OUTPUT_TRANSFORM_NORMAL;
}
gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect,
const gfx::Size& bounds,
wl_output_transform transform) {
gfx::Rect result = rect;
switch (transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
break;
case WL_OUTPUT_TRANSFORM_FLIPPED:
result.set_x(bounds.width() - rect.x() - rect.width());
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
result.set_x(rect.y());
result.set_y(rect.x());
result.set_width(rect.height());
result.set_height(rect.width());
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
result.set_y(bounds.height() - rect.y() - rect.height());
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
result.set_x(bounds.height() - rect.y() - rect.height());
result.set_y(bounds.width() - rect.x() - rect.width());
result.set_width(rect.height());
result.set_height(rect.width());
break;
case WL_OUTPUT_TRANSFORM_90:
result.set_x(rect.y());
result.set_y(bounds.width() - rect.x() - rect.width());
result.set_width(rect.height());
result.set_height(rect.width());
break;
case WL_OUTPUT_TRANSFORM_180:
result.set_x(bounds.width() - rect.x() - rect.width());
result.set_y(bounds.height() - rect.y() - rect.height());
break;
case WL_OUTPUT_TRANSFORM_270:
result.set_x(bounds.height() - rect.y() - rect.height());
result.set_y(rect.x());
result.set_width(rect.height());
result.set_height(rect.width());
break;
default:
NOTREACHED();
break;
}
return result;
}
gfx::Size ApplyWaylandTransform(const gfx::Size& size,
wl_output_transform transform) {
gfx::Size result = size;
switch (transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_180:
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_270:
result.set_width(size.height());
result.set_height(size.width());
break;
default:
NOTREACHED();
break;
}
return result;
}
bool IsMenuType(ui::PlatformWindowType type) {
return type == ui::PlatformWindowType::kMenu ||
type == ui::PlatformWindowType::kPopup;
......
......@@ -12,6 +12,7 @@
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/platform_window/platform_window_init_properties.h"
......@@ -58,6 +59,21 @@ gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
const gfx::Rect& parent_bounds);
// Returns wl_output_transform corresponding |transform|. |transform| is an
// enumeration of a fixed selection of transformations.
wl_output_transform ToWaylandTransform(gfx::OverlayTransform transform);
// |bounds| contains |rect|. ApplyWaylandTransform() returns the resulted
// |rect| after transformation is applied to |bounds| containing |rect| as a
// whole.
gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect,
const gfx::Size& bounds,
wl_output_transform transform);
// Applies transformation to |size|.
gfx::Size ApplyWaylandTransform(const gfx::Size& size,
wl_output_transform transform);
// Says if the type is kPopup or kMenu.
bool IsMenuType(ui::PlatformWindowType type);
......
......@@ -246,7 +246,8 @@ class WaylandBufferManagerHost::Surface {
pending_damage_region.set_size(buffer->size);
DCHECK(!pending_damage_region.size().IsEmpty());
wayland_surface_->Damage(pending_damage_region);
wayland_surface_->UpdateBufferDamageRegion(pending_damage_region,
buffer->size);
}
void AttachBuffer(WaylandBuffer* buffer) {
......@@ -633,6 +634,13 @@ void WaylandBufferManagerHost::OnSubsurfaceRemoved(
surfaces_.erase(it);
}
void WaylandBufferManagerHost::SetSurfaceConfigured(WaylandSurface* surface) {
DCHECK(surface);
auto it = surfaces_.find(surface);
DCHECK(it != surfaces_.end());
it->second->OnSurfaceConfigured();
}
void WaylandBufferManagerHost::SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_callback) {
terminate_gpu_cb_ = std::move(terminate_callback);
......
......@@ -89,6 +89,9 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
void OnSubsurfaceRemoved(WaylandWindow* window,
WaylandSubsurface* subsurface) override;
// Start allowing attaching buffers to |surface|, same as
// OnWindowConfigured(), but for WaylandSurface.
void SetSurfaceConfigured(WaylandSurface* surface);
void SetTerminateGpuCallback(
base::OnceCallback<void(std::string)> terminate_gpu_cb);
......
......@@ -52,6 +52,7 @@ constexpr uint32_t kMaxShmVersion = 1;
constexpr uint32_t kMaxXdgShellVersion = 1;
constexpr uint32_t kMaxDeviceManagerVersion = 3;
constexpr uint32_t kMaxWpPresentationVersion = 1;
constexpr uint32_t kMaxWpViewporterVersion = 1;
constexpr uint32_t kMaxTextInputManagerVersion = 1;
constexpr uint32_t kMaxExplicitSyncVersion = 2;
constexpr uint32_t kMinAuraShellVersion = 10;
......@@ -354,6 +355,10 @@ void WaylandConnection::Global(void* data,
(strcmp(interface, "wp_presentation") == 0)) {
connection->presentation_ =
wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion);
} else if (!connection->viewporter_ &&
(strcmp(interface, "wp_viewporter") == 0)) {
connection->viewporter_ =
wl::Bind<wp_viewporter>(registry, name, kMaxWpViewporterVersion);
} else if (!connection->keyboard_extension_v1_ &&
strcmp(interface, "zcr_keyboard_extension_v1") == 0) {
connection->keyboard_extension_v1_ = wl::Bind<zcr_keyboard_extension_v1>(
......
......@@ -64,6 +64,7 @@ class WaylandConnection {
wl_compositor* compositor() const { return compositor_.get(); }
uint32_t compositor_version() const { return compositor_version_; }
wl_subcompositor* subcompositor() const { return subcompositor_.get(); }
wp_viewporter* viewporter() const { return viewporter_.get(); }
xdg_wm_base* shell() const { return shell_.get(); }
zxdg_shell_v6* shell_v6() const { return shell_v6_.get(); }
zaura_shell* aura_shell() const { return aura_shell_.get(); }
......@@ -188,6 +189,7 @@ class WaylandConnection {
wl::Object<xdg_wm_base> shell_;
wl::Object<zxdg_shell_v6> shell_v6_;
wl::Object<wp_presentation> presentation_;
wl::Object<wp_viewporter> viewporter_;
wl::Object<zcr_keyboard_extension_v1> keyboard_extension_v1_;
wl::Object<zwp_text_input_manager_v1> text_input_manager_v1_;
wl::Object<zaura_shell> aura_shell_;
......
......@@ -43,6 +43,7 @@ WaylandSubsurface::WaylandSubsurface(WaylandConnection* connection,
LOG(ERROR) << "Failed to create wl_surface";
return;
}
wayland_surface_.Initialize();
}
WaylandSubsurface::~WaylandSubsurface() = default;
......@@ -69,11 +70,9 @@ bool WaylandSubsurface::IsVisible() const {
}
void WaylandSubsurface::UpdateOpaqueRegion() {
gfx::Size region_size = enable_blend_ ? gfx::Size() : bounds_px_.size();
wl::Object<wl_region> region(
wl_compositor_create_region(connection_->compositor()));
wl_region_add(region.get(), 0, 0, region_size.width(), region_size.height());
wl_surface_set_opaque_region(surface(), region.get());
gfx::Rect region_px =
enable_blend_ ? gfx::Rect() : gfx::Rect(bounds_px_.size());
wayland_surface()->SetOpaqueRegion(region_px);
}
void WaylandSubsurface::SetBounds(const gfx::Rect& bounds) {
......@@ -115,21 +114,22 @@ void WaylandSubsurface::CreateSubsurface() {
wl_compositor_create_region(connection_->compositor()));
wl_region_add(region.get(), 0, 0, 0, 0);
wl_surface_set_input_region(surface(), region.get());
connection_->buffer_manager_host()->SetSurfaceConfigured(wayland_surface());
}
void WaylandSubsurface::ConfigureAndShowSurface(
gfx::OverlayTransform transform,
const gfx::RectF& src_rect,
const gfx::Rect& bounds_rect,
bool enable_blend,
const WaylandSurface* reference_below,
const WaylandSurface* reference_above) {
wayland_surface()->SetBufferTransform(transform);
wayland_surface()->SetBufferScale(parent_->buffer_scale(), false);
gfx::Rect bounds_px{
bounds_rect.origin() + parent_->GetBounds().origin().OffsetFromOrigin(),
bounds_rect.size()};
auto old_bounds = bounds_px_;
SetBounds(bounds_px);
SetBounds(bounds_rect);
if (old_bounds != bounds_px_ || enable_blend_ != enable_blend) {
enable_blend_ = enable_blend;
......@@ -144,6 +144,9 @@ void WaylandSubsurface::ConfigureAndShowSurface(
} else if (reference_above) {
wl_subsurface_place_below(subsurface_.get(), reference_above->surface());
}
wayland_surface()->SetViewportSource(src_rect);
wayland_surface()->SetViewportDestination(bounds_rect.size());
}
} // namespace ui
......@@ -34,7 +34,23 @@ class WaylandSubsurface {
// Sets up wl_surface and wl_subsurface. Allows an overlay to be shown
// correctly once a wl_buffer is attached.
// |transform|: specifies the wl_surface buffer_transform.
// |src_rect|: specifies the displayable content (wp_viewport.src) of
// upcoming attached buffers.
// |bounds_rect|: The contents of the source rectangle are scaled to the
// destination size (wp_viewport.dst).
// |enable_blend|: whether the wl_surface will be transluscent.
// |reference_below| & |reference_above|: this subsurface is taken from the
// subsurface stack and inserted back to be immediately below/above the
// reference subsurface.
//
// The coordinate transformations from buffer pixel coordinates up to the
// surface-local coordinates happen in the following order:
// 1. buffer_transform
// 2. buffer_scale
// 3. crop and scale of viewport
void ConfigureAndShowSurface(gfx::OverlayTransform transform,
const gfx::RectF& src_rect,
const gfx::Rect& bounds_rect,
bool enable_blend,
const WaylandSurface* reference_below,
......
......@@ -4,7 +4,11 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include <viewporter-client-protocol.h>
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/native_widget_types.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_window.h"
......@@ -38,6 +42,15 @@ bool WaylandSurface::Initialize() {
};
wl_surface_add_listener(surface_.get(), &surface_listener, this);
if (connection_->viewporter()) {
viewport_.reset(
wp_viewporter_get_viewport(connection_->viewporter(), surface()));
if (!viewport_) {
LOG(ERROR) << "Failed to create wp_viewport";
return false;
}
}
return true;
}
......@@ -54,7 +67,39 @@ void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
connection_->ScheduleFlush();
}
void WaylandSurface::Damage(const gfx::Rect& pending_damage_region) {
void WaylandSurface::UpdateBufferDamageRegion(
const gfx::Rect& pending_damage_region,
const gfx::Size& buffer_size) {
// Buffer-local coordinates are in pixels, surface coordinates are in DIP.
// The coordinate transformations from buffer pixel coordinates up to
// the surface-local coordinates happen in the following order:
// 1. buffer_transform (wl_surface.set_buffer_transform)
// 2. buffer_scale (wl_surface.set_buffer_scale)
// 3. crop and scale (wp_viewport.set*)
// Apply buffer_transform (wl_surface.set_buffer_transform).
gfx::Size bounds = wl::ApplyWaylandTransform(
buffer_size, wl::ToWaylandTransform(buffer_transform_));
// Apply buffer_scale (wl_surface.set_buffer_scale).
bounds = gfx::ScaleToCeiledSize(bounds, 1.f / buffer_scale_);
// Apply crop (wp_viewport.set_source).
gfx::Rect viewport_src = gfx::Rect(bounds);
if (!crop_rect_.IsEmpty()) {
viewport_src = gfx::ToEnclosedRect(
gfx::ScaleRect(crop_rect_, bounds.width(), bounds.height()));
wp_viewport_set_source(viewport(), wl_fixed_from_int(viewport_src.x()),
wl_fixed_from_int(viewport_src.y()),
wl_fixed_from_int(viewport_src.width()),
wl_fixed_from_int(viewport_src.height()));
}
// Apply viewport scale (wp_viewport.set_destination).
gfx::Size viewport_dst = bounds;
if (!display_size_px_.IsEmpty()) {
viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
wp_viewport_set_destination(viewport(), viewport_dst.width(),
viewport_dst.height());
}
if (connection_->compositor_version() >=
WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
// wl_surface_damage_buffer relies on compositor API version 4. See
......@@ -65,20 +110,29 @@ void WaylandSurface::Damage(const gfx::Rect& pending_damage_region) {
surface_.get(), pending_damage_region.x(), pending_damage_region.y(),
pending_damage_region.width(), pending_damage_region.height());
} else {
// The calculation for damage region relies on two assumptions:
// 1) The buffer is always attached at surface location (0, 0)
// 2) The API wl_surface::set_buffer_transform is not used.
// It's possible to write logic that accounts for both cases above, but
// it's currently unnecessary.
//
// Note: The damage region may not be an integer multiple of scale. To
// keep the implementation simple, the x() and y() coordinates round down,
// and the width() and height() calculations always add an extra pixel.
wl_surface_damage(surface_.get(), pending_damage_region.x() / buffer_scale_,
pending_damage_region.y() / buffer_scale_,
pending_damage_region.width() / buffer_scale_ + 1,
pending_damage_region.height() / buffer_scale_ + 1);
// Calculate the damage region in surface coordinates.
// The calculation for damage region relies on the assumption: The buffer is
// always attached at surface location (0, 0).
// It's possible to write logic that accounts for attaching buffer at other
// locations, but it's currently unnecessary.
// Apply buffer_transform (wl_surface.set_buffer_transform).
gfx::Rect damage =
wl::ApplyWaylandTransform(pending_damage_region, buffer_size,
wl::ToWaylandTransform(buffer_transform_));
// Apply buffer_scale (wl_surface.set_buffer_scale).
damage = gfx::ScaleToEnclosingRect(damage, 1.f / buffer_scale_);
// Adjust coordinates to |viewport_src| (wp_viewport.set_source).
damage = wl::TranslateBoundsToParentCoordinates(damage, viewport_src);
// Apply viewport scale (wp_viewport.set_destination).
damage = gfx::ScaleToEnclosingRect(
damage, static_cast<float>(viewport_dst.width()) / viewport_src.width(),
static_cast<float>(viewport_dst.height()) / viewport_src.height());
wl_surface_damage(surface_.get(), damage.x(), damage.y(), damage.width(),
damage.height());
}
connection_->ScheduleFlush();
}
......@@ -87,6 +141,16 @@ void WaylandSurface::Commit() {
connection_->ScheduleFlush();
}
void WaylandSurface::SetBufferTransform(gfx::OverlayTransform transform) {
DCHECK(transform != gfx::OVERLAY_TRANSFORM_INVALID);
if (buffer_transform_ == transform)
return;
buffer_transform_ = transform;
wl_output_transform wl_transform = wl::ToWaylandTransform(buffer_transform_);
wl_surface_set_buffer_transform(surface_.get(), wl_transform);
}
void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
DCHECK_GT(new_scale, 0);
......@@ -98,7 +162,7 @@ void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
connection_->ScheduleFlush();
}
void WaylandSurface::SetBounds(const gfx::Rect& bounds_px) {
void WaylandSurface::SetOpaqueRegion(const gfx::Rect& region_px) {
// It's important to set opaque region for opaque windows (provides
// optimization hint for the Wayland compositor).
if (!root_window_ || !root_window_->IsOpaqueWindow())
......@@ -106,13 +170,38 @@ void WaylandSurface::SetBounds(const gfx::Rect& bounds_px) {
wl::Object<wl_region> region(
wl_compositor_create_region(connection_->compositor()));
wl_region_add(region.get(), 0, 0, bounds_px.width(), bounds_px.height());
gfx::Rect region_dip =
gfx::ScaleToEnclosingRect(region_px, 1.f / buffer_scale_);
wl_region_add(region.get(), region_dip.x(), region_dip.y(),
region_dip.width(), region_dip.height());
wl_surface_set_opaque_region(surface_.get(), region.get());
connection_->ScheduleFlush();
}
void WaylandSurface::SetViewportSource(const gfx::RectF& src_rect) {
if (src_rect == crop_rect_) {
return;
} else if (src_rect.IsEmpty() || src_rect == gfx::RectF{0.f, 0.f, 1.f, 1.f}) {
wp_viewport_set_source(viewport(), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1));
return;
}
crop_rect_ = src_rect;
}
void WaylandSurface::SetViewportDestination(const gfx::Size& dest_size_px) {
if (dest_size_px == display_size_px_) {
return;
} else if (dest_size_px.IsEmpty()) {
wp_viewport_set_destination(viewport(), -1, -1);
}
display_size_px_ = dest_size_px;
}
wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
WaylandSurface* parent) {
DCHECK(parent);
......
......@@ -8,7 +8,9 @@
#include <cstdint>
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
namespace ui {
......@@ -26,6 +28,7 @@ class WaylandSurface {
WaylandWindow* root_window() const { return root_window_; }
wl_surface* surface() const { return surface_.get(); }
wp_viewport* viewport() const { return viewport_.get(); }
int32_t buffer_scale() const { return buffer_scale_; }
void set_buffer_scale(int32_t scale) { buffer_scale_ = scale; }
......@@ -47,19 +50,35 @@ class WaylandSurface {
// Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
void AttachBuffer(wl_buffer* buffer);
// Damages the surface according to |pending_damage_region|, which should be
// in surface coordinates (dp).
void Damage(const gfx::Rect& pending_damage_region);
// Describes where the surface needs to be repainted according to
// |buffer_pending_damage_region|, which should be in buffer coordinates (px).
void UpdateBufferDamageRegion(const gfx::Rect& buffer_pending_damage_region,
const gfx::Size& buffer_size);
// Commits the underlying wl_surface.
void Commit();
// Sets an optional transformation for how the Wayland compositor interprets
// the contents of the buffer attached to this surface.
void SetBufferTransform(gfx::OverlayTransform transform);
// Sets the buffer scale for this surface.
void SetBufferScale(int32_t scale, bool update_bounds);
// Sets the bounds on this surface. This is used for determining the opaque
// region.
void SetBounds(const gfx::Rect& bounds_px);
// Sets the region that is opaque on this surface in physical pixels. This is
// expected to be called whenever the region that the surface span changes or
// the opacity changes.
void SetOpaqueRegion(const gfx::Rect& bounds_px);
// Set the source rectangle of the associated wl_surface.
// See:
// https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/viewporter/viewporter.xml
// If |src_rect| is empty, the source rectangle is unset.
void SetViewportSource(const gfx::RectF& src_rect);
// Set the destination size of the associated wl_surface according to
// |dest_size_px|, which should be in physical pixels.
void SetViewportDestination(const gfx::Size& dest_size_px);
// Creates a wl_subsurface relating this surface and a parent surface,
// |parent|. Callers take ownership of the wl_subsurface.
......@@ -69,11 +88,28 @@ class WaylandSurface {
WaylandConnection* const connection_;
WaylandWindow* root_window_ = nullptr;
wl::Object<wl_surface> surface_;
wl::Object<wp_viewport> viewport_;
// Wayland's scale factor for the output that this window currently belongs
// Transformation for how the compositor interprets the contents of the
// buffer.
gfx::OverlayTransform buffer_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
// Wayland's scale factor for the output that this surface currently belongs
// to.
int32_t buffer_scale_ = 1;
// Following fields are used to help determine the damage_region in
// surface-local coordinates if wl_surface_damage_buffer() is not available.
// Normalized bounds of the buffer to be displayed in |display_size_px_|.
// If empty, no cropping is applied.
gfx::RectF crop_rect_ = gfx::RectF();
// Current size of the destination of the viewport in physical pixels. Wayland
// compositor will scale the (cropped) buffer content to fit the
// |display_size_px_|.
// If empty, no scaling is applied.
gfx::Size display_size_px_ = gfx::Size();
// wl_surface_listener
static void Enter(void* data,
struct wl_surface* wl_surface,
......
......@@ -134,7 +134,7 @@ void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
return;
bounds_px_ = bounds_px;
root_surface_->SetBounds(bounds_px);
root_surface_->SetOpaqueRegion(bounds_px);
delegate_->OnBoundsChanged(bounds_px_);
}
......@@ -358,7 +358,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
// Will do nothing for menus because they have got their scale above.
UpdateBufferScale(false);
root_surface_->SetBounds(bounds_px_);
root_surface_->SetOpaqueRegion(bounds_px_);
return true;
}
......@@ -568,8 +568,9 @@ bool WaylandWindow::CommitOverlays(
reference_above = (*std::next(iter))->wayland_surface();
}
(*iter)->ConfigureAndShowSurface(
(*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
(*overlay_iter)->enable_blend, nullptr, reference_above);
(*overlay_iter)->transform, (*overlay_iter)->crop_rect,
(*overlay_iter)->bounds_rect, (*overlay_iter)->enable_blend,
nullptr, reference_above);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
gfx::Rect());
......@@ -596,8 +597,9 @@ bool WaylandWindow::CommitOverlays(
reference_below = (*std::prev(iter))->wayland_surface();
}
(*iter)->ConfigureAndShowSurface(
(*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
(*overlay_iter)->enable_blend, reference_below, nullptr);
(*overlay_iter)->transform, (*overlay_iter)->crop_rect,
(*overlay_iter)->bounds_rect, (*overlay_iter)->enable_blend,
reference_below, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
gfx::Rect());
......
......@@ -2128,8 +2128,9 @@ TEST_P(WaylandWindowTest, OneWaylandSubsurface) {
auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
wayland_subsurface->wayland_surface()->GetSurfaceId());
EXPECT_TRUE(mock_surface_subsurface);
wayland_subsurface->ConfigureAndShowSurface(
gfx::OVERLAY_TRANSFORM_NONE, subsurface_bounds, true, nullptr, nullptr);
wayland_subsurface->ConfigureAndShowSurface(gfx::OVERLAY_TRANSFORM_NONE,
gfx::RectF(), subsurface_bounds,
true, nullptr, nullptr);
connection_->ScheduleFlush();
Sync();
......
......@@ -89,6 +89,8 @@ MockSurface::~MockSurface() {
wl_resource_destroy(xdg_surface_->resource());
if (sub_surface_ && sub_surface_->resource())
wl_resource_destroy(sub_surface_->resource());
if (viewport_ && viewport_->resource())
wl_resource_destroy(viewport_->resource());
}
MockSurface* MockSurface::FromResource(wl_resource* resource) {
......
......@@ -15,6 +15,7 @@
#include "ui/ozone/platform/wayland/test/mock_xdg_surface.h"
#include "ui/ozone/platform/wayland/test/server_object.h"
#include "ui/ozone/platform/wayland/test/test_subsurface.h"
#include "ui/ozone/platform/wayland/test/test_viewport.h"
#include "ui/ozone/platform/wayland/test/test_xdg_popup.h"
struct wl_resource;
......@@ -52,6 +53,9 @@ class MockSurface : public ServerObject {
}
TestSubSurface* sub_surface() const { return sub_surface_; }
void set_viewport(TestViewport* viewport) { viewport_ = viewport; }
TestViewport* viewport() { return viewport_; }
void set_frame_callback(wl_resource* callback_resource) {
DCHECK(!frame_callback_);
frame_callback_ = callback_resource;
......@@ -70,6 +74,7 @@ class MockSurface : public ServerObject {
private:
MockXdgSurface* xdg_surface_ = nullptr;
TestSubSurface* sub_surface_ = nullptr;
TestViewport* viewport_ = nullptr;
wl_resource* frame_callback_ = nullptr;
......
// Copyright 2020 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/test/test_viewport.h"
#include "base/notreached.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
namespace wl {
namespace {
void SetSource(wl_client* client,
wl_resource* resource,
wl_fixed_t x,
wl_fixed_t y,
wl_fixed_t width,
wl_fixed_t height) {
NOTIMPLEMENTED_LOG_ONCE();
}
void SetDestination(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y) {
NOTIMPLEMENTED_LOG_ONCE();
}
} // namespace
const struct wp_viewport_interface kTestViewportImpl = {
DestroyResource,
SetSource,
SetDestination,
};
TestViewport::TestViewport(wl_resource* resource, wl_resource* surface)
: ServerObject(resource), surface_(surface) {
DCHECK(surface_);
}
TestViewport::~TestViewport() {
auto* mock_surface = GetUserDataAs<MockSurface>(surface_);
if (mock_surface)
mock_surface->set_viewport(nullptr);
}
} // namespace wl
// Copyright 2020 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_TEST_TEST_VIEWPORT_H_
#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORT_H_
#include <viewporter-server-protocol.h>
#include "ui/ozone/platform/wayland/test/server_object.h"
struct wl_resource;
namespace wl {
extern const struct wp_viewport_interface kTestViewportImpl;
class TestViewport : public ServerObject {
public:
explicit TestViewport(wl_resource* resource, wl_resource* surface);
~TestViewport() override;
TestViewport(const TestViewport& rhs) = delete;
TestViewport& operator=(const TestViewport& rhs) = delete;
private:
// Surface resource that is the ground for this Viewport.
wl_resource* surface_ = nullptr;
};
} // namespace wl
#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORT_H_
// Copyright 2020 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/test/test_viewporter.h"
#include <viewporter-server-protocol.h>
#include <wayland-server-core.h>
#include "base/check.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/test_viewport.h"
namespace wl {
namespace {
constexpr uint32_t kViewporterVersion = 1;
void GetViewport(struct wl_client* client,
struct wl_resource* resource,
uint32_t id,
struct wl_resource* surface) {
auto* mock_surface = GetUserDataAs<MockSurface>(surface);
if (mock_surface->viewport()) {
wl_resource_post_error(resource, WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
"viewport exists");
return;
}
wl_resource* viewport_resource =
CreateResourceWithImpl<::testing::NiceMock<TestViewport>>(
client, &wp_viewport_interface, wl_resource_get_version(resource),
&kTestViewportImpl, id, surface);
DCHECK(viewport_resource);
mock_surface->set_viewport(GetUserDataAs<TestViewport>(viewport_resource));
}
} // namespace
const struct wp_viewporter_interface kTestViewporterImpl = {
DestroyResource,
GetViewport,
};
TestViewporter::TestViewporter()
: GlobalObject(&wp_viewporter_interface,
&kTestViewporterImpl,
kViewporterVersion) {}
TestViewporter::~TestViewporter() = default;
} // namespace wl
// Copyright 2020 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_TEST_TEST_VIEWPORTER_H_
#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORTER_H_
#include "ui/ozone/platform/wayland/test/global_object.h"
namespace wl {
// Manage wl_viewporter object.
class TestViewporter : public GlobalObject {
public:
TestViewporter();
~TestViewporter() override;
TestViewporter(const TestViewporter& rhs) = delete;
TestViewporter& operator=(const TestViewporter& rhs) = delete;
};
} // namespace wl
#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_VIEWPORTER_H_
......@@ -58,6 +58,8 @@ bool TestWaylandServerThread::Start(uint32_t shell_version) {
return false;
if (!sub_compositor_.Initialize(display_.get()))
return false;
if (!viewporter_.Initialize(display_.get()))
return false;
if (!output_.Initialize(display_.get()))
return false;
SetupOutputs();
......
......@@ -22,6 +22,7 @@
#include "ui/ozone/platform/wayland/test/test_output.h"
#include "ui/ozone/platform/wayland/test/test_seat.h"
#include "ui/ozone/platform/wayland/test/test_subcompositor.h"
#include "ui/ozone/platform/wayland/test/test_viewporter.h"
#include "ui/ozone/platform/wayland/test/test_zwp_text_input_manager.h"
struct wl_client;
......@@ -111,6 +112,7 @@ class TestWaylandServerThread : public base::Thread,
// Represent Wayland global objects
TestCompositor compositor_;
TestSubCompositor sub_compositor_;
TestViewporter viewporter_;
TestDataDeviceManager data_device_manager_;
TestOutput output_;
TestSeat seat_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment