| // Copyright 2015 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 COMPONENTS_EXO_SURFACE_H_ |
| #define COMPONENTS_EXO_SURFACE_H_ |
| |
| #include <list> |
| #include <set> |
| #include <utility> |
| |
| #include "base/callback.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "cc/base/region.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 "third_party/skia/include/core/SkBlendMode.h" |
| #include "ui/aura/window.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "ui/gfx/transform.h" |
| |
| class SkPath; |
| |
| namespace ash { |
| class OutputProtectionDelegate; |
| } |
| |
| namespace base { |
| namespace trace_event { |
| class TracedValue; |
| } |
| } // namespace base |
| |
| namespace gfx { |
| class ColorSpace; |
| class GpuFence; |
| } |
| |
| namespace viz { |
| class CompositorFrame; |
| } |
| |
| namespace exo { |
| class Buffer; |
| class FrameSinkResourceManager; |
| class SurfaceObserver; |
| |
| namespace subtle { |
| class PropertyHelper; |
| } |
| |
| // Counter-clockwise rotations. |
| enum class Transform { NORMAL, ROTATE_90, ROTATE_180, ROTATE_270 }; |
| |
| // A property key to store the surface Id set by the client. |
| extern const ui::ClassProperty<int32_t>* const kClientSurfaceIdKey; |
| |
| // 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<void(int64_t, int64_t)>; |
| |
| Surface(); |
| ~Surface() override; |
| |
| // Type-checking downcast routine. |
| static Surface* AsSurface(const aura::Window* window); |
| |
| aura::Window* window() { return window_.get(); } |
| |
| void set_leave_enter_callback(LeaveEnterCallback callback) { |
| leave_enter_callback_ = callback; |
| } |
| |
| // Called when the display the surface is on has changed. |
| void UpdateDisplay(int64_t old_id, int64_t new_id); |
| |
| // 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); |
| void SetSubSurfacePosition(Surface* sub_surface, const gfx::Point& position); |
| void PlaceSubSurfaceAbove(Surface* sub_surface, Surface* reference); |
| void PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling); |
| void OnSubSurfaceCommit(); |
| |
| // This sets the surface viewport for scaling. |
| void SetViewport(const gfx::Size& 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 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 hide the shelf when fullscreen. If true, shelf is inaccessible |
| // (plain fullscreen). If false, shelf auto-hides and can be shown with a |
| // mouse gesture (immersive fullscreen). |
| void SetUseImmersiveForFullscreen(bool value); |
| |
| // 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(int32_t client_surface_id); |
| int32_t GetClientSurfaceId() const; |
| |
| // Enable embedding of an arbitrary viz surface in this exo surface. |
| // If the callback is valid, a SurfaceDrawQuad will be emitted targeting |
| // the returned SurfaceId each frame. |
| void SetEmbeddedSurfaceId( |
| base::RepeatingCallback<viz::SurfaceId()> surface_id_callback); |
| |
| // Set the size of the embedded surface, to allow proper scaling. |
| void SetEmbeddedSurfaceSize(const gfx::Size& size); |
| |
| // 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; |
| |
| // 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::Point& origin, |
| float device_scale_factor, |
| FrameSinkResourceManager* resource_manager, |
| 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; |
| |
| // 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::Size& 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_damage_.Contains(damage); |
| } |
| |
| // Set occlusion tracking region for surface. |
| void SetOcclusionTracking(bool tracking); |
| |
| // Triggers sending an occlusion update to observers. |
| void OnWindowOcclusionChanged(); |
| |
| // 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(); |
| |
| private: |
| struct State { |
| State(); |
| ~State(); |
| |
| bool operator==(const State& other) const; |
| bool operator!=(const State& other) const { return !(*this == other); } |
| |
| cc::Region opaque_region; |
| base::Optional<cc::Region> input_region; |
| int input_outset = 0; |
| float buffer_scale = 1.0f; |
| Transform buffer_transform = Transform::NORMAL; |
| gfx::Size 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; |
| bool is_tracking_occlusion = false; |
| }; |
| class BufferAttachment { |
| public: |
| BufferAttachment(); |
| ~BufferAttachment(); |
| |
| 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_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BufferAttachment); |
| }; |
| |
| friend class subtle::PropertyHelper; |
| |
| // 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); |
| |
| // Puts the current surface into a draw quad, and appends the draw quads into |
| // the |frame|. |
| void AppendContentsToFrame(const gfx::Point& origin, |
| 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 !current_buffer_.size().IsEmpty(); } |
| |
| // This window has the layer which contains the Surface contents. |
| std::unique_ptr<aura::Window> window_; |
| |
| // This true, if sub_surfaces_ has changes (order, position, etc). |
| bool sub_surfaces_changed_ = false; |
| |
| // This is the size of the last committed contents. |
| gfx::Size 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 take |
| // effect next time Commit() is called. |
| bool has_pending_contents_ = false; |
| |
| // The buffer that will become the content of surface when Commit() is called. |
| BufferAttachment pending_buffer_; |
| |
| // The damage region to schedule paint for when Commit() is called. |
| cc::Region pending_damage_; |
| |
| // The damage region which will be used by |
| // AppendSurfaceHierarchyContentsToFrame() to generate frame. |
| cc::Region damage_; |
| |
| // These lists contains the callbacks to notify the client when it is a good |
| // time to start producing a new frame. These callbacks move to |
| // |frame_callbacks_| when Commit() is called. Later they are moved to |
| // |active_frame_callbacks_| when the effect of the Commit() is scheduled to |
| // be drawn. They fire at the first begin frame notification after this. |
| std::list<FrameCallback> pending_frame_callbacks_; |
| std::list<FrameCallback> frame_callbacks_; |
| |
| // These lists contains the callbacks to notify the client when surface |
| // contents have been presented. These callbacks move to |
| // |presentation_callbacks_| when Commit() is called. Later they are moved to |
| // |swapping_presentation_callbacks_| when the effect of the Commit() is |
| // scheduled to be drawn and then moved to |swapped_presentation_callbacks_| |
| // after receiving VSync parameters update for the previous frame. They fire |
| // at the next VSync parameters update after that. |
| std::list<PresentationCallback> pending_presentation_callbacks_; |
| std::list<PresentationCallback> presentation_callbacks_; |
| |
| // This is the state that has yet to be committed. |
| State pending_state_; |
| |
| // This is the state that has been committed. |
| State 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. |
| using SubSurfaceEntry = std::pair<Surface*, gfx::Point>; |
| using SubSurfaceEntryList = std::list<SubSurfaceEntry>; |
| SubSurfaceEntryList pending_sub_surfaces_; |
| SubSurfaceEntryList sub_surfaces_; |
| |
| // The buffer that is currently set as content of surface. |
| BufferAttachment current_buffer_; |
| |
| // 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; |
| |
| // The acquire gpu fence to associate with the surface buffer when Commit() |
| // is called. |
| std::unique_ptr<gfx::GpuFence> pending_acquire_fence_; |
| // The acquire gpu fence that is currently associated with the surface buffer. |
| std::unique_ptr<gfx::GpuFence> acquire_fence_; |
| |
| // 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. |
| SurfaceDelegate* delegate_ = nullptr; |
| |
| // Surface observer list. Surface does not own the observers. |
| base::ObserverList<SurfaceObserver, true>::Unchecked observers_; |
| |
| #if defined(OS_CHROMEOS) |
| std::unique_ptr<ash::OutputProtectionDelegate> output_protection_; |
| #endif // defined(OS_CHROMEOS) |
| |
| viz::SurfaceId first_embedded_surface_id_; |
| viz::SurfaceId latest_embedded_surface_id_; |
| base::RepeatingCallback<viz::SurfaceId()> get_current_surface_id_; |
| |
| // The embedded surface is actually |embedded_surface_size_|. This is used |
| // for calculating clipping and scaling. |
| gfx::Size embedded_surface_size_; |
| |
| LeaveEnterCallback leave_enter_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Surface); |
| }; |
| |
| class ScopedSurface { |
| public: |
| ScopedSurface(Surface* surface, SurfaceObserver* observer); |
| ~ScopedSurface(); |
| Surface* get() { return surface_; } |
| |
| private: |
| Surface* const surface_; |
| SurfaceObserver* const observer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedSurface); |
| }; |
| |
| } // namespace exo |
| |
| #endif // COMPONENTS_EXO_SURFACE_H_ |