blob: 5d9081b329b385ed4c1c61dac2144b0c774af4e7 [file] [log] [blame]
// Copyright 2021 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 "components/exo/wayland/surface_augmenter.h"
#include <surface-augmenter-server-protocol.h>
#include <memory>
#include "components/exo/buffer.h"
#include "components/exo/sub_surface.h"
#include "components/exo/sub_surface_observer.h"
#include "components/exo/surface.h"
#include "components/exo/surface_observer.h"
#include "components/exo/wayland/server_util.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/geometry/size.h"
namespace exo {
namespace wayland {
namespace {
// A property key containing a boolean set to true if a surface augmenter is
// associated with with surface object.
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasAugmentedSurfaceKey, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSubSurfaceHasAugmentedSubSurfaceKey, false)
////////////////////////////////////////////////////////////////////////////////
// augmented_surface_interface:
// Implements the augmenter interface to a Surface. The "augmented"-state is set
// to null upon destruction. A window property will be set during the lifetime
// of this class to prevent multiple instances from being created for the same
// Surface.
class AugmentedSurface : public SurfaceObserver {
public:
explicit AugmentedSurface(Surface* surface) : surface_(surface) {
surface_->AddSurfaceObserver(this);
surface_->SetProperty(kSurfaceHasAugmentedSurfaceKey, true);
}
AugmentedSurface(const AugmentedSurface&) = delete;
AugmentedSurface& operator=(const AugmentedSurface&) = delete;
~AugmentedSurface() override {
if (surface_) {
surface_->RemoveSurfaceObserver(this);
surface_->SetProperty(kSurfaceHasAugmentedSurfaceKey, false);
}
}
void SetCorners(int32_t x,
int32_t y,
int32_t width,
int32_t height,
double top_left,
double top_right,
double bottom_right,
double bottom_left) {
surface_->SetRoundedCorners(gfx::RRectF(
gfx::RectF(x, y, width, height),
gfx::RoundedCornersF(top_left, top_right, bottom_right, bottom_left)));
}
void SetDestination(float width, float height) {
surface_->SetViewport(gfx::SizeF(width, height));
}
void SetBackgroundColor(absl::optional<SkColor> background_color) {
surface_->SetBackgroundColor(background_color);
}
// SurfaceObserver:
void OnSurfaceDestroying(Surface* surface) override {
surface->RemoveSurfaceObserver(this);
surface_ = nullptr;
}
private:
Surface* surface_;
};
void augmented_surface_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void augmented_surface_set_corners_DEPRECATED(wl_client* client,
wl_resource* resource,
wl_fixed_t top_left,
wl_fixed_t top_right,
wl_fixed_t bottom_right,
wl_fixed_t bottom_left) {
LOG(WARNING) << "Deprecated. The server doesn't support this request.";
}
void augmented_surface_set_destination_size(wl_client* client,
wl_resource* resource,
wl_fixed_t width,
wl_fixed_t height) {
if (width < 0 || height < 0) {
wl_resource_post_error(resource, AUGMENTED_SURFACE_ERROR_BAD_VALUE,
"Dimension can't be negative (%d, %d)", width,
height);
return;
}
GetUserDataAs<AugmentedSurface>(resource)->SetDestination(
wl_fixed_to_double(width), wl_fixed_to_double(height));
}
void augmented_surface_set_rounded_corners_bounds(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height,
wl_fixed_t top_left,
wl_fixed_t top_right,
wl_fixed_t bottom_right,
wl_fixed_t bottom_left) {
if (width < 0 || height < 0 || top_left < 0 || bottom_left < 0 ||
bottom_right < 0 || top_right < 0) {
wl_resource_post_error(resource, AUGMENTED_SURFACE_ERROR_BAD_VALUE,
"The size and corners must have positive values "
"(%d, %d, %d, %d, %d, %d)",
width, height, top_left, top_right, bottom_right,
bottom_left);
return;
}
GetUserDataAs<AugmentedSurface>(resource)->SetCorners(
x, y, width, height, wl_fixed_to_double(top_left),
wl_fixed_to_double(top_right), wl_fixed_to_double(bottom_right),
wl_fixed_to_double(bottom_left));
}
void augmented_surface_set_background_color(wl_client* client,
wl_resource* resource,
wl_array* color_data) {
absl::optional<SkColor> sk_color;
// Empty data means no color.
if (color_data->size) {
float* data = reinterpret_cast<float*>(color_data->data);
SkColor4f color = {data[0], data[1], data[2], data[3]};
sk_color = color.toSkColor();
}
GetUserDataAs<AugmentedSurface>(resource)->SetBackgroundColor(sk_color);
}
const struct augmented_surface_interface augmented_implementation = {
augmented_surface_destroy, augmented_surface_set_corners_DEPRECATED,
augmented_surface_set_destination_size,
augmented_surface_set_rounded_corners_bounds,
augmented_surface_set_background_color};
////////////////////////////////////////////////////////////////////////////////
// augmented_sub_surface_interface:
// Implements the augmenter interface to a Surface. The "augmented"-state is set
// to null upon destruction. A window property will be set during the lifetime
// of this class to prevent multiple instances from being created for the same
// Surface.
class AugmentedSubSurface : public SubSurfaceObserver {
public:
explicit AugmentedSubSurface(SubSurface* sub_surface)
: sub_surface_(sub_surface) {
sub_surface_->AddSubSurfaceObserver(this);
sub_surface_->SetProperty(kSubSurfaceHasAugmentedSubSurfaceKey, true);
}
AugmentedSubSurface(const AugmentedSubSurface&) = delete;
AugmentedSubSurface& operator=(const AugmentedSubSurface&) = delete;
~AugmentedSubSurface() override {
if (sub_surface_) {
sub_surface_->SetProperty(kSubSurfaceHasAugmentedSubSurfaceKey, false);
sub_surface_->RemoveSubSurfaceObserver(this);
}
}
void SetPosition(float x, float y) {
sub_surface_->SetPosition(gfx::PointF(x, y));
}
// SurfaceObserver:
void OnSubSurfaceDestroying(SubSurface* sub_surface) override {
sub_surface->RemoveSubSurfaceObserver(this);
sub_surface_ = nullptr;
}
private:
SubSurface* sub_surface_;
};
void augmented_sub_surface_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void augmented_sub_surface_set_position(wl_client* client,
wl_resource* resource,
wl_fixed_t x,
wl_fixed_t y) {
GetUserDataAs<AugmentedSubSurface>(resource)->SetPosition(
wl_fixed_to_double(x), wl_fixed_to_double(y));
}
const struct augmented_sub_surface_interface
augmented_sub_surface_implementation = {augmented_sub_surface_destroy,
augmented_sub_surface_set_position};
////////////////////////////////////////////////////////////////////////////////
// wl_buffer_interface:
void buffer_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
const struct wl_buffer_interface buffer_implementation = {buffer_destroy};
////////////////////////////////////////////////////////////////////////////////
// surface_augmenter_interface:
void augmenter_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void HandleBufferReleaseCallback(wl_resource* resource) {
wl_buffer_send_release(resource);
wl_client_flush(wl_resource_get_client(resource));
}
void augmenter_create_solid_color_buffer(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_array* color_data,
int width,
int height) {
float* data = reinterpret_cast<float*>(color_data->data);
SkColor4f color = {data[0], data[1], data[2], data[3]};
std::unique_ptr<SolidColorBuffer> buffer =
std::make_unique<SolidColorBuffer>(color, gfx::Size(width, height));
wl_resource* buffer_resource = wl_resource_create(
client, &wl_buffer_interface, wl_resource_get_version(resource), id);
buffer->set_release_callback(base::BindRepeating(
&HandleBufferReleaseCallback, base::Unretained(buffer_resource)));
SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer));
}
void augmenter_get_augmented_surface(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_resource* surface_resource) {
Surface* surface = GetUserDataAs<Surface>(surface_resource);
if (surface->GetProperty(kSurfaceHasAugmentedSurfaceKey)) {
wl_resource_post_error(resource,
SURFACE_AUGMENTER_ERROR_AUGMENTED_SURFACE_EXISTS,
"an augmenter for that surface already exists");
return;
}
wl_resource* augmented_resource =
wl_resource_create(client, &augmented_surface_interface,
wl_resource_get_version(resource), id);
SetImplementation(augmented_resource, &augmented_implementation,
std::make_unique<AugmentedSurface>(surface));
}
void augmenter_get_augmented_sub_surface(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_resource* sub_surface_resource) {
SubSurface* sub_surface = GetUserDataAs<SubSurface>(sub_surface_resource);
if (sub_surface->GetProperty(kSubSurfaceHasAugmentedSubSurfaceKey)) {
wl_resource_post_error(resource,
SURFACE_AUGMENTER_ERROR_AUGMENTED_SURFACE_EXISTS,
"an augmenter for that sub-surface already exists");
return;
}
wl_resource* augmented_resource =
wl_resource_create(client, &augmented_sub_surface_interface,
wl_resource_get_version(resource), id);
SetImplementation(augmented_resource, &augmented_sub_surface_implementation,
std::make_unique<AugmentedSubSurface>(sub_surface));
}
const struct surface_augmenter_interface augmenter_implementation = {
augmenter_destroy, augmenter_create_solid_color_buffer,
augmenter_get_augmented_surface, augmenter_get_augmented_sub_surface};
} // namespace
void bind_surface_augmenter(wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
wl_resource* resource =
wl_resource_create(client, &surface_augmenter_interface,
std::min(version, kSurfaceAugmenterVersion), id);
wl_resource_set_implementation(resource, &augmenter_implementation, data,
nullptr);
}
} // namespace wayland
} // namespace exo