// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_EXO_SURFACE_H_
#define COMPONENTS_EXO_SURFACE_H_
#include <list>
#include <optional>
#include <utility>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "cc/base/region.h"
#include "chromeos/ui/frame/caption_buttons/snap_controller.h"
#include "components/exo/buffer.h"
#include "components/exo/layer_tree_frame_sink_holder.h"
#include "components/exo/surface_delegate.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/native_widget_types.h"
class SkPath;
namespace ash {
class OutputProtectionDelegate;
}
namespace base {
namespace trace_event {
class TracedValue;
}
} // namespace base
namespace gfx {
class ColorSpace;
class GpuFence;
struct PresentationFeedback;
} // namespace gfx
namespace viz {
class CompositorFrame;
}
namespace exo {
// Occluded surfaces can be detected and not emitted as a quad in the
// corresponding compositor frame.
BASE_DECLARE_FEATURE(kExoPerSurfaceOcclusion);
class Buffer;
class SecurityDelegate;
class FrameSinkResourceManager;
class SurfaceObserver;
namespace subtle {
class PropertyHelper;
}
// Counter-clockwise rotations.
enum class Transform {
NORMAL,
ROTATE_90,
ROTATE_180,
ROTATE_270,
FLIPPED,
FLIPPED_ROTATE_90,
FLIPPED_ROTATE_180,
FLIPPED_ROTATE_270
};
// Priority for overlay promotion.
enum class OverlayPriority { LOW, REGULAR, REQUIRED };
// A property key to store the surface Id set by the client.
extern const ui::ClassProperty<std::string*>* const kClientSurfaceIdKey;
// A property key to store the window session Id set by client or full_restore
// component.
extern const ui::ClassProperty<int32_t>* const kWindowSessionId;
// This class represents a rectangular area that is displayed on the screen.
// It has a location, size and pixel contents.
class Surface final : public ui::PropertyHandler {
public:
using PropertyDeallocator = void (*)(int64_t value);
using LeaveEnterCallback = base::RepeatingCallback<bool(int64_t, int64_t)>;
Surface();
Surface(const Surface&) = delete;
Surface& operator=(const Surface&) = delete;
~Surface() override;
// Type-checking downcast routine.
static Surface* AsSurface(const aura::Window* window);
aura::Window* window() const { return window_.get(); }
std::vector<raw_ptr<aura::Window, VectorExperimental>> GetChildWindows()
const;
void set_leave_enter_callback(LeaveEnterCallback callback) {
leave_enter_callback_ = callback;
}
void set_legacy_buffer_release_skippable(bool skippable) {
legacy_buffer_release_skippable_ = skippable;
}
bool is_augmented() const { return is_augmented_; }
void set_is_augmented(bool augmented) { is_augmented_ = augmented; }
// Called when the display the surface is on has changed.
// Returns true if successful, and false if it fails.
bool UpdateDisplay(int64_t old_id, int64_t new_id);
display::Display GetDisplay() const;
// Called when the output is added for new display.
void OnNewOutputAdded();
// Set a buffer as the content of this surface. A buffer can only be attached
// to one surface at a time.
void Attach(Buffer* buffer);
void Attach(Buffer* buffer, gfx::Vector2d offset);
gfx::Vector2d GetBufferOffset();
// Returns whether the surface has an uncommitted attached buffer.
bool HasPendingAttachedBuffer() const;
// Describe the regions where the pending buffer is different from the
// current surface contents, and where the surface therefore needs to be
// repainted.
void Damage(const gfx::Rect& rect);
// Request notification when it's a good time to produce a new frame. Useful
// for throttling redrawing operations, and driving animations.
using FrameCallback =
base::RepeatingCallback<void(base::TimeTicks frame_time)>;
void RequestFrameCallback(const FrameCallback& callback);
// Request notification when the next frame is displayed. Useful for
// throttling redrawing operations, and driving animations.
using PresentationCallback =
base::RepeatingCallback<void(const gfx::PresentationFeedback&)>;
void RequestPresentationCallback(const PresentationCallback& callback);
// This sets the region of the surface that contains opaque content.
void SetOpaqueRegion(const cc::Region& region);
// This sets the region of the surface that can receive pointer and touch
// events. The region is clipped to the surface bounds.
void SetInputRegion(const cc::Region& region);
const cc::Region& hit_test_region() const { return hit_test_region_; }
// This resets the region of the surface that can receive pointer and touch
// events to be wide-open. This will be clipped to the surface bounds.
void ResetInputRegion();
// This overrides the input region to the surface bounds with an outset.
// TODO(domlaskowski): Remove this once client-driven resizing is removed.
void SetInputOutset(int outset);
// This sets the scaling factor used to interpret the contents of the buffer
// attached to the surface. Note that if the scale is larger than 1, then you
// have to attach a buffer that is larger (by a factor of scale in each
// dimension) than the desired surface size.
void SetBufferScale(float scale);
// This sets the transformation used to interpret the contents of the buffer
// attached to the surface.
void SetBufferTransform(Transform transform);
// Functions that control sub-surface state. All sub-surface state is
// double-buffered and will be applied when Commit() is called.
void AddSubSurface(Surface* sub_surface);
void RemoveSubSurface(Surface* sub_surface);
// Allow for finer granularity for sub surface positioning.
void SetSubSurfacePosition(Surface* sub_surface, const gfx::PointF& position);
void PlaceSubSurfaceAbove(Surface* sub_surface, Surface* reference);
void PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling);
void OnSubSurfaceCommit();
using SubSurfaceEntry = std::pair<Surface*, gfx::PointF>;
using SubSurfaceEntryList = std::list<SubSurfaceEntry>;
SubSurfaceEntryList& sub_surfaces() { return sub_surfaces_; }
SubSurfaceEntryList& render_layers() { return render_layers_; }
// `rounded_corners_bounds` is on the local surface coordinates.
// If `commit` is true, rounded corner bounds are add to committed state,
// overriding the previously committed value.
void SetRoundedCorners(const gfx::RRectF& rounded_corners_bounds,
bool commit_override);
void SetOverlayPriorityHint(OverlayPriority hint);
// Sets the surface's clip rectangle.
void SetClipRect(const std::optional<gfx::RectF>& clip_rect);
// Sets the trace ID for tracking frame submission, which is used for the next
// surface commit.
void SetFrameTraceId(int64_t frame_trace_id);
// Sets the surface's transformation matrix.
void SetSurfaceTransform(const gfx::Transform& transform);
// Sets the background color that shall be associated with the next buffer
// commit.
void SetBackgroundColor(std::optional<SkColor4f> background_color);
// This sets the surface viewport for scaling.
void SetViewport(const gfx::SizeF& viewport);
// This sets the surface crop rectangle.
void SetCrop(const gfx::RectF& crop);
// This sets the only visible on secure output flag, preventing it from
// appearing in screenshots or from being viewed on non-secure displays.
void SetOnlyVisibleOnSecureOutput(bool only_visible_on_secure_output);
// This sets the blend mode that will be used when drawing the surface.
void SetBlendMode(SkBlendMode blend_mode);
// This sets the alpha value that will be applied to the whole surface.
void SetAlpha(float alpha);
// Request that surface should have the specified frame type.
void SetFrame(SurfaceFrameType type);
// Request that the server should start resize on this surface.
void SetServerStartResize();
// Request that surface should use a specific set of frame colors.
void SetFrameColors(SkColor active_color, SkColor inactive_color);
// Request that surface should have a specific startup ID string.
void SetStartupId(const char* startup_id);
// Request that surface should have a specific application ID string.
void SetApplicationId(const char* application_id);
// Whether to show/hide the shelf when fullscreen. If true, the titlebar/shelf
// will show when the mouse moves to the top/bottom of the screen. If false
// (plain fullscreen), the titlebar and shelf are always hidden.
void SetUseImmersiveForFullscreen(bool value);
// Called to show the snap preview to the primary or secondary position, or
// to hide it.
void ShowSnapPreviewToSecondary();
void ShowSnapPreviewToPrimary();
void HideSnapPreview();
// Called when the client was snapped to primary or secondary position, or
// reset.
void SetSnapPrimary(float snap_ratio);
void SetSnapSecondary(float snap_ratio);
void UnsetSnap();
// Whether the current client window can go back, as per its navigation list.
void SetCanGoBack();
void UnsetCanGoBack();
// This sets the color space for the buffer for this surface.
void SetColorSpace(gfx::ColorSpace color_space);
// Request "parent" for surface.
void SetParent(Surface* parent, const gfx::Point& position);
// Request that surface should have a specific ID assigned by client.
void SetClientSurfaceId(const char* client_surface_id);
std::string GetClientSurfaceId() const;
// Sets whether the surface contains video.
void SetContainsVideo(bool contains_video);
// Returns whether this surface or any of its subsurfaces contains a video.
bool ContainsVideo();
// Request that the attached surface buffer at the next commit is associated
// with a gpu fence to be signaled when the buffer is ready for use.
void SetAcquireFence(std::unique_ptr<gfx::GpuFence> gpu_fence);
// Returns whether the surface has an uncommitted acquire fence.
bool HasPendingAcquireFence() const;
// Returns whether the surface has a committed acquire fence.
bool HasAcquireFence() const;
// Request a callback when the buffer attached at the next commit is
// no longer used by that commit.
void SetPerCommitBufferReleaseCallback(
Buffer::PerCommitExplicitReleaseCallback callback);
// Whether the surface has an uncommitted per-commit buffer release callback.
bool HasPendingPerCommitBufferReleaseCallback() const;
// Surface state (damage regions, attached buffers, etc.) is double-buffered.
// A Commit() call atomically applies all pending state, replacing the
// current state. Commit() is not guaranteed to be synchronous. See
// CommitSurfaceHierarchy() below.
void Commit();
// This will commit all pending state of the surface and its descendants by
// recursively calling CommitSurfaceHierarchy() for each sub-surface.
// If |synchronized| is set to false, then synchronized surfaces should not
// commit pending state.
void CommitSurfaceHierarchy(bool synchronized);
// This will append current callbacks for surface and its descendants to
// |frame_callbacks| and |presentation_callbacks|.
void AppendSurfaceHierarchyCallbacks(
std::list<FrameCallback>* frame_callbacks,
std::list<PresentationCallback>* presentation_callbacks);
// This will append contents for surface and its descendants to frame.
void AppendSurfaceHierarchyContentsToFrame(
const gfx::PointF& parent_to_root_px,
const gfx::PointF& to_parent_dp,
bool needs_full_damage,
FrameSinkResourceManager* resource_manager,
std::optional<float> device_scale_factor,
viz::CompositorFrame* frame);
// Returns true if surface is in synchronized mode.
bool IsSynchronized() const;
// Returns true if surface should receive input events.
bool IsInputEnabled(Surface* surface) const;
// Returns false if the hit test region is empty.
bool HasHitTestRegion() const;
// Returns true if |point| is inside the surface.
bool HitTest(const gfx::Point& point) const;
// Sets |mask| to the path that delineates the hit test region of the surface.
void GetHitTestMask(SkPath* mask) const;
// Set the surface delegate.
void SetSurfaceDelegate(SurfaceDelegate* delegate);
// Returns true if surface has been assigned a surface delegate.
bool HasSurfaceDelegate() const;
// Returns a pointer to the SurfaceDelegate for this surface, used by tests.
SurfaceDelegate* GetDelegateForTesting();
// Surface does not own observers. It is the responsibility of the observer
// to remove itself when it is done observing.
void AddSurfaceObserver(SurfaceObserver* observer);
void RemoveSurfaceObserver(SurfaceObserver* observer);
bool HasSurfaceObserver(const SurfaceObserver* observer) const;
// Returns a trace value representing the state of the surface.
std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
// Called when the begin frame source has changed.
void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source);
// Returns the active content size.
const gfx::SizeF& content_size() const { return content_size_; }
// Returns the active content bounds for surface hierarchy. ie. the bounding
// box of the surface and its descendants, in the local coordinate space of
// the surface.
const gfx::Rect& surface_hierarchy_content_bounds() const {
return surface_hierarchy_content_bounds_;
}
// Returns true if the associated window is in 'stylus-only' mode.
bool IsStylusOnly();
// Enables 'stylus-only' mode for the associated window.
void SetStylusOnly();
// Notify surface that resources and subsurfaces' resources have been lost.
void SurfaceHierarchyResourcesLost();
// Returns true if the surface's bounds should be filled opaquely.
bool FillsBoundsOpaquely() const;
bool HasPendingDamageForTesting(const gfx::Rect& damage) const {
return pending_state_.damage.Contains(damage);
}
bool HasLeaveEnterCallbackForTesting() const {
return !leave_enter_callback_.is_null();
}
// Set occlusion tracking region for surface.
void SetOcclusionTracking(bool tracking);
void OnScaleFactorChanged(float old_scale_factor, float new_scale_factor);
// Triggers sending an occlusion update to observers.
void OnWindowOcclusionChanged(
aura::Window::OcclusionState old_occlusion_state,
aura::Window::OcclusionState new_occlusion_state);
// Triggers sending a locking status to observers.
// true : lock a frame to normal or restore state
// false : unlock the previously locked frame
void SetFrameLocked(bool lock);
// True if the window for this surface has its occlusion tracked.
bool IsTrackingOcclusion();
// Sets the |surface_hierarchy_content_bounds_|.
void SetSurfaceHierarchyContentBoundsForTest(const gfx::Rect& content_bounds);
// Requests that this surface should be made active (i.e. foregrounded).
void RequestActivation();
// Requests that surface my have a window session ID assigned by client or
// full_restore component.
void SetWindowSessionId(int32_t window_session_id);
int32_t GetWindowSessionId();
// Requests that the surface enters PIP mode.
void SetPip();
// Requests that the surface exits PIP mode.
void UnsetPip();
// Requests that the surface maintains the given aspect ratio.
void SetAspectRatio(const gfx::SizeF& aspect_ratio);
// Triggers send desk state of the window to observers.
// |state| is the index of the desk which the window moved to,
// or -1 for a window assigned to all desks.
void OnDeskChanged(int state);
// Requests that DesksController to move the window to a desk at |desk_index|.
void MoveToDesk(int desk_index);
// Requests that window is visible on all workspaces.
void SetVisibleOnAllWorkspaces();
// Sets the initial workspace to restore a window to the corresponding desk.
void SetInitialWorkspace(const char* initial_workspace);
// Pins/locks a window to the screen so that the user cannot do anything
// else before the mode is released. If trusted is set, it is an invocation
// from a trusted app like a school test mode app.
void Pin(bool trusted);
// Release the pinned mode and allows the user to do other things again.
void Unpin();
// Starts or ends throttling on the surface.
void ThrottleFrameRate(bool on);
// Informs tooltip is shown.
void OnTooltipShown(const std::u16string& text, const gfx::Rect& bounds);
// Informs tooltip is hidden.
void OnTooltipHidden();
// If true is set, if this window has a focus, key events should be sent to
// the app, even if it is an ash shortcut (with some exceptions).
// See exo::Keyboard for more details.
void SetKeyboardShortcutsInhibited(bool inhibited);
// Returns whether keyboard shortcuts are inhibited.
bool is_keyboard_shortcuts_inhibited() const {
return keyboard_shortcuts_inhibited_;
}
// Returns the SecurityDelegate associated with this surface, or nullptr
// if one can not be determined. See go/secure-exo-ids for more details.
SecurityDelegate* GetSecurityDelegate();
// Sets the accessibility window ID sent from the shell client to the window.
// A negative number removes it.
void SetClientAccessibilityId(int id);
// Set top inset for surface.
void SetTopInset(int height);
// Inform observers and subsurfaces about new fullscreen state
void OnFullscreenStateChanged(bool fullscreen);
OverlayPriority GetOverlayPriorityHint() {
return state_.overlay_priority_hint;
}
// Returns the buffer scale of the last committed buffer.
float GetBufferScale() const { return state_.basic_state.buffer_scale; }
int64_t GetFrameTraceId() const { return state_.frame_trace_id; }
// Returns the last committed buffer.
Buffer* GetBuffer();
// Dump Debug Info.
std::string DumpDebugInfo() const;
private:
struct State {
State();
~State();
bool operator==(const State& other) const;
bool operator!=(const State& other) const { return !(*this == other); }
cc::Region opaque_region;
std::optional<cc::Region> input_region;
int input_outset = 0;
float buffer_scale = 1.0f;
Transform buffer_transform = Transform::NORMAL;
gfx::SizeF viewport;
gfx::RectF crop;
bool only_visible_on_secure_output = false;
SkBlendMode blend_mode = SkBlendMode::kSrcOver;
float alpha = 1.0f;
gfx::Vector2d offset;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
bool is_tracking_occlusion = false;
// Represents optional background color that must be associated with the
// next buffer commit.
std::optional<SkColor4f> background_color;
bool contains_video = false;
};
class BufferAttachment {
public:
BufferAttachment();
BufferAttachment(const BufferAttachment&) = delete;
BufferAttachment& operator=(const BufferAttachment&) = delete;
~BufferAttachment();
BufferAttachment(BufferAttachment&& buffer);
BufferAttachment& operator=(BufferAttachment&& buffer);
base::WeakPtr<Buffer>& buffer();
const base::WeakPtr<Buffer>& buffer() const;
const gfx::Size& size() const;
void Reset(base::WeakPtr<Buffer> buffer);
private:
base::WeakPtr<Buffer> buffer_;
gfx::Size size_;
};
// State for this surface. State is committed in a three step process:
// 1. Pending state is accummulated into before commit.
// 2. On commit, state is copied to a cached state. This is to support
// synchronized commit of a tree of surfaces. When the tree of surfaces is
// set to be synchronized, the state of the tree will not be committed
// until the root of the tree (precisely, until a unsynchronized root of a
// subtree) is committed.
// 3. State is committed.
// Some fields are persisted between commits (e.g. which buffer is attached),
// and some fields are not (e.g. acquire fence). For fields that are
// persisted, they either need to be copyable, or if they are move only, they
// need to be wrapped in std::optional and only copied on commit if they
// have been changed. Not doing this can lead to broken behaviour, such as
// losing the attached buffer if some unrelated field is updated in a commit.
// If you add new fields to this struct, please document whether the field
// should be persisted between commits.
// See crbug.com/1283305 for context.
struct ExtendedState {
ExtendedState();
~ExtendedState();
State basic_state;
// The buffer that will become the content of surface.
// Persisted between commits.
std::optional<BufferAttachment> buffer;
// The rounded corners bounds for the surface.
// Persisted between commits.
gfx::RRectF rounded_corners_bounds;
// The damage region to schedule paint for.
// Not persisted between commits.
cc::Region damage;
// These lists contain the callbacks to notify the client when it is a good
// time to start producing a new frame.
// Not persisted between commits.
std::list<FrameCallback> frame_callbacks;
// These lists contain the callbacks to notify the client when surface
// contents have been presented.
// Not persisted between commits.
std::list<PresentationCallback> presentation_callbacks;
// The acquire gpu fence to associate with the surface buffer.
// Not persisted between commits.
std::unique_ptr<gfx::GpuFence> acquire_fence;
// Callback to notify about the per-commit buffer release. The wayland
// Exo backend uses this callback to implement the immediate_release
// event of the explicit sync protocol.
// Not persisted between commits.
Buffer::PerCommitExplicitReleaseCallback
per_commit_explicit_release_callback_;
// The hint for overlay prioritization
// Persisted between commits.
OverlayPriority overlay_priority_hint = OverlayPriority::REGULAR;
// The clip rect for this surface, in the local coordinate space. This
// should only be set for subsurfaces.
// Persisted between commits.
std::optional<gfx::RectF> clip_rect;
// The transform to apply when drawing this surface. This should only be set
// for subsurfaces, and doesn't apply to children of this surface.
// Persisted between commits.
gfx::Transform surface_transform;
// Trace ID for tracking frame submission.
// Not persisted between commits.
int64_t frame_trace_id = -1;
};
friend class subtle::PropertyHelper;
// Adjust the stacking order of `list`, returns true if the `list` ordering is
// altered.
bool DoPlaceAboveOrBelow(Surface* child,
Surface* reference,
SubSurfaceEntryList& list,
bool place_above);
// Updates current_resource_ with a new resource id corresponding to the
// contents of the attached buffer (or id 0, if no buffer is attached).
// UpdateSurface must be called afterwards to ensure the release callback
// will be called.
void UpdateResource(FrameSinkResourceManager* resource_manager);
// Updates buffer_transform_ to match the current buffer parameters.
void UpdateBufferTransform(bool y_invert);
// Update state_.overlay_priority_hint and notify observers
void UpdateOverlayPriorityHint(OverlayPriority overlay_priority_hint);
// Puts the current surface into a draw quad, and appends the draw quads into
// the `frame`. `device_scale_factor` is supplied if the client does not
// submit surfaces in pixel coordinates.
void AppendContentsToFrame(const gfx::PointF& parent_to_root_px,
const gfx::PointF& to_parent_dp,
bool needs_full_damage,
std::optional<float> device_scale_factor,
viz::CompositorFrame* frame);
// Update surface content size base on current buffer size.
void UpdateContentSize();
// This returns true when the surface has some contents assigned to it.
bool has_contents() const {
return state_.buffer.has_value() && !state_.buffer->size().IsEmpty();
}
// This window has the layer which contains the Surface contents.
std::unique_ptr<aura::Window> window_;
// Whether this surface is an object only to composite its parent.
bool is_augmented_ = false;
// This is true, if sub_surfaces_ has changes (order, position, etc).
bool sub_surfaces_changed_ = false;
// Because client side damage does not expand past `content_size_`. This
// accounts for damage that are outside of this surface. 3 ways extended
// damage can be introduced if this surface is a subsurface that fits within
// the overall shell_surface's host_window bounds:
//
// 1) This surface's width/height shrinks without changing stacking/position,
// it will not fully damage the parent surface, introduced damage area (dotted
// line). s1 (child of s) shrunk:
//
// _host_window__________ _host_window__________
// |s ______ | |s ____... |
// | |s1 | | | |s1 | : |
// | | | | => | | | : |
// | | | | | |____| : |
// | |______| | | :......: |
// |______________________| |______________________|
//
// 2) The toplevel surface shrinks but not in a way that affects host_window
// bounds due to a subsurface expanding it, introduced damage area (dotted
// line). s (parent of s1) shrunk:
//
// _host_window__________ _host_window__________
// |s ______ | |s ______ |
// | |s1 | | | |s1 | |
// | | | | => |____| |__________|
// | | | | : | | :
// |____|______|__________| :....|______|..........:
//
// 3) This surface has a subsurface that is shown outside, but fits within the
// overall shell_surface's host_window, when the subsurface is removed, it
// fully damage the parent surface, but not the part outside of the parent
// (dotted line). s11 (child of s1) is removed:
//
// _host_window__________ _host_window__________
// |s0 __________ | |s0 __________ |
// | |s1 | | | |s1 | |
// | | ______ | | => | | | |
// | |_|s11 |_| | | |__________| |
// | |______| | | :......: |
// |______________________| |______________________|
//
std::optional<gfx::RectF> extended_damage_dp_ = std::nullopt;
// This is the size of the last committed contents.
gfx::SizeF content_size_;
// This is the bounds of the last committed surface hierarchy contents.
gfx::Rect surface_hierarchy_content_bounds_;
// This is true when Attach() has been called and new contents should be
// cached next time Commit() is called.
bool has_pending_contents_ = false;
// This is true when new contents are cached and should take effect next time
// synchronized CommitSurfaceHierarchy() is called.
bool has_cached_contents_ = false;
// This is the state that has yet to be cached.
ExtendedState pending_state_;
// This is the state that has yet to be committed.
ExtendedState cached_state_;
// This is the state that has been committed.
ExtendedState state_;
// Cumulative input region of surface and its sub-surfaces.
cc::Region hit_test_region_;
// The stack of sub-surfaces to take effect when Commit() is called.
// Bottom-most sub-surface at the front of the list and top-most sub-surface
// at the back.
SubSurfaceEntryList pending_sub_surfaces_;
SubSurfaceEntryList sub_surfaces_;
// The stack of delegate compositing render_layers for this surface when
// Commit() is called.
// The tree structure of this with sub_surface is this (Surface2 is stacked
// beneath Surface3):
//
// Surface1: { layer1, layer2 }
// / \
// / \
// Surface2: { layer3 } \
// Surface3: { layer4, layer5 }
//
// When compositing, from bottom to top, the content order is visually:
// { Surface1, layer1, layer2, Surface2, layer3, Surface3, layer4, layer5 }
//
// TODO(fangzhoug): Reusing wl_subsurface and SubSurface class is not ideal,
// consider introducing a different role object like wl_subsurface, or a base
// object like wl_surface, to better prevent the unintended behavior such has
// a layer parenting a subsurface.
SubSurfaceEntryList render_layers_;
// The last resource that was sent to a surface.
viz::TransferableResource current_resource_;
// Whether the last resource that was sent to a surface has an alpha channel.
bool current_resource_has_alpha_ = false;
// This is true if a call to Commit() as been made but
// CommitSurfaceHierarchy() has not yet been called.
bool needs_commit_surface_ = false;
// This is true if UpdateResources() should be called.
bool needs_update_resource_ = true;
// The current buffer transform matrix. It specifies the transformation from
// normalized buffer coordinates to post-tranform buffer coordinates.
gfx::Transform buffer_transform_;
// This is set when the compositing starts and passed to active frame
// callbacks when compositing successfully ends.
base::TimeTicks last_compositing_start_time_;
// This can be set to have some functions delegated. E.g. ShellSurface class
// can set this to handle Commit() and apply any double buffered state it
// maintains.
raw_ptr<SurfaceDelegate> delegate_ = nullptr;
// Surface observer list. Surface does not own the observers.
base::ObserverList<SurfaceObserver, true>::Unchecked observers_;
std::unique_ptr<ash::OutputProtectionDelegate> output_protection_;
LeaveEnterCallback leave_enter_callback_;
bool keyboard_shortcuts_inhibited_ = false;
bool legacy_buffer_release_skippable_ = false;
// Display id state for unmapped surfaces.
int64_t display_id_ = display::kInvalidDisplayId;
};
class ScopedSurface {
public:
ScopedSurface(Surface* surface, SurfaceObserver* observer);
ScopedSurface(const ScopedSurface&) = delete;
ScopedSurface& operator=(const ScopedSurface&) = delete;
virtual ~ScopedSurface();
Surface* get() { return surface_; }
private:
const raw_ptr<Surface> surface_;
const raw_ptr<SurfaceObserver> observer_;
};
} // namespace exo
#endif // COMPONENTS_EXO_SURFACE_H_