blob: 392ed45a41dc91e4ae09c2a9a9bb0cf8d490fef8 [file] [log] [blame]
revemanb195f41d2015-11-19 22:16:481// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/exo/surface.h"
6
dcheng27f7483f2015-12-29 22:26:567#include <utility>
8
Evan Stade4bfb3342019-01-30 21:43:599#include "ash/public/cpp/shell_window_ids.h"
revemanb195f41d2015-11-19 22:16:4810#include "base/callback_helpers.h"
Peng Huang583c9dc62017-07-27 23:38:2811#include "base/containers/adapters.h"
revemanb195f41d2015-11-19 22:16:4812#include "base/logging.h"
avibc5337b2015-12-25 23:16:3313#include "base/macros.h"
dcheng31759da2016-04-21 01:26:3114#include "base/memory/ptr_util.h"
revemanb195f41d2015-11-19 22:16:4815#include "base/trace_event/trace_event.h"
David 'Digit' Turnerea071142018-10-29 15:38:1216#include "base/trace_event/traced_value.h"
revemanb195f41d2015-11-19 22:16:4817#include "components/exo/buffer.h"
Albert Chaulk56e96582019-01-30 19:33:1818#include "components/exo/frame_sink_resource_manager.h"
[email protected]29befae2019-01-09 22:55:3519#include "components/exo/shell_surface_util.h"
revemanb195f41d2015-11-19 22:16:4820#include "components/exo/surface_delegate.h"
reveman27fe2642015-11-20 06:33:3921#include "components/exo/surface_observer.h"
Shawn Gallea61906012018-11-08 20:44:1622#include "components/exo/wm_helper.h"
danakje5805be2017-09-15 19:24:5523#include "components/viz/common/quads/render_pass.h"
Alex Zhangabad2292017-08-23 21:55:1924#include "components/viz/common/quads/shared_quad_state.h"
danakje5805be2017-09-15 19:24:5525#include "components/viz/common/quads/solid_color_draw_quad.h"
Albert Chaulkfd08f9842019-10-11 15:26:1426#include "components/viz/common/quads/surface_draw_quad.h"
danakje5805be2017-09-15 19:24:5527#include "components/viz/common/quads/texture_draw_quad.h"
danakjf20f4502017-09-26 17:13:3128#include "components/viz/common/resources/single_release_callback.h"
Fady Samuele4786072017-07-24 20:03:3829#include "components/viz/service/surfaces/surface.h"
30#include "components/viz/service/surfaces/surface_manager.h"
jbaumanbd9586a92016-05-28 01:09:0331#include "third_party/khronos/GLES2/gl2.h"
Raul Tambre038e96d2019-01-07 21:47:4432#include "third_party/skia/include/core/SkPath.h"
kaznacheev8e270592017-05-25 06:13:2633#include "ui/aura/client/aura_constants.h"
Daichi Hirono7a552012017-08-04 05:29:2834#include "ui/aura/client/drag_drop_delegate.h"
reveman4c94cf962015-12-03 06:49:4335#include "ui/aura/window_delegate.h"
Eliot Courtneybb051d12018-12-15 02:41:3136#include "ui/aura/window_occlusion_tracker.h"
reveman2966d7702016-02-12 02:09:5437#include "ui/aura/window_targeter.h"
kylixrd61e45cf2017-01-30 19:52:5338#include "ui/base/class_property.h"
reveman4c94cf962015-12-03 06:49:4339#include "ui/base/cursor/cursor.h"
40#include "ui/base/hit_test.h"
revemanb195f41d2015-11-19 22:16:4841#include "ui/compositor/layer.h"
reveman2966d7702016-02-12 02:09:5442#include "ui/events/event.h"
revemanb195f41d2015-11-19 22:16:4843#include "ui/gfx/buffer_format_util.h"
Peng Huang76f5fd02017-09-01 00:59:3944#include "ui/gfx/geometry/dip_util.h"
reveman8e323902016-05-23 21:55:3645#include "ui/gfx/geometry/safe_integer_conversions.h"
46#include "ui/gfx/geometry/size_conversions.h"
Alexandros Frantzis4ee9da52019-03-11 15:29:2347#include "ui/gfx/gpu_fence.h"
revemanb195f41d2015-11-19 22:16:4848#include "ui/gfx/gpu_memory_buffer.h"
Sadrul Habib Chowdhuryb62a97302018-06-06 03:33:4849#include "ui/gfx/presentation_feedback.h"
reveman7efa4b02016-01-06 08:29:5450#include "ui/gfx/transform_util.h"
kinaba70a30442016-03-31 04:09:5751#include "ui/views/widget/widget.h"
revemanb195f41d2015-11-19 22:16:4852
Ahmed Fakhryf929d5f2019-04-11 02:22:4853#if defined(OS_CHROMEOS)
Dominik Laskowski638b1632019-06-28 20:59:0254#include "ash/display/output_protection_delegate.h"
Ahmed Fakhryf929d5f2019-04-11 02:22:4855#include "ash/wm/desks/desks_util.h"
56#endif // defined(OS_CHROMEOS)
57
Nico Weber0f1ed9a2019-02-20 18:26:3058DEFINE_UI_CLASS_PROPERTY_TYPE(exo::Surface*)
reveman39b32c872015-12-08 05:34:0559
revemanb195f41d2015-11-19 22:16:4860namespace exo {
reveman27fe2642015-11-20 06:33:3961namespace {
62
reveman39b32c872015-12-08 05:34:0563// A property key containing the surface that is associated with
64// window. If unset, no surface is associated with window.
Nico Weber0f1ed9a2019-02-20 18:26:3065DEFINE_UI_CLASS_PROPERTY_KEY(Surface*, kSurfaceKey, nullptr)
reveman39b32c872015-12-08 05:34:0566
kaznacheev8e270592017-05-25 06:13:2667// A property key to store whether the surface should only consume
68// stylus input events.
Nico Weber0f1ed9a2019-02-20 18:26:3069DEFINE_UI_CLASS_PROPERTY_KEY(bool, kStylusOnlyKey, false)
kaznacheev8e270592017-05-25 06:13:2670
reveman27fe2642015-11-20 06:33:3971// Helper function that returns an iterator to the first entry in |list|
72// with |key|.
73template <typename T, typename U>
74typename T::iterator FindListEntry(T& list, U key) {
75 return std::find_if(list.begin(), list.end(),
76 [key](const typename T::value_type& entry) {
77 return entry.first == key;
78 });
79}
80
81// Helper function that returns true if |list| contains an entry with |key|.
82template <typename T, typename U>
83bool ListContainsEntry(T& list, U key) {
84 return FindListEntry(list, key) != list.end();
85}
86
revemanca132dc2017-01-31 22:35:5487// Helper function that returns true if |format| may have an alpha channel.
88// Note: False positives are allowed but false negatives are not.
89bool FormatHasAlpha(gfx::BufferFormat format) {
90 switch (format) {
91 case gfx::BufferFormat::BGR_565:
92 case gfx::BufferFormat::RGBX_8888:
93 case gfx::BufferFormat::BGRX_8888:
94 case gfx::BufferFormat::YVU_420:
95 case gfx::BufferFormat::YUV_420_BIPLANAR:
revemanca132dc2017-01-31 22:35:5496 return false;
97 default:
98 return true;
99 }
100}
101
David Revemanfca309b2017-08-24 18:18:11102// Helper function that returns |size| after adjusting for |transform|.
103gfx::Size ToTransformedSize(const gfx::Size& size, Transform transform) {
104 switch (transform) {
105 case Transform::NORMAL:
106 case Transform::ROTATE_180:
107 return size;
108 case Transform::ROTATE_90:
109 case Transform::ROTATE_270:
110 return gfx::Size(size.height(), size.width());
111 }
112
113 NOTREACHED();
114}
115
Ahmed Fakhryf929d5f2019-04-11 02:22:48116bool IsDeskContainer(aura::Window* container) {
117#if defined(OS_CHROMEOS)
118 return ash::desks_util::IsDeskContainer(container);
119#else
120 return container->id() == ash::kShellWindowId_DefaultContainerDeprecated;
121#endif // defined(OS_CHROMEOS)
122}
123
reveman2966d7702016-02-12 02:09:54124class CustomWindowDelegate : public aura::WindowDelegate {
reveman4c94cf962015-12-03 06:49:43125 public:
reveman2966d7702016-02-12 02:09:54126 explicit CustomWindowDelegate(Surface* surface) : surface_(surface) {}
127 ~CustomWindowDelegate() override {}
reveman4c94cf962015-12-03 06:49:43128
129 // Overridden from aura::WindowDelegate:
130 gfx::Size GetMinimumSize() const override { return gfx::Size(); }
131 gfx::Size GetMaximumSize() const override { return gfx::Size(); }
132 void OnBoundsChanged(const gfx::Rect& old_bounds,
133 const gfx::Rect& new_bounds) override {}
134 gfx::NativeCursor GetCursor(const gfx::Point& point) override {
Mitsuru Oshima46d38702018-03-10 06:21:15135 views::Widget* widget =
136 views::Widget::GetTopLevelWidgetForNativeView(surface_->window());
137 if (widget)
138 return widget->GetNativeWindow()->GetCursor(point /* not used */);
139 return ui::CursorType::kNull;
reveman4c94cf962015-12-03 06:49:43140 }
141 int GetNonClientComponent(const gfx::Point& point) const override {
Evan Stade4bfb3342019-01-30 21:43:59142 views::Widget* widget =
143 views::Widget::GetTopLevelWidgetForNativeView(surface_->window());
Ahmed Fakhryf929d5f2019-04-11 02:22:48144 if (widget && IsDeskContainer(widget->GetNativeView()->parent()) &&
Evan Stade4bfb3342019-01-30 21:43:59145 surface_->HitTest(point)) {
146 return HTCLIENT;
147 }
148
reveman4c94cf962015-12-03 06:49:43149 return HTNOWHERE;
150 }
151 bool ShouldDescendIntoChildForEventHandling(
152 aura::Window* child,
153 const gfx::Point& location) override {
revemanf999944b2016-01-28 00:12:06154 return true;
reveman4c94cf962015-12-03 06:49:43155 }
156 bool CanFocus() override { return true; }
157 void OnCaptureLost() override {}
158 void OnPaint(const ui::PaintContext& context) override {}
Scott Violet06aff2b42017-09-08 00:26:32159 void OnDeviceScaleFactorChanged(float old_device_scale_factor,
160 float new_device_scale_factor) override {}
reveman4c94cf962015-12-03 06:49:43161 void OnWindowDestroying(aura::Window* window) override {}
162 void OnWindowDestroyed(aura::Window* window) override { delete this; }
163 void OnWindowTargetVisibilityChanged(bool visible) override {}
Eliot Courtneybb051d12018-12-15 02:41:31164 void OnWindowOcclusionChanged(aura::Window::OcclusionState occlusion_state,
165 const SkRegion& occluded_region) override {
166 surface_->OnWindowOcclusionChanged();
167 }
Dominik Laskowski57064702017-11-30 10:31:41168 bool HasHitTestMask() const override { return true; }
Raul Tambre038e96d2019-01-07 21:47:44169 void GetHitTestMask(SkPath* mask) const override {
reveman2966d7702016-02-12 02:09:54170 surface_->GetHitTestMask(mask);
171 }
kinaba70a30442016-03-31 04:09:57172 void OnKeyEvent(ui::KeyEvent* event) override {
173 // Propagates the key event upto the top-level views Widget so that we can
174 // trigger proper events in the views/ash level there. Event handling for
175 // Surfaces is done in a post event handler in keyboard.cc.
176 views::Widget* widget =
jbaumane3526252016-06-09 18:43:05177 views::Widget::GetTopLevelWidgetForNativeView(surface_->window());
kinaba70a30442016-03-31 04:09:57178 if (widget)
179 widget->OnKeyEvent(event);
180 }
reveman4c94cf962015-12-03 06:49:43181
182 private:
reveman2966d7702016-02-12 02:09:54183 Surface* const surface_;
184
185 DISALLOW_COPY_AND_ASSIGN(CustomWindowDelegate);
186};
187
188class CustomWindowTargeter : public aura::WindowTargeter {
189 public:
190 CustomWindowTargeter() {}
191 ~CustomWindowTargeter() override {}
192
193 // Overridden from aura::WindowTargeter:
194 bool EventLocationInsideBounds(aura::Window* window,
195 const ui::LocatedEvent& event) const override {
196 Surface* surface = Surface::AsSurface(window);
Dominik Laskowski14a163772018-02-09 19:25:18197 if (!surface || !surface->IsInputEnabled(surface))
Dominik Laskowski3e2f94792017-12-15 00:27:10198 return false;
199
reveman2966d7702016-02-12 02:09:54200 gfx::Point local_point = event.location();
201 if (window->parent())
202 aura::Window::ConvertPointToTarget(window->parent(), window,
203 &local_point);
Dominik Laskowski57064702017-11-30 10:31:41204 return surface->HitTest(local_point);
reveman2966d7702016-02-12 02:09:54205 }
206
207 private:
208 DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter);
reveman4c94cf962015-12-03 06:49:43209};
210
[email protected]29befae2019-01-09 22:55:35211const std::string& GetApplicationId(aura::Window* window) {
212 static const std::string empty_app_id;
213 if (!window)
214 return empty_app_id;
215 while (window) {
216 const std::string* app_id = exo::GetShellApplicationId(window);
217 if (app_id)
218 return *app_id;
219 window = window->parent();
220 }
221 return empty_app_id;
222}
223
reveman27fe2642015-11-20 06:33:39224} // namespace
revemanb195f41d2015-11-19 22:16:48225
Ryo Hashimoto4e7c572f2019-04-18 05:55:56226DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kClientSurfaceIdKey, 0)
227
Fergus Dalla4293852019-07-26 07:13:47228ScopedSurface::ScopedSurface(Surface* surface, SurfaceObserver* observer)
229 : surface_(surface), observer_(observer) {
230 surface_->AddSurfaceObserver(observer_);
231}
232
233ScopedSurface::~ScopedSurface() {
234 surface_->RemoveSurfaceObserver(observer_);
235}
236
reveman2d3815d2016-06-26 20:13:25237////////////////////////////////////////////////////////////////////////////////
revemanb195f41d2015-11-19 22:16:48238// Surface, public:
239
Scott Violet13de50d2018-08-10 20:07:11240Surface::Surface()
Jun Mukai1f426ff2019-05-16 18:19:24241 : window_(
242 std::make_unique<aura::Window>(new CustomWindowDelegate(this),
243 aura::client::WINDOW_TYPE_CONTROL)) {
jbaumane3526252016-06-09 18:43:05244 window_->SetName("ExoSurface");
245 window_->SetProperty(kSurfaceKey, this);
Peng Huang583c9dc62017-07-27 23:38:28246 window_->Init(ui::LAYER_NOT_DRAWN);
Scott Violetec3b3b682018-08-30 20:06:30247 window_->SetEventTargeter(std::make_unique<CustomWindowTargeter>());
jbaumane3526252016-06-09 18:43:05248 window_->set_owned_by_parent(false);
Daichi Hirono7a552012017-08-04 05:29:28249 WMHelper::GetInstance()->SetDragDropDelegate(window_.get());
revemanb195f41d2015-11-19 22:16:48250}
revemanb195f41d2015-11-19 22:16:48251Surface::~Surface() {
ericwilligersa22488d42016-10-25 01:20:57252 for (SurfaceObserver& observer : observers_)
253 observer.OnSurfaceDestroying(this);
revemanb195f41d2015-11-19 22:16:48254
reveman211cf802017-01-10 00:30:59255 // Call all frame callbacks with a null frame time to indicate that they
256 // have been cancelled.
David Revemanef1cb082017-11-09 21:14:40257 frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
258 for (const auto& frame_callback : frame_callbacks_)
reveman211cf802017-01-10 00:30:59259 frame_callback.Run(base::TimeTicks());
260
reveman211cf802017-01-10 00:30:59261 // Call all presentation callbacks with a null presentation time to indicate
262 // that they have been cancelled.
David Revemanef1cb082017-11-09 21:14:40263 presentation_callbacks_.splice(presentation_callbacks_.end(),
264 pending_presentation_callbacks_);
265 for (const auto& presentation_callback : presentation_callbacks_)
Sadrul Habib Chowdhuryb62a97302018-06-06 03:33:48266 presentation_callback.Run(gfx::PresentationFeedback());
Daichi Hirono7a552012017-08-04 05:29:28267
268 WMHelper::GetInstance()->ResetDragDropDelegate(window_.get());
revemanb195f41d2015-11-19 22:16:48269}
270
reveman39b32c872015-12-08 05:34:05271// static
kinabad14ca03e2016-02-23 04:43:35272Surface* Surface::AsSurface(const aura::Window* window) {
reveman39b32c872015-12-08 05:34:05273 return window->GetProperty(kSurfaceKey);
274}
275
revemanb195f41d2015-11-19 22:16:48276void Surface::Attach(Buffer* buffer) {
Fergus Dalla4293852019-07-26 07:13:47277 Attach(buffer, gfx::Vector2d());
278}
279
280void Surface::Attach(Buffer* buffer, gfx::Vector2d offset) {
[email protected]29befae2019-01-09 22:55:35281 TRACE_EVENT2("exo", "Surface::Attach", "buffer_id",
282 buffer ? buffer->gfx_buffer() : nullptr, "app_id",
283 GetApplicationId(window_.get()));
revemanced21f82015-11-24 00:42:49284 has_pending_contents_ = true;
jbauman45c06862016-06-23 19:35:02285 pending_buffer_.Reset(buffer ? buffer->AsWeakPtr() : base::WeakPtr<Buffer>());
Fergus Dalla4293852019-07-26 07:13:47286 pending_state_.offset = offset;
287}
288
289gfx::Vector2d Surface::GetBufferOffset() {
290 return state_.offset;
revemanb195f41d2015-11-19 22:16:48291}
292
Alexandros Frantzis4ee9da52019-03-11 15:29:23293bool Surface::HasPendingAttachedBuffer() const {
294 return pending_buffer_.buffer() != nullptr;
295}
296
revemanb195f41d2015-11-19 22:16:48297void Surface::Damage(const gfx::Rect& damage) {
298 TRACE_EVENT1("exo", "Surface::Damage", "damage", damage.ToString());
299
Dominik Laskowski0dcf91352017-11-29 19:21:35300 pending_damage_.Union(damage);
revemanb195f41d2015-11-19 22:16:48301}
302
303void Surface::RequestFrameCallback(const FrameCallback& callback) {
304 TRACE_EVENT0("exo", "Surface::RequestFrameCallback");
305
306 pending_frame_callbacks_.push_back(callback);
307}
308
reveman211cf802017-01-10 00:30:59309void Surface::RequestPresentationCallback(
310 const PresentationCallback& callback) {
311 TRACE_EVENT0("exo", "Surface::RequestPresentationCallback");
312
313 pending_presentation_callbacks_.push_back(callback);
314}
315
Dominik Laskowski0dcf91352017-11-29 19:21:35316void Surface::SetOpaqueRegion(const cc::Region& region) {
317 TRACE_EVENT1("exo", "Surface::SetOpaqueRegion", "region", region.ToString());
revemanb195f41d2015-11-19 22:16:48318
jbaumanf4c3f292016-06-11 00:57:33319 pending_state_.opaque_region = region;
revemanb195f41d2015-11-19 22:16:48320}
321
Dominik Laskowski0dcf91352017-11-29 19:21:35322void Surface::SetInputRegion(const cc::Region& region) {
323 TRACE_EVENT1("exo", "Surface::SetInputRegion", "region", region.ToString());
reveman2966d7702016-02-12 02:09:54324
jbaumanf4c3f292016-06-11 00:57:33325 pending_state_.input_region = region;
reveman2966d7702016-02-12 02:09:54326}
327
Mike Reed2c570fa2018-01-11 21:59:22328void Surface::ResetInputRegion() {
329 TRACE_EVENT0("exo", "Surface::ResetInputRegion");
330
331 pending_state_.input_region = base::nullopt;
332}
333
Dominik Laskowski2d4316412017-12-13 19:14:44334void Surface::SetInputOutset(int outset) {
335 TRACE_EVENT1("exo", "Surface::SetInputOutset", "outset", outset);
336
337 pending_state_.input_outset = outset;
338}
339
reveman7efa4b02016-01-06 08:29:54340void Surface::SetBufferScale(float scale) {
341 TRACE_EVENT1("exo", "Surface::SetBufferScale", "scale", scale);
342
jbaumanf4c3f292016-06-11 00:57:33343 pending_state_.buffer_scale = scale;
reveman7efa4b02016-01-06 08:29:54344}
345
David Revemanfca309b2017-08-24 18:18:11346void Surface::SetBufferTransform(Transform transform) {
347 TRACE_EVENT1("exo", "Surface::SetBufferTransform", "transform",
348 static_cast<int>(transform));
349
350 pending_state_.buffer_transform = transform;
351}
352
reveman27fe2642015-11-20 06:33:39353void Surface::AddSubSurface(Surface* sub_surface) {
354 TRACE_EVENT1("exo", "Surface::AddSubSurface", "sub_surface",
355 sub_surface->AsTracedValue());
356
jbaumane3526252016-06-09 18:43:05357 DCHECK(!sub_surface->window()->parent());
Peng Huang583c9dc62017-07-27 23:38:28358 sub_surface->window()->SetBounds(
359 gfx::Rect(sub_surface->window()->bounds().size()));
jbaumane3526252016-06-09 18:43:05360 window_->AddChild(sub_surface->window());
reveman27fe2642015-11-20 06:33:39361
362 DCHECK(!ListContainsEntry(pending_sub_surfaces_, sub_surface));
363 pending_sub_surfaces_.push_back(std::make_pair(sub_surface, gfx::Point()));
Peng Huang583c9dc62017-07-27 23:38:28364 sub_surfaces_.push_back(std::make_pair(sub_surface, gfx::Point()));
Peng Huangf925ebf2017-10-31 15:37:50365 sub_surfaces_changed_ = true;
reveman27fe2642015-11-20 06:33:39366}
367
368void Surface::RemoveSubSurface(Surface* sub_surface) {
yoshikia56c53c2016-11-19 07:07:56369 TRACE_EVENT1("exo", "Surface::RemoveSubSurface", "sub_surface",
reveman27fe2642015-11-20 06:33:39370 sub_surface->AsTracedValue());
371
jbaumane3526252016-06-09 18:43:05372 if (sub_surface->window()->IsVisible())
373 sub_surface->window()->Hide();
Eliot Courtneyb5a8f332019-09-10 08:25:26374 window_->RemoveChild(sub_surface->window());
reveman27fe2642015-11-20 06:33:39375
376 DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
377 pending_sub_surfaces_.erase(
378 FindListEntry(pending_sub_surfaces_, sub_surface));
Eliot Courtney28e7aa52017-09-27 02:16:21379
Peng Huang583c9dc62017-07-27 23:38:28380 DCHECK(ListContainsEntry(sub_surfaces_, sub_surface));
Eliot Courtney28e7aa52017-09-27 02:16:21381 auto it = FindListEntry(sub_surfaces_, sub_surface);
Eliot Courtney28e7aa52017-09-27 02:16:21382 sub_surfaces_.erase(it);
Peng Huangc51f7aba2017-09-05 16:00:39383 // Force recreating resources when the surface is added to a tree again.
384 sub_surface->SurfaceHierarchyResourcesLost();
Peng Huangf925ebf2017-10-31 15:37:50385 sub_surfaces_changed_ = true;
reveman27fe2642015-11-20 06:33:39386}
387
388void Surface::SetSubSurfacePosition(Surface* sub_surface,
389 const gfx::Point& position) {
390 TRACE_EVENT2("exo", "Surface::SetSubSurfacePosition", "sub_surface",
391 sub_surface->AsTracedValue(), "position", position.ToString());
392
393 auto it = FindListEntry(pending_sub_surfaces_, sub_surface);
394 DCHECK(it != pending_sub_surfaces_.end());
jbaumanf4c3f292016-06-11 00:57:33395 if (it->second == position)
396 return;
reveman27fe2642015-11-20 06:33:39397 it->second = position;
Peng Huang583c9dc62017-07-27 23:38:28398 sub_surfaces_changed_ = true;
reveman27fe2642015-11-20 06:33:39399}
400
401void Surface::PlaceSubSurfaceAbove(Surface* sub_surface, Surface* reference) {
402 TRACE_EVENT2("exo", "Surface::PlaceSubSurfaceAbove", "sub_surface",
403 sub_surface->AsTracedValue(), "reference",
404 reference->AsTracedValue());
405
406 if (sub_surface == reference) {
407 DLOG(WARNING) << "Client tried to place sub-surface above itself";
408 return;
409 }
410
411 auto position_it = pending_sub_surfaces_.begin();
412 if (reference != this) {
413 position_it = FindListEntry(pending_sub_surfaces_, reference);
414 if (position_it == pending_sub_surfaces_.end()) {
415 DLOG(WARNING) << "Client tried to place sub-surface above a reference "
416 "surface that is neither a parent nor a sibling";
417 return;
418 }
419
420 // Advance iterator to have |position_it| point to the sibling surface
421 // above |reference|.
422 ++position_it;
423 }
424
425 DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
jbaumanf4c3f292016-06-11 00:57:33426 auto it = FindListEntry(pending_sub_surfaces_, sub_surface);
427 if (it == position_it)
428 return;
429 pending_sub_surfaces_.splice(position_it, pending_sub_surfaces_, it);
Peng Huang583c9dc62017-07-27 23:38:28430 sub_surfaces_changed_ = true;
reveman27fe2642015-11-20 06:33:39431}
432
433void Surface::PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling) {
434 TRACE_EVENT2("exo", "Surface::PlaceSubSurfaceBelow", "sub_surface",
435 sub_surface->AsTracedValue(), "sibling",
436 sibling->AsTracedValue());
437
438 if (sub_surface == sibling) {
439 DLOG(WARNING) << "Client tried to place sub-surface below itself";
440 return;
441 }
442
443 auto sibling_it = FindListEntry(pending_sub_surfaces_, sibling);
444 if (sibling_it == pending_sub_surfaces_.end()) {
445 DLOG(WARNING) << "Client tried to place sub-surface below a surface that "
446 "is not a sibling";
447 return;
448 }
449
450 DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
jbaumanf4c3f292016-06-11 00:57:33451 auto it = FindListEntry(pending_sub_surfaces_, sub_surface);
452 if (it == sibling_it)
453 return;
454 pending_sub_surfaces_.splice(sibling_it, pending_sub_surfaces_, it);
Peng Huang583c9dc62017-07-27 23:38:28455 sub_surfaces_changed_ = true;
reveman27fe2642015-11-20 06:33:39456}
457
David Reveman8b43b352017-11-03 15:24:51458void Surface::OnSubSurfaceCommit() {
459 if (delegate_)
460 delegate_->OnSurfaceCommit();
461}
462
reveman642d8c332016-02-19 19:55:44463void Surface::SetViewport(const gfx::Size& viewport) {
464 TRACE_EVENT1("exo", "Surface::SetViewport", "viewport", viewport.ToString());
465
jbaumanf4c3f292016-06-11 00:57:33466 pending_state_.viewport = viewport;
reveman642d8c332016-02-19 19:55:44467}
468
reveman8e323902016-05-23 21:55:36469void Surface::SetCrop(const gfx::RectF& crop) {
470 TRACE_EVENT1("exo", "Surface::SetCrop", "crop", crop.ToString());
471
jbaumanf4c3f292016-06-11 00:57:33472 pending_state_.crop = crop;
reveman8e323902016-05-23 21:55:36473}
474
reveman85b7a562016-03-17 23:27:32475void Surface::SetOnlyVisibleOnSecureOutput(bool only_visible_on_secure_output) {
476 TRACE_EVENT1("exo", "Surface::SetOnlyVisibleOnSecureOutput",
477 "only_visible_on_secure_output", only_visible_on_secure_output);
478
jbaumanf4c3f292016-06-11 00:57:33479 pending_state_.only_visible_on_secure_output = only_visible_on_secure_output;
reveman85b7a562016-03-17 23:27:32480}
481
reedcc9c70f2016-11-22 04:26:01482void Surface::SetBlendMode(SkBlendMode blend_mode) {
483 TRACE_EVENT1("exo", "Surface::SetBlendMode", "blend_mode",
484 static_cast<int>(blend_mode));
revemanfca687e2016-05-10 21:44:48485
jbaumanf4c3f292016-06-11 00:57:33486 pending_state_.blend_mode = blend_mode;
revemanfca687e2016-05-10 21:44:48487}
488
489void Surface::SetAlpha(float alpha) {
490 TRACE_EVENT1("exo", "Surface::SetAlpha", "alpha", alpha);
491
jbaumanf4c3f292016-06-11 00:57:33492 pending_state_.alpha = alpha;
revemanfca687e2016-05-10 21:44:48493}
494
David Reveman93f67c02017-09-06 03:23:08495void Surface::SetFrame(SurfaceFrameType type) {
496 TRACE_EVENT1("exo", "Surface::SetFrame", "type", static_cast<uint32_t>(type));
497
498 if (delegate_)
499 delegate_->OnSetFrame(type);
500}
501
David Reveman786d3182017-12-20 22:04:33502void Surface::SetFrameColors(SkColor active_color, SkColor inactive_color) {
503 TRACE_EVENT2("exo", "Surface::SetFrameColors", "active_color", active_color,
504 "inactive_color", inactive_color);
505
506 if (delegate_)
507 delegate_->OnSetFrameColors(active_color, inactive_color);
508}
509
Tim Zheng08df5662018-04-04 05:08:15510void Surface::SetStartupId(const char* startup_id) {
511 TRACE_EVENT1("exo", "Surface::SetStartupId", "startup_id", startup_id);
512
513 if (delegate_)
514 delegate_->OnSetStartupId(startup_id);
515}
516
David Reveman21e2236d2018-04-12 06:01:10517void Surface::SetApplicationId(const char* application_id) {
518 TRACE_EVENT1("exo", "Surface::SetApplicationId", "application_id",
519 application_id);
520
521 if (delegate_)
522 delegate_->OnSetApplicationId(application_id);
523}
524
David Reveman32715092017-12-05 18:24:11525void Surface::SetParent(Surface* parent, const gfx::Point& position) {
526 TRACE_EVENT2("exo", "Surface::SetParent", "parent", !!parent, "position",
527 position.ToString());
528
529 if (delegate_)
530 delegate_->OnSetParent(parent, position);
531}
532
Ryo Hashimoto8f10c882018-11-28 17:43:52533void Surface::SetClientSurfaceId(int32_t client_surface_id) {
534 if (client_surface_id)
535 window_->SetProperty(kClientSurfaceIdKey, client_surface_id);
536 else
537 window_->ClearProperty(kClientSurfaceIdKey);
538}
539
540int32_t Surface::GetClientSurfaceId() const {
541 return window_->GetProperty(kClientSurfaceIdKey);
542}
543
Albert Chaulkfd08f9842019-10-11 15:26:14544void Surface::SetEmbeddedSurfaceId(
545 base::RepeatingCallback<viz::SurfaceId()> surface_id_callback) {
546 get_current_surface_id_ = std::move(surface_id_callback);
547 first_embedded_surface_id_ = viz::SurfaceId();
548}
549
Alexandros Frantzis4ee9da52019-03-11 15:29:23550void Surface::SetAcquireFence(std::unique_ptr<gfx::GpuFence> gpu_fence) {
551 TRACE_EVENT1("exo", "Surface::SetAcquireFence", "fence_fd",
552 gpu_fence ? gpu_fence->GetGpuFenceHandle().native_fd.fd : -1);
553
554 pending_acquire_fence_ = std::move(gpu_fence);
555}
556
557bool Surface::HasPendingAcquireFence() const {
558 return !!pending_acquire_fence_;
559}
560
revemanb195f41d2015-11-19 22:16:48561void Surface::Commit() {
[email protected]822d6aef2019-11-01 22:22:01562 TRACE_EVENT1("exo", "Surface::Commit", "buffer_id",
563 pending_buffer_.buffer() ? pending_buffer_.buffer()->gfx_buffer()
564 : nullptr);
revemanb195f41d2015-11-19 22:16:48565
[email protected]1b37dd462019-07-17 18:20:59566 for (auto& observer : observers_)
567 observer.OnCommit(this);
[email protected]009a15e2019-03-22 23:43:43568
Peng Huang76f5fd02017-09-01 00:59:39569 needs_commit_surface_ = true;
Peng Huang583c9dc62017-07-27 23:38:28570 if (delegate_)
revemanb195f41d2015-11-19 22:16:48571 delegate_->OnSurfaceCommit();
David Reveman7a126ba2017-11-09 17:17:41572 else
David Revemanef1cb082017-11-09 21:14:40573 CommitSurfaceHierarchy(false);
reveman27fe2642015-11-20 06:33:39574}
575
David Revemanef1cb082017-11-09 21:14:40576void Surface::CommitSurfaceHierarchy(bool synchronized) {
[email protected]29befae2019-01-09 22:55:35577 TRACE_EVENT0("exo", "Surface::CommitSurfaceHierarchy");
David Reveman8b43b352017-11-03 15:24:51578 if (needs_commit_surface_ && (synchronized || !IsSynchronized())) {
Peng Huang76f5fd02017-09-01 00:59:39579 needs_commit_surface_ = false;
David Reveman8b43b352017-11-03 15:24:51580 synchronized = true;
Lloyd Piqued1e23fd2017-08-15 23:10:51581
Peng Huangf925ebf2017-10-31 15:37:50582 // TODO(penghuang): Make the damage more precise for sub surface changes.
583 // https://crbug.com/779704
Peng Huang76f5fd02017-09-01 00:59:39584 bool needs_full_damage =
Peng Huangf925ebf2017-10-31 15:37:50585 sub_surfaces_changed_ ||
Peng Huang76f5fd02017-09-01 00:59:39586 pending_state_.opaque_region != state_.opaque_region ||
Lloyd Piqued1e23fd2017-08-15 23:10:51587 pending_state_.buffer_scale != state_.buffer_scale ||
David Revemanfca309b2017-08-24 18:18:11588 pending_state_.buffer_transform != state_.buffer_transform ||
Lloyd Piqued1e23fd2017-08-15 23:10:51589 pending_state_.viewport != state_.viewport ||
590 pending_state_.crop != state_.crop ||
591 pending_state_.only_visible_on_secure_output !=
592 state_.only_visible_on_secure_output ||
593 pending_state_.blend_mode != state_.blend_mode ||
Peng Huang76f5fd02017-09-01 00:59:39594 pending_state_.alpha != state_.alpha;
Lloyd Piqued1e23fd2017-08-15 23:10:51595
Lloyd Pique0a3045f2017-09-15 23:34:12596 bool needs_update_buffer_transform =
597 pending_state_.buffer_scale != state_.buffer_scale ||
598 pending_state_.buffer_transform != state_.buffer_transform;
599
Dominik Laskowski638b1632019-06-28 20:59:02600#if defined(OS_CHROMEOS)
601 bool needs_output_protection =
602 pending_state_.only_visible_on_secure_output !=
603 state_.only_visible_on_secure_output;
604#endif // defined(OS_CHROMEOS)
605
Zach Reizner8bcce6e2018-10-31 00:04:37606 bool pending_invert_y = false;
607
Peng Huanga72f3a92017-10-05 00:32:27608 // If the current state is fully transparent, the last submitted frame will
609 // not include the TextureDrawQuad for the resource, so the resource might
610 // have been released and needs to be updated again.
611 if (!state_.alpha && pending_state_.alpha)
612 needs_update_resource_ = true;
613
Peng Huang583c9dc62017-07-27 23:38:28614 state_ = pending_state_;
615 pending_state_.only_visible_on_secure_output = false;
revemanbf33b942016-06-07 00:22:34616
Peng Huang45e581ff2017-09-14 22:46:42617 window_->SetEventTargetingPolicy(
Mike Reed2c570fa2018-01-11 21:59:22618 (state_.input_region.has_value() && state_.input_region->IsEmpty())
Scott Violet827d23b2019-05-24 16:12:49619 ? aura::EventTargetingPolicy::kDescendantsOnly
620 : aura::EventTargetingPolicy::kTargetAndDescendants);
Peng Huang45e581ff2017-09-14 22:46:42621
Dominik Laskowski638b1632019-06-28 20:59:02622#if defined(OS_CHROMEOS)
623 if (needs_output_protection) {
624 if (!output_protection_) {
625 output_protection_ =
626 std::make_unique<ash::OutputProtectionDelegate>(window_.get());
627 }
628
629 uint32_t protection_mask = state_.only_visible_on_secure_output
630 ? display::CONTENT_PROTECTION_METHOD_HDCP
631 : display::CONTENT_PROTECTION_METHOD_NONE;
632
633 output_protection_->SetProtection(protection_mask, base::DoNothing());
634 }
635#endif // defined(OS_CHROMEOS)
636
Peng Huang583c9dc62017-07-27 23:38:28637 // We update contents if Attach() has been called since last commit.
638 if (has_pending_contents_) {
639 has_pending_contents_ = false;
Zach Reizner8bcce6e2018-10-31 00:04:37640
641 bool current_invert_y =
642 current_buffer_.buffer() && current_buffer_.buffer()->y_invert();
643 pending_invert_y =
644 pending_buffer_.buffer() && pending_buffer_.buffer()->y_invert();
645 if (current_invert_y != pending_invert_y)
646 needs_update_buffer_transform = true;
647
Peng Huang583c9dc62017-07-27 23:38:28648 current_buffer_ = std::move(pending_buffer_);
Alexandros Frantzis4ee9da52019-03-11 15:29:23649 acquire_fence_ = std::move(pending_acquire_fence_);
Peng Huanga72f3a92017-10-05 00:32:27650 if (state_.alpha)
651 needs_update_resource_ = true;
Peng Huang583c9dc62017-07-27 23:38:28652 }
Alexandros Frantzis4ee9da52019-03-11 15:29:23653 // Either we didn't have a pending acquire fence, or we had one along with
654 // a new buffer, and it was already moved to acquire_fence_. Note that
655 // it is a commit-time client error to commit a fence without a buffer.
656 DCHECK(!pending_acquire_fence_);
Peng Huang583c9dc62017-07-27 23:38:28657
Lloyd Pique0a3045f2017-09-15 23:34:12658 if (needs_update_buffer_transform)
Zach Reizner8bcce6e2018-10-31 00:04:37659 UpdateBufferTransform(pending_invert_y);
Lloyd Pique0a3045f2017-09-15 23:34:12660
David Revemanef1cb082017-11-09 21:14:40661 // Move pending frame callbacks to the end of |frame_callbacks_|.
662 frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
Peng Huang583c9dc62017-07-27 23:38:28663
David Revemanef1cb082017-11-09 21:14:40664 // Move pending presentation callbacks to the end of
665 // |presentation_callbacks_|.
666 presentation_callbacks_.splice(presentation_callbacks_.end(),
667 pending_presentation_callbacks_);
Peng Huang583c9dc62017-07-27 23:38:28668
669 UpdateContentSize();
670
671 // Synchronize window hierarchy. This will position and update the stacking
672 // order of all sub-surfaces after committing all pending state of
673 // sub-surface descendants.
674 if (sub_surfaces_changed_) {
675 sub_surfaces_.clear();
676 aura::Window* stacking_target = nullptr;
677 for (const auto& sub_surface_entry : pending_sub_surfaces_) {
678 Surface* sub_surface = sub_surface_entry.first;
679 sub_surfaces_.push_back(sub_surface_entry);
680 // Move sub-surface to its new position in the stack.
681 if (stacking_target)
682 window_->StackChildAbove(sub_surface->window(), stacking_target);
683
684 // Stack next sub-surface above this sub-surface.
685 stacking_target = sub_surface->window();
686
687 // Update sub-surface position relative to surface origin.
688 sub_surface->window()->SetBounds(gfx::Rect(
689 sub_surface_entry.second, sub_surface->window()->bounds().size()));
690 }
691 sub_surfaces_changed_ = false;
692 }
Peng Huang76f5fd02017-09-01 00:59:39693
Dominik Laskowski0dcf91352017-11-29 19:21:35694 gfx::Rect output_rect(content_size_);
Peng Huang76f5fd02017-09-01 00:59:39695 if (needs_full_damage) {
Dominik Laskowski0dcf91352017-11-29 19:21:35696 damage_ = output_rect;
Peng Huang76f5fd02017-09-01 00:59:39697 } else {
698 // pending_damage_ is in Surface coordinates.
Dominik Laskowski0dcf91352017-11-29 19:21:35699 damage_.Swap(&pending_damage_);
700 damage_.Intersect(output_rect);
Peng Huang76f5fd02017-09-01 00:59:39701 }
Dominik Laskowski0dcf91352017-11-29 19:21:35702 pending_damage_.Clear();
revemanaabfd712016-05-13 01:40:20703 }
jbauman2fdc0732016-06-07 00:55:36704
David Reveman7a126ba2017-11-09 17:17:41705 surface_hierarchy_content_bounds_ = gfx::Rect(content_size_);
Mike Reed2c570fa2018-01-11 21:59:22706 if (state_.input_region) {
707 hit_test_region_ = *state_.input_region;
708 hit_test_region_.Intersect(surface_hierarchy_content_bounds_);
Lei Zhang1c9963ba2018-05-15 04:50:21709 } else {
Mike Reed2c570fa2018-01-11 21:59:22710 hit_test_region_ = surface_hierarchy_content_bounds_;
Lei Zhang1c9963ba2018-05-15 04:50:21711 }
Dominik Laskowski2af53e72017-10-03 00:16:37712
Dominik Laskowski2d4316412017-12-13 19:14:44713 int outset = state_.input_outset;
714 if (outset > 0) {
715 gfx::Rect input_rect = surface_hierarchy_content_bounds_;
716 input_rect.Inset(-outset, -outset);
717 hit_test_region_ = input_rect;
718 }
719
Peng Huang583c9dc62017-07-27 23:38:28720 for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
721 auto* sub_surface = sub_surface_entry.first;
Dominik Laskowski57064702017-11-30 10:31:41722 gfx::Vector2d offset = sub_surface_entry.second.OffsetFromOrigin();
Dominik Laskowski2af53e72017-10-03 00:16:37723 // Synchronously commit all pending state of the sub-surface and its
724 // descendants.
David Revemanef1cb082017-11-09 21:14:40725 sub_surface->CommitSurfaceHierarchy(synchronized);
David Reveman7a126ba2017-11-09 17:17:41726 surface_hierarchy_content_bounds_.Union(
Dominik Laskowski57064702017-11-30 10:31:41727 sub_surface->surface_hierarchy_content_bounds() + offset);
728 hit_test_region_.Union(sub_surface->hit_test_region_ + offset);
Peng Huang76f5fd02017-09-01 00:59:39729 }
730}
731
David Revemanef1cb082017-11-09 21:14:40732void Surface::AppendSurfaceHierarchyCallbacks(
733 std::list<FrameCallback>* frame_callbacks,
734 std::list<PresentationCallback>* presentation_callbacks) {
735 // Move frame callbacks to the end of |frame_callbacks|.
736 frame_callbacks->splice(frame_callbacks->end(), frame_callbacks_);
737 // Move presentation callbacks to the end of |presentation_callbacks|.
738 presentation_callbacks->splice(presentation_callbacks->end(),
739 presentation_callbacks_);
740
741 for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
742 auto* sub_surface = sub_surface_entry.first;
743 sub_surface->AppendSurfaceHierarchyCallbacks(frame_callbacks,
744 presentation_callbacks);
745 }
746}
747
Peng Huang76f5fd02017-09-01 00:59:39748void Surface::AppendSurfaceHierarchyContentsToFrame(
749 const gfx::Point& origin,
750 float device_scale_factor,
Albert Chaulk56e96582019-01-30 19:33:18751 FrameSinkResourceManager* resource_manager,
danakj5e0a12b2017-09-25 17:26:49752 viz::CompositorFrame* frame) {
Peng Huang76f5fd02017-09-01 00:59:39753 // The top most sub-surface is at the front of the RenderPass's quad_list,
754 // so we need composite sub-surface in reversed order.
755 for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
756 auto* sub_surface = sub_surface_entry.first;
757 // Synchronsouly commit all pending state of the sub-surface and its
758 // decendents.
759 sub_surface->AppendSurfaceHierarchyContentsToFrame(
760 origin + sub_surface_entry.second.OffsetFromOrigin(),
Albert Chaulk56e96582019-01-30 19:33:18761 device_scale_factor, resource_manager, frame);
Kazuhiro Inaba4f19a782017-07-18 05:28:51762 }
Peng Huang583c9dc62017-07-27 23:38:28763
Peng Huangc51f7aba2017-09-05 16:00:39764 if (needs_update_resource_)
Albert Chaulk56e96582019-01-30 19:33:18765 UpdateResource(resource_manager);
Peng Huangc51f7aba2017-09-05 16:00:39766
Peng Huang76f5fd02017-09-01 00:59:39767 AppendContentsToFrame(origin, device_scale_factor, frame);
Peng Huang583c9dc62017-07-27 23:38:28768
Albert Chaulk56e96582019-01-30 19:33:18769 DCHECK(!current_resource_.id ||
770 resource_manager->HasReleaseCallbackForResource(current_resource_.id));
jbaumanbd9586a92016-05-28 01:09:03771}
772
jbauman90410452016-06-15 22:40:56773bool Surface::IsSynchronized() const {
Dominik Laskowski3e2f94792017-12-15 00:27:10774 return delegate_ && delegate_->IsSurfaceSynchronized();
775}
776
Dominik Laskowski14a163772018-02-09 19:25:18777bool Surface::IsInputEnabled(Surface* surface) const {
778 return !delegate_ || delegate_->IsInputEnabled(surface);
jbauman90410452016-06-15 22:40:56779}
reveman56f345902016-06-06 03:58:28780
Dominik Laskowski57064702017-11-30 10:31:41781bool Surface::HasHitTestRegion() const {
782 return !hit_test_region_.IsEmpty();
jbauman90410452016-06-15 22:40:56783}
784
Dominik Laskowski57064702017-11-30 10:31:41785bool Surface::HitTest(const gfx::Point& point) const {
786 return hit_test_region_.Contains(point);
jbauman90410452016-06-15 22:40:56787}
788
Raul Tambre038e96d2019-01-07 21:47:44789void Surface::GetHitTestMask(SkPath* mask) const {
Dominik Laskowski57064702017-11-30 10:31:41790 hit_test_region_.GetBoundaryPath(mask);
jbauman90410452016-06-15 22:40:56791}
792
jbauman90410452016-06-15 22:40:56793void Surface::SetSurfaceDelegate(SurfaceDelegate* delegate) {
794 DCHECK(!delegate_ || !delegate);
795 delegate_ = delegate;
796}
797
798bool Surface::HasSurfaceDelegate() const {
799 return !!delegate_;
800}
801
802void Surface::AddSurfaceObserver(SurfaceObserver* observer) {
803 observers_.AddObserver(observer);
804}
805
806void Surface::RemoveSurfaceObserver(SurfaceObserver* observer) {
807 observers_.RemoveObserver(observer);
808}
809
810bool Surface::HasSurfaceObserver(const SurfaceObserver* observer) const {
811 return observers_.HasObserver(observer);
812}
813
814std::unique_ptr<base::trace_event::TracedValue> Surface::AsTracedValue() const {
815 std::unique_ptr<base::trace_event::TracedValue> value(
816 new base::trace_event::TracedValue());
817 value->SetString("name", window_->layer()->name());
818 return value;
819}
820
kaznacheev8e270592017-05-25 06:13:26821bool Surface::IsStylusOnly() {
822 return window_->GetProperty(kStylusOnlyKey);
823}
824
825void Surface::SetStylusOnly() {
826 window_->SetProperty(kStylusOnlyKey, true);
827}
828
Peng Huangc51f7aba2017-09-05 16:00:39829void Surface::SurfaceHierarchyResourcesLost() {
830 // Update resource and full damage are needed for next frame.
831 needs_update_resource_ = true;
Peng Huang583c9dc62017-07-27 23:38:28832 for (const auto& sub_surface : sub_surfaces_)
Peng Huangc51f7aba2017-09-05 16:00:39833 sub_surface.first->SurfaceHierarchyResourcesLost();
reveman15aee282016-11-04 19:09:20834}
835
Peng Huang583c9dc62017-07-27 23:38:28836bool Surface::FillsBoundsOpaquely() const {
837 return !current_resource_has_alpha_ ||
838 state_.blend_mode == SkBlendMode::kSrc ||
Dominik Laskowski0dcf91352017-11-29 19:21:35839 state_.opaque_region.Contains(gfx::Rect(content_size_));
reveman211cf802017-01-10 00:30:59840}
841
Eliot Courtneybb051d12018-12-15 02:41:31842void Surface::SetOcclusionTracking(bool tracking) {
843 is_tracking_occlusion_ = tracking;
844 // TODO(edcourtney): Currently, it doesn't seem to be possible to stop
845 // tracking the occlusion state once started, but it would be nice to stop if
846 // the tracked occlusion region becomes empty.
847 if (is_tracking_occlusion_)
848 window()->TrackOcclusionState();
849}
850
[email protected]93855732019-06-24 19:49:30851void Surface::SetSurfaceHierarchyContentBoundsForTest(
852 const gfx::Rect& content_bounds) {
853 surface_hierarchy_content_bounds_ = content_bounds;
854}
855
reveman211cf802017-01-10 00:30:59856////////////////////////////////////////////////////////////////////////////////
857// Buffer, private:
858
Mike Reed2c570fa2018-01-11 21:59:22859Surface::State::State() {}
jbauman90410452016-06-15 22:40:56860
861Surface::State::~State() = default;
862
Lei Zhang1c9963ba2018-05-15 04:50:21863bool Surface::State::operator==(const State& other) const {
David Revemanfca309b2017-08-24 18:18:11864 return other.opaque_region == opaque_region &&
865 other.input_region == input_region &&
866 other.buffer_scale == buffer_scale &&
867 other.buffer_transform == buffer_transform &&
868 other.viewport == viewport && other.crop == crop &&
869 other.only_visible_on_secure_output == only_visible_on_secure_output &&
870 other.blend_mode == blend_mode && other.alpha == alpha;
jbauman90410452016-06-15 22:40:56871}
872
jbauman45c06862016-06-23 19:35:02873Surface::BufferAttachment::BufferAttachment() {}
874
875Surface::BufferAttachment::~BufferAttachment() {
876 if (buffer_)
877 buffer_->OnDetach();
878}
879
880Surface::BufferAttachment& Surface::BufferAttachment::operator=(
881 BufferAttachment&& other) {
882 if (buffer_)
883 buffer_->OnDetach();
884 buffer_ = other.buffer_;
David Revemane6e23342017-11-07 06:18:06885 size_ = other.size_;
jbauman45c06862016-06-23 19:35:02886 other.buffer_ = base::WeakPtr<Buffer>();
David Revemane6e23342017-11-07 06:18:06887 other.size_ = gfx::Size();
jbauman45c06862016-06-23 19:35:02888 return *this;
889}
890
891base::WeakPtr<Buffer>& Surface::BufferAttachment::buffer() {
892 return buffer_;
893}
894
895const base::WeakPtr<Buffer>& Surface::BufferAttachment::buffer() const {
896 return buffer_;
897}
898
David Revemane6e23342017-11-07 06:18:06899const gfx::Size& Surface::BufferAttachment::size() const {
900 return size_;
901}
902
jbauman45c06862016-06-23 19:35:02903void Surface::BufferAttachment::Reset(base::WeakPtr<Buffer> buffer) {
David Revemane6e23342017-11-07 06:18:06904 size_ = gfx::Size();
905 if (buffer) {
jbauman45c06862016-06-23 19:35:02906 buffer->OnAttach();
David Revemane6e23342017-11-07 06:18:06907 size_ = buffer->GetSize();
908 }
jbauman45c06862016-06-23 19:35:02909 if (buffer_)
910 buffer_->OnDetach();
911 buffer_ = buffer;
912}
913
Albert Chaulk56e96582019-01-30 19:33:18914void Surface::UpdateResource(FrameSinkResourceManager* resource_manager) {
Peng Huangc51f7aba2017-09-05 16:00:39915 DCHECK(needs_update_resource_);
916 needs_update_resource_ = false;
917 if (current_buffer_.buffer()) {
918 if (current_buffer_.buffer()->ProduceTransferableResource(
Daniele Castagnafade73662019-06-04 03:30:31919 resource_manager, std::move(acquire_fence_),
920 state_.only_visible_on_secure_output, &current_resource_)) {
Peng Huangc51f7aba2017-09-05 16:00:39921 current_resource_has_alpha_ =
922 FormatHasAlpha(current_buffer_.buffer()->GetFormat());
923 } else {
924 current_resource_.id = 0;
925 // Use the buffer's size, so the AppendContentsToFrame() will append
926 // a SolidColorDrawQuad with the buffer's size.
David Revemane6e23342017-11-07 06:18:06927 current_resource_.size = current_buffer_.size();
Peng Huangc51f7aba2017-09-05 16:00:39928 current_resource_has_alpha_ = false;
929 }
revemanca132dc2017-01-31 22:35:54930 } else {
jbauman45c06862016-06-23 19:35:02931 current_resource_.id = 0;
932 current_resource_.size = gfx::Size();
revemanca132dc2017-01-31 22:35:54933 current_resource_has_alpha_ = false;
jbauman45c06862016-06-23 19:35:02934 }
935}
936
Zach Reizner8bcce6e2018-10-31 00:04:37937void Surface::UpdateBufferTransform(bool y_invert) {
Lloyd Pique0a3045f2017-09-15 23:34:12938 SkMatrix buffer_matrix;
939 switch (state_.buffer_transform) {
940 case Transform::NORMAL:
941 buffer_matrix.setIdentity();
942 break;
943 case Transform::ROTATE_90:
944 buffer_matrix.setSinCos(-1, 0, 0.5f, 0.5f);
945 break;
946 case Transform::ROTATE_180:
947 buffer_matrix.setSinCos(0, -1, 0.5f, 0.5f);
948 break;
949 case Transform::ROTATE_270:
950 buffer_matrix.setSinCos(1, 0, 0.5f, 0.5f);
951 break;
952 }
Zach Reizner8bcce6e2018-10-31 00:04:37953 if (y_invert)
954 buffer_matrix.preScale(1, -1, 0.5f, 0.5f);
Lloyd Pique0a3045f2017-09-15 23:34:12955 buffer_matrix.postIDiv(state_.buffer_scale, state_.buffer_scale);
956 buffer_transform_ = gfx::Transform(buffer_matrix);
957}
958
Peng Huang583c9dc62017-07-27 23:38:28959void Surface::AppendContentsToFrame(const gfx::Point& origin,
Peng Huang76f5fd02017-09-01 00:59:39960 float device_scale_factor,
danakj5e0a12b2017-09-25 17:26:49961 viz::CompositorFrame* frame) {
danakje5805be2017-09-15 19:24:55962 const std::unique_ptr<viz::RenderPass>& render_pass =
Peng Huang583c9dc62017-07-27 23:38:28963 frame->render_pass_list.back();
David Revemanfca309b2017-08-24 18:18:11964 gfx::Rect output_rect(origin, content_size_);
Lloyd Pique0a3045f2017-09-15 23:34:12965 gfx::Rect quad_rect(0, 0, 1, 1);
David Revemanfca309b2017-08-24 18:18:11966
Dominik Laskowski2af53e72017-10-03 00:16:37967 // Surface bounds are in DIPs, but |damage_rect| and |output_rect| are in
968 // pixels, so we need to scale by the |device_scale_factor|.
Dominik Laskowski0dcf91352017-11-29 19:21:35969 gfx::Rect damage_rect = damage_.bounds();
David Reveman472ec3212017-11-11 04:19:03970 if (!damage_rect.IsEmpty()) {
971 // Outset damage by 1 DIP to as damage is in surface coordinate space and
972 // client might not be aware of |device_scale_factor| and the
973 // scaling/filtering it requires.
974 damage_rect.Inset(-1, -1);
Dominik Laskowski0dcf91352017-11-29 19:21:35975 damage_rect += origin.OffsetFromOrigin();
David Reveman472ec3212017-11-11 04:19:03976 damage_rect.Intersect(output_rect);
977 render_pass->damage_rect.Union(
978 gfx::ConvertRectToPixel(device_scale_factor, damage_rect));
979 }
980
Lloyd Pique0a3045f2017-09-15 23:34:12981 // Compute the total transformation from post-transform buffer coordinates to
982 // target coordinates.
983 SkMatrix viewport_to_target_matrix;
984 // Scale and offset the normalized space to fit the content size rectangle.
985 viewport_to_target_matrix.setScale(
986 content_size_.width() * state_.buffer_scale,
987 content_size_.height() * state_.buffer_scale);
988 viewport_to_target_matrix.postTranslate(origin.x(), origin.y());
989 // Convert from DPs to pixels.
990 viewport_to_target_matrix.postScale(device_scale_factor, device_scale_factor);
991
992 gfx::Transform quad_to_target_transform(buffer_transform_);
993 quad_to_target_transform.ConcatTransform(
994 gfx::Transform(viewport_to_target_matrix));
David Revemanfca309b2017-08-24 18:18:11995
Dominik Laskowski0dcf91352017-11-29 19:21:35996 bool are_contents_opaque = !current_resource_has_alpha_ ||
997 state_.blend_mode == SkBlendMode::kSrc ||
998 state_.opaque_region.Contains(output_rect);
yiyix10141eca2017-09-05 20:36:52999
Alex Zhangabad2292017-08-23 21:55:191000 viz::SharedQuadState* quad_state =
jbauman45c06862016-06-23 19:35:021001 render_pass->CreateAndAppendSharedQuadState();
Weiliang Chen5b0f31f62017-08-02 17:20:581002 quad_state->SetAll(
Malay Keshavc91ca412019-03-13 20:46:451003 quad_to_target_transform, quad_rect /*quad_layer_rect=*/,
1004 quad_rect /*visible_quad_layer_rect=*/,
1005 gfx::RRectF() /*rounded_corner_bounds=*/, gfx::Rect() /*clip_rect=*/,
1006 false /*is_clipped=*/, are_contents_opaque, state_.alpha /*opacity=*/,
1007 SkBlendMode::kSrcOver /*blend_mode=*/, 0 /*sorting_context_id=*/);
jbauman45c06862016-06-23 19:35:021008
Kazuhiro Inaba4f19a782017-07-18 05:28:511009 if (current_resource_.id) {
Lloyd Pique0a3045f2017-09-15 23:34:121010 gfx::RectF uv_crop(gfx::SizeF(1, 1));
Peng Huang583c9dc62017-07-27 23:38:281011 if (!state_.crop.IsEmpty()) {
Lloyd Pique0a3045f2017-09-15 23:34:121012 // The crop rectangle is a post-transformation rectangle. To get the UV
1013 // coordinates, we need to convert it to normalized buffer coordinates and
1014 // pass them through the inverse of the buffer transformation.
1015 uv_crop = gfx::RectF(state_.crop);
1016 gfx::Size transformed_buffer_size(
1017 ToTransformedSize(current_resource_.size, state_.buffer_transform));
1018 if (!transformed_buffer_size.IsEmpty())
1019 uv_crop.Scale(1.f / transformed_buffer_size.width(),
1020 1.f / transformed_buffer_size.height());
1021
1022 buffer_transform_.TransformRectReverse(&uv_crop);
Peng Huang583c9dc62017-07-27 23:38:281023 }
Lloyd Pique0a3045f2017-09-15 23:34:121024
Albert Chaulkfd08f9842019-10-11 15:26:141025 SkColor background_color = SK_ColorTRANSPARENT;
1026 if (current_resource_has_alpha_ && are_contents_opaque)
1027 background_color = SK_ColorBLACK; // Avoid writing alpha < 1
1028
1029 // If this surface is being replaced by a SurfaceId emit a SurfaceDrawQuad.
1030 if (get_current_surface_id_) {
1031 auto current_surface_id = get_current_surface_id_.Run();
Albert Chaulk0adb8b8d2019-11-06 20:06:271032 // If the surface ID is valid update it, otherwise keep showing the old
1033 // one for now.
Albert Chaulkfd08f9842019-10-11 15:26:141034 if (current_surface_id.is_valid()) {
Albert Chaulk0adb8b8d2019-11-06 20:06:271035 latest_embedded_surface_id_ = current_surface_id;
1036 if (!current_surface_id.HasSameEmbedTokenAs(
1037 first_embedded_surface_id_)) {
Albert Chaulkfd08f9842019-10-11 15:26:141038 first_embedded_surface_id_ = current_surface_id;
Albert Chaulk0adb8b8d2019-11-06 20:06:271039 }
1040 }
1041 if (latest_embedded_surface_id_.is_valid()) {
Albert Chaulkfd08f9842019-10-11 15:26:141042 viz::SurfaceDrawQuad* surface_quad =
1043 render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
Albert Chaulk0adb8b8d2019-11-06 20:06:271044 surface_quad->SetNew(quad_state, quad_rect, quad_rect,
1045 viz::SurfaceRange(first_embedded_surface_id_,
1046 latest_embedded_surface_id_),
1047 background_color,
1048 /*stretch_content_to_fill_bounds=*/true,
1049 /*ignores_input_event=*/false);
Albert Chaulkfd08f9842019-10-11 15:26:141050 }
1051 } else if (state_.alpha) {
1052 // Texture quad is only needed if buffer is not fully transparent.
danakje5805be2017-09-15 19:24:551053 viz::TextureDrawQuad* texture_quad =
1054 render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
revemane2d54b82016-08-25 00:30:381055 float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0};
Peng Huang583c9dc62017-07-27 23:38:281056 texture_quad->SetNew(
Daniele Castagna9f262542019-02-20 05:50:311057 quad_state, quad_rect, quad_rect,
1058 /* needs_blending=*/!are_contents_opaque, current_resource_.id,
1059 /* premultiplied_alpha=*/true, uv_crop.origin(),
1060 uv_crop.bottom_right(), background_color, vertex_opacity,
1061 /* y_flipped=*/false, /* nearest_neighbor=*/false,
Maggie Chena507bbb12019-06-04 00:19:511062 state_.only_visible_on_secure_output,
1063 gfx::ProtectedVideoType::kClear);
revemane2d54b82016-08-25 00:30:381064 if (current_resource_.is_overlay_candidate)
1065 texture_quad->set_resource_size_in_pixels(current_resource_.size);
Peng Huang583c9dc62017-07-27 23:38:281066 frame->resource_list.push_back(current_resource_);
revemane2d54b82016-08-25 00:30:381067 }
jbauman45c06862016-06-23 19:35:021068 } else {
danakje5805be2017-09-15 19:24:551069 viz::SolidColorDrawQuad* solid_quad =
1070 render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
Peng Huang583c9dc62017-07-27 23:38:281071 solid_quad->SetNew(quad_state, quad_rect, quad_rect, SK_ColorBLACK,
1072 false /* force_anti_aliasing_off */);
jbauman45c06862016-06-23 19:35:021073 }
Peng Huang583c9dc62017-07-27 23:38:281074}
jbauman45c06862016-06-23 19:35:021075
Peng Huang583c9dc62017-07-27 23:38:281076void Surface::UpdateContentSize() {
Peng Huang11ddbb42017-08-15 15:43:181077 gfx::Size content_size;
Peng Huang583c9dc62017-07-27 23:38:281078 if (!state_.viewport.IsEmpty()) {
Peng Huang11ddbb42017-08-15 15:43:181079 content_size = state_.viewport;
Peng Huang583c9dc62017-07-27 23:38:281080 } else if (!state_.crop.IsEmpty()) {
1081 DLOG_IF(WARNING, !gfx::IsExpressibleAsInt(state_.crop.width()) ||
1082 !gfx::IsExpressibleAsInt(state_.crop.height()))
1083 << "Crop rectangle size (" << state_.crop.size().ToString()
1084 << ") most be expressible using integers when viewport is not set";
Peng Huang11ddbb42017-08-15 15:43:181085 content_size = gfx::ToCeiledSize(state_.crop.size());
Peng Huang583c9dc62017-07-27 23:38:281086 } else {
David Revemane6e23342017-11-07 06:18:061087 content_size = gfx::ToCeiledSize(
1088 gfx::ScaleSize(gfx::SizeF(ToTransformedSize(current_buffer_.size(),
1089 state_.buffer_transform)),
1090 1.0f / state_.buffer_scale));
Peng Huang583c9dc62017-07-27 23:38:281091 }
Peng Huang583c9dc62017-07-27 23:38:281092
1093 // Enable/disable sub-surface based on if it has contents.
1094 if (has_contents())
1095 window_->Show();
1096 else
1097 window_->Hide();
Peng Huang11ddbb42017-08-15 15:43:181098
1099 if (content_size_ != content_size) {
1100 content_size_ = content_size;
1101 window_->SetBounds(gfx::Rect(window_->bounds().origin(), content_size_));
Peng Huang11ddbb42017-08-15 15:43:181102 }
reveman15aee282016-11-04 19:09:201103}
1104
Eliot Courtneybb051d12018-12-15 02:41:311105void Surface::OnWindowOcclusionChanged() {
1106 if (!is_tracking_occlusion_)
1107 return;
1108
1109 for (SurfaceObserver& observer : observers_)
1110 observer.OnWindowOcclusionChanged(this);
1111}
1112
revemanb195f41d2015-11-19 22:16:481113} // namespace exo