// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/wayland/zcr_alpha_compositing.h"
#include <alpha-compositing-unstable-v1-server-protocol.h>
#include "base/memory/raw_ptr.h"
#include "components/exo/surface.h"
#include "components/exo/surface_observer.h"
#include "components/exo/wayland/server_util.h"
namespace exo {
namespace wayland {
namespace {
// A property key containing a boolean set to true if a blending object is
// associated with surface object.
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasBlendingKey, false)
////////////////////////////////////////////////////////////////////////////////
// blending_interface:
// Implements the blending interface to a Surface. The "blend mode" and
// "alpha"-state is set to SrcOver and 1 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 Blending : public SurfaceObserver {
public:
explicit Blending(Surface* surface) : surface_(surface) {
surface_->AddSurfaceObserver(this);
surface_->SetProperty(kSurfaceHasBlendingKey, true);
}
Blending(const Blending&) = delete;
Blending& operator=(const Blending&) = delete;
~Blending() override {
if (surface_) {
surface_->RemoveSurfaceObserver(this);
surface_->SetBlendMode(SkBlendMode::kSrcOver);
surface_->SetAlpha(1.0f);
surface_->SetProperty(kSurfaceHasBlendingKey, false);
}
}
void SetBlendMode(SkBlendMode blend_mode) {
if (surface_)
surface_->SetBlendMode(blend_mode);
}
void SetAlpha(float value) {
if (surface_)
surface_->SetAlpha(value);
}
// Overridden from SurfaceObserver:
void OnSurfaceDestroying(Surface* surface) override {
surface->RemoveSurfaceObserver(this);
surface_ = nullptr;
}
private:
raw_ptr<Surface> surface_;
};
void blending_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void blending_set_blending(wl_client* client,
wl_resource* resource,
uint32_t equation) {
switch (equation) {
case ZCR_BLENDING_V1_BLENDING_EQUATION_NONE:
GetUserDataAs<Blending>(resource)->SetBlendMode(SkBlendMode::kSrc);
break;
case ZCR_BLENDING_V1_BLENDING_EQUATION_PREMULT:
GetUserDataAs<Blending>(resource)->SetBlendMode(SkBlendMode::kSrcOver);
break;
case ZCR_BLENDING_V1_BLENDING_EQUATION_COVERAGE:
NOTIMPLEMENTED();
break;
default:
DLOG(WARNING) << "Unsupported blending equation: " << equation;
break;
}
}
void blending_set_alpha(wl_client* client,
wl_resource* resource,
wl_fixed_t alpha) {
GetUserDataAs<Blending>(resource)->SetAlpha(wl_fixed_to_double(alpha));
}
const struct zcr_blending_v1_interface blending_implementation = {
blending_destroy, blending_set_blending, blending_set_alpha};
////////////////////////////////////////////////////////////////////////////////
// alpha_compositing_interface:
void alpha_compositing_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void alpha_compositing_get_blending(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_resource* surface_resource) {
Surface* surface = GetUserDataAs<Surface>(surface_resource);
if (surface->GetProperty(kSurfaceHasBlendingKey)) {
wl_resource_post_error(resource,
ZCR_ALPHA_COMPOSITING_V1_ERROR_BLENDING_EXISTS,
"a blending object for that surface already exists");
return;
}
wl_resource* blending_resource =
wl_resource_create(client, &zcr_blending_v1_interface, 1, id);
SetImplementation(blending_resource, &blending_implementation,
std::make_unique<Blending>(surface));
}
const struct zcr_alpha_compositing_v1_interface
alpha_compositing_implementation = {alpha_compositing_destroy,
alpha_compositing_get_blending};
} // namespace
void bind_alpha_compositing(wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
wl_resource* resource =
wl_resource_create(client, &zcr_alpha_compositing_v1_interface, 1, id);
wl_resource_set_implementation(resource, &alpha_compositing_implementation,
data, nullptr);
}
} // namespace wayland
} // namespace exo