summaryrefslogtreecommitdiff
path: root/chromium/components/exo/surface.h
blob: 57893f139973aa102afabac288b8ddacfcef5e46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
// 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 base {
namespace trace_event {
class TracedValue;
}
}

namespace viz {
class CompositorFrame;
}

namespace exo {
class Buffer;
class LayerTreeFrameSinkHolder;
class SurfaceObserver;
class Surface;

namespace subtle {
class PropertyHelper;
}

// Counter-clockwise rotations.
enum class Transform { NORMAL, ROTATE_90, ROTATE_180, ROTATE_270 };

// 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);

  Surface();
  ~Surface();

  // Type-checking downcast routine.
  static Surface* AsSurface(const aura::Window* window);

  aura::Window* window() { return window_.get(); }

  // 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);

  // 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::Callback<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::Callback<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);

  // 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;

  // 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,
      LayerTreeFrameSinkHolder* frame_sink_holder,
      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();

 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;
  };
  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(LayerTreeFrameSinkHolder* frame_sink_holder);

  // 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;

  // 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_;

  // Whether this surface is tracking occlusion for the client.
  bool is_tracking_occlusion_ = false;

  DISALLOW_COPY_AND_ASSIGN(Surface);
};

}  // namespace exo

#endif  // COMPONENTS_EXO_SURFACE_H_