123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- // Copyright (c) 2013 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.
- #include "ui/aura/window_tree_host.h"
- #include "base/command_line.h"
- #include "base/containers/contains.h"
- #include "base/feature_list.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/scoped_refptr.h"
- #include "base/metrics/field_trial_params.h"
- #include "base/no_destructor.h"
- #include "base/observer_list.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/trace_event/trace_event.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "components/viz/common/features.h"
- #include "components/viz/common/surfaces/frame_sink_id.h"
- #include "components/viz/host/host_frame_sink_manager.h"
- #include "ui/aura/client/capture_client.h"
- #include "ui/aura/client/cursor_client.h"
- #include "ui/aura/env.h"
- #include "ui/aura/host_frame_rate_throttler.h"
- #include "ui/aura/native_window_occlusion_tracker.h"
- #include "ui/aura/scoped_keyboard_hook.h"
- #include "ui/aura/scoped_simple_keyboard_hook.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_event_dispatcher.h"
- #include "ui/aura/window_targeter.h"
- #include "ui/aura/window_tree_host_observer.h"
- #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
- #include "ui/base/ime/init/input_method_factory.h"
- #include "ui/base/ime/input_method.h"
- #include "ui/base/layout.h"
- #include "ui/base/ui_base_features.h"
- #include "ui/base/view_prop.h"
- #include "ui/compositor/compositor.h"
- #include "ui/compositor/compositor_switches.h"
- #include "ui/compositor/layer.h"
- #include "ui/display/display.h"
- #include "ui/display/screen.h"
- #include "ui/events/keycodes/dom/dom_code.h"
- #include "ui/gfx/geometry/insets.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/point3_f.h"
- #include "ui/gfx/geometry/point_conversions.h"
- #include "ui/gfx/geometry/rect_conversions.h"
- #include "ui/gfx/geometry/size_conversions.h"
- #include "ui/gfx/icc_profile.h"
- #include "ui/gfx/switches.h"
- #include "ui/platform_window/platform_window_init_properties.h"
- namespace aura {
- namespace {
- const char kWindowTreeHostForAcceleratedWidget[] =
- "__AURA_WINDOW_TREE_HOST_ACCELERATED_WIDGET__";
- // Returns the cc::Layer used by a ui::Layer. This is a bit ugly, and is done to
- // avoid exposing cc::Layer outside of ui::Layer.
- cc::Layer* ccLayerFromUiLayer(ui::Layer* layer) {
- return static_cast<ui::LayerAnimationDelegate*>(layer)->GetCcLayer();
- }
- #if DCHECK_IS_ON()
- class ScopedLocalSurfaceIdValidator {
- public:
- explicit ScopedLocalSurfaceIdValidator(Window* window)
- : window_(window),
- local_surface_id_(window ? window->GetLocalSurfaceId()
- : viz::LocalSurfaceId()) {}
- ScopedLocalSurfaceIdValidator(const ScopedLocalSurfaceIdValidator&) = delete;
- ScopedLocalSurfaceIdValidator& operator=(
- const ScopedLocalSurfaceIdValidator&) = delete;
- ~ScopedLocalSurfaceIdValidator() {
- if (window_) {
- DCHECK_EQ(local_surface_id_, window_->GetLocalSurfaceId());
- }
- }
- private:
- const raw_ptr<Window> window_;
- const viz::LocalSurfaceId local_surface_id_;
- };
- #else
- class ScopedLocalSurfaceIdValidator {
- public:
- explicit ScopedLocalSurfaceIdValidator(Window* window) {}
- ~ScopedLocalSurfaceIdValidator() {}
- };
- #endif
- } // namespace
- // In order for viz to drop all references to resources used by the browser
- // (and renderers) a CompositorFrame with *no* references to other surfaces
- // must be generated. To do this a solid color layer is inserted into the
- // layer tree, and the existing root layer is removed. Adding a layer at the top
- // (keeping existing layer tree) is not enough, as the CompositorFrame still
- // contains information about the surfaces/resources that are obscured. Once the
- // frame is generated, the root layer (from `window_`) is inserted back in the
- // Compositor's root layer and then the Compositor is hidden.
- class WindowTreeHost::HideHelper {
- public:
- explicit HideHelper(WindowTreeHost* host)
- : host_(host),
- compositor_root_layer_(
- ccLayerFromUiLayer(host->window()->layer())->mutable_parent()),
- layer_for_transition_(
- std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR)) {
- layer_for_transition_->SetColor(SK_ColorWHITE);
- aura::Window* host_window = host_->window();
- ui::Layer* host_window_layer = host_window->layer();
- ui::Compositor* compositor = host_->compositor();
- // SetRootLayer() resets the `compositor_` member in Layer. If
- // SetRootLayer() were used, it would mean the existing layer hierarchy
- // would no longer think it is in a compositor. As this state is temporary,
- // and purely to release resources, SetRootLayer() is not used.
- // We do need to disable ticking of animations since the animation code
- // expects that its callers ensure that any ticking animations reference
- // element IDs for layers that are currently in the layer tree.
- DCHECK_EQ(host_window_layer, compositor->root_layer());
- compositor->DisableAnimations();
- ccLayerFromUiLayer(host_window_layer)->RemoveFromParent();
- layer_for_transition_->SetBounds(host_window->bounds());
- compositor_root_layer_->AddChild(
- ccLayerFromUiLayer(layer_for_transition_.get()));
- layer_for_transition_->OnDeviceScaleFactorChanged(
- host_window->layer()->device_scale_factor());
- // Request a presentation frame. Once the frame is generated the real root
- // layer is added back (from the destructor).
- compositor->RequestPresentationTimeForNextFrame(base::BindOnce(
- &HideHelper::OnFramePresented, weak_ptr_factory_.GetWeakPtr()));
- }
- ~HideHelper() {
- ui::Layer* host_window_layer = host_->window()->layer();
- compositor_root_layer_->AddChild(ccLayerFromUiLayer(host_window_layer));
- host_window_layer->OnDeviceScaleFactorChanged(
- layer_for_transition_->device_scale_factor());
- DCHECK_EQ(host_window_layer, host_->compositor()->root_layer());
- host_->compositor()->EnableAnimations();
- }
- private:
- void OnFramePresented(const gfx::PresentationFeedback& feedback) {
- host_->FinishHideTransition();
- // WARNING: this has been deleted.
- }
- raw_ptr<WindowTreeHost, DanglingUntriaged> host_;
- scoped_refptr<cc::Layer> compositor_root_layer_;
- std::unique_ptr<ui::Layer> layer_for_transition_;
- base::WeakPtrFactory<HideHelper> weak_ptr_factory_{this};
- };
- WindowTreeHost::VideoCaptureLock::~VideoCaptureLock() {
- if (host_)
- host_->DecrementVideoCaptureCount();
- }
- WindowTreeHost::VideoCaptureLock::VideoCaptureLock(WindowTreeHost* host)
- : host_(host->GetWeakPtr()) {}
- ////////////////////////////////////////////////////////////////////////////////
- // WindowTreeHost, public:
- WindowTreeHost::~WindowTreeHost() {
- DCHECK(!compositor_) << "compositor must be destroyed before root window";
- }
- // static
- WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget(
- gfx::AcceleratedWidget widget) {
- return reinterpret_cast<WindowTreeHost*>(
- ui::ViewProp::GetValue(widget, kWindowTreeHostForAcceleratedWidget));
- }
- void WindowTreeHost::InitHost() {
- display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
- device_scale_factor_ = display.device_scale_factor();
- UpdateRootWindowSize();
- InitCompositor();
- Env::GetInstance()->NotifyHostInitialized(this);
- }
- void WindowTreeHost::AddObserver(WindowTreeHostObserver* observer) {
- observers_.AddObserver(observer);
- }
- void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) {
- observers_.RemoveObserver(observer);
- }
- bool WindowTreeHost::HasObserver(const WindowTreeHostObserver* observer) const {
- return observers_.HasObserver(observer);
- }
- base::WeakPtr<WindowTreeHost> WindowTreeHost::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
- }
- gfx::Transform WindowTreeHost::GetRootTransform() const {
- gfx::Transform transform;
- transform.Scale(device_scale_factor_, device_scale_factor_);
- transform *= window()->layer()->transform();
- return transform;
- }
- void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) {
- window()->SetTransform(transform);
- UpdateRootWindowSize();
- }
- gfx::Transform WindowTreeHost::GetInverseRootTransform() const {
- gfx::Transform invert;
- gfx::Transform transform = GetRootTransform();
- if (!transform.GetInverse(&invert))
- return transform;
- return invert;
- }
- void WindowTreeHost::SetDisplayTransformHint(gfx::OverlayTransform transform) {
- if (compositor()->display_transform_hint() == transform)
- return;
- compositor()->SetDisplayTransformHint(transform);
- UpdateCompositorScaleAndSize(GetBoundsInPixels().size());
- }
- gfx::Transform WindowTreeHost::GetRootTransformForLocalEventCoordinates()
- const {
- return GetRootTransform();
- }
- gfx::Transform WindowTreeHost::GetInverseRootTransformForLocalEventCoordinates()
- const {
- gfx::Transform invert;
- gfx::Transform transform = GetRootTransformForLocalEventCoordinates();
- if (!transform.GetInverse(&invert))
- return transform;
- return invert;
- }
- void WindowTreeHost::UpdateCompositorScaleAndSize(
- const gfx::Size& new_size_in_pixels) {
- gfx::Rect new_bounds(new_size_in_pixels);
- if (compositor_->display_transform_hint() ==
- gfx::OVERLAY_TRANSFORM_ROTATE_90 ||
- compositor_->display_transform_hint() ==
- gfx::OVERLAY_TRANSFORM_ROTATE_270) {
- new_bounds.Transpose();
- }
- // Allocate a new LocalSurfaceId for the new size or scale factor.
- window_->AllocateLocalSurfaceId();
- ScopedLocalSurfaceIdValidator lsi_validator(window());
- compositor_->SetScaleAndSize(device_scale_factor_, new_bounds.size(),
- window_->GetLocalSurfaceId());
- }
- void WindowTreeHost::ConvertDIPToScreenInPixels(gfx::Point* point) const {
- ConvertDIPToPixels(point);
- gfx::Point location = GetLocationOnScreenInPixels();
- point->Offset(location.x(), location.y());
- }
- void WindowTreeHost::ConvertScreenInPixelsToDIP(gfx::Point* point) const {
- gfx::Point location = GetLocationOnScreenInPixels();
- point->Offset(-location.x(), -location.y());
- ConvertPixelsToDIP(point);
- }
- void WindowTreeHost::ConvertDIPToPixels(gfx::Point* point) const {
- gfx::PointF point_f{*point};
- ConvertDIPToPixels(&point_f);
- *point = gfx::ToFlooredPoint(point_f);
- }
- void WindowTreeHost::ConvertDIPToPixels(gfx::PointF* point) const {
- GetRootTransform().TransformPoint(point);
- }
- void WindowTreeHost::ConvertPixelsToDIP(gfx::Point* point) const {
- gfx::PointF point_f{*point};
- ConvertPixelsToDIP(&point_f);
- *point = gfx::ToFlooredPoint(point_f);
- }
- void WindowTreeHost::ConvertPixelsToDIP(gfx::PointF* point) const {
- GetInverseRootTransform().TransformPoint(point);
- }
- void WindowTreeHost::SetCursor(gfx::NativeCursor cursor) {
- last_cursor_ = cursor;
- // A lot of code seems to depend on NULL cursors actually showing an arrow,
- // so just pass everything along to the host.
- SetCursorNative(cursor);
- }
- void WindowTreeHost::OnCursorVisibilityChanged(bool show) {
- // Clear any existing mouse hover effects when the cursor becomes invisible.
- // Note we do not need to dispatch a mouse enter when the cursor becomes
- // visible because that can only happen in response to a mouse event, which
- // will trigger its own mouse enter.
- if (!show) {
- ui::EventDispatchDetails details = dispatcher()->DispatchMouseExitAtPoint(
- nullptr, dispatcher()->GetLastMouseLocationInRoot(),
- ui::EF_CURSOR_HIDE);
- if (details.dispatcher_destroyed)
- return;
- }
- OnCursorVisibilityChangedNative(show);
- }
- void WindowTreeHost::MoveCursorToLocationInDIP(
- const gfx::Point& location_in_dip) {
- gfx::Point host_location(location_in_dip);
- ConvertDIPToPixels(&host_location);
- MoveCursorToInternal(location_in_dip, host_location);
- }
- void WindowTreeHost::MoveCursorToLocationInPixels(
- const gfx::Point& location_in_pixels) {
- gfx::Point root_location(location_in_pixels);
- ConvertPixelsToDIP(&root_location);
- MoveCursorToInternal(root_location, location_in_pixels);
- }
- ui::InputMethod* WindowTreeHost::GetInputMethod() {
- if (!input_method_) {
- input_method_owned_ = ui::CreateInputMethod(this, GetAcceleratedWidget());
- input_method_ = input_method_owned_.get();
- }
- return input_method_;
- }
- void WindowTreeHost::SetSharedInputMethod(ui::InputMethod* input_method) {
- input_method_ = input_method;
- input_method_owned_.reset();
- }
- ui::EventDispatchDetails WindowTreeHost::DispatchKeyEventPostIME(
- ui::KeyEvent* event) {
- // If dispatch to IME is already disabled we shouldn't reach here.
- DCHECK(!dispatcher_->should_skip_ime());
- dispatcher_->set_skip_ime(true);
- // InputMethod::DispatchKeyEvent() is called in PRE_DISPATCH phase, so event
- // target is reset here to avoid issues in subsequent processing phases.
- ui::Event::DispatcherApi(event).set_target(nullptr);
- // We should bypass event rewriters here as they've been tried before.
- ui::EventDispatchDetails dispatch_details =
- GetEventSink()->OnEventFromSource(event);
- if (!dispatch_details.dispatcher_destroyed)
- dispatcher_->set_skip_ime(false);
- return dispatch_details;
- }
- ui::EventSink* WindowTreeHost::GetEventSink() {
- return dispatcher_.get();
- }
- int64_t WindowTreeHost::GetDisplayId() {
- return display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id();
- }
- void WindowTreeHost::Show() {
- // Ensure that compositor has been properly initialized, see InitCompositor()
- // and InitHost().
- DCHECK(compositor());
- DCHECK_EQ(compositor()->root_layer(), window()->layer());
- OnAcceleratedWidgetMadeVisible(true);
- ShowImpl();
- window()->Show();
- }
- void WindowTreeHost::Hide() {
- HideImpl();
- OnAcceleratedWidgetMadeVisible(false);
- }
- gfx::Rect WindowTreeHost::GetBoundsInDIP() const {
- aura::Window* root_window = const_cast<aura::Window*>(window());
- display::Screen* screen = display::Screen::GetScreen();
- gfx::Rect screen_bounds = GetBoundsInPixels();
- return screen->ScreenToDIPRectInWindow(root_window, screen_bounds);
- }
- gfx::Rect WindowTreeHost::GetBoundsInAcceleratedWidgetPixelCoordinates() {
- return gfx::Rect(GetBoundsInPixels().size());
- }
- std::unique_ptr<ScopedKeyboardHook> WindowTreeHost::CaptureSystemKeyEvents(
- absl::optional<base::flat_set<ui::DomCode>> dom_codes) {
- // TODO(joedow): Remove the simple hook class/logic once this flag is removed.
- if (!base::FeatureList::IsEnabled(features::kSystemKeyboardLock))
- return std::make_unique<ScopedSimpleKeyboardHook>(std::move(dom_codes));
- if (CaptureSystemKeyEventsImpl(std::move(dom_codes)))
- return std::make_unique<ScopedKeyboardHook>(weak_factory_.GetWeakPtr());
- return nullptr;
- }
- bool WindowTreeHost::ShouldSendKeyEventToIme() {
- return true;
- }
- bool WindowTreeHost::IsNativeWindowOcclusionEnabled() const {
- return native_window_occlusion_enabled_;
- }
- void WindowTreeHost::SetNativeWindowOcclusionState(
- Window::OcclusionState state,
- const SkRegion& occluded_region) {
- if (occlusion_state_ == state && occluded_region_ == occluded_region)
- return;
- occlusion_state_ = state;
- if (compositor() && accelerated_widget_made_visible_ &&
- NativeWindowOcclusionTracker::
- IsNativeWindowOcclusionTrackingAlwaysEnabled(this)) {
- if (ShouldThrottleWhenOccluded()) {
- // Throttling doesn't update the visibility.
- if (occlusion_state_ == Window::OcclusionState::OCCLUDED)
- HostFrameRateThrottler::GetInstance().AddHost(this);
- else
- HostFrameRateThrottler::GetInstance().RemoveHost(this);
- } else {
- const bool visible = CalculateCompositorVisibilityFromOcclusionState();
- // Transitioning to hidden means the compositor state hasn't been updated
- // yet, but will. In this case, always route through
- // UpdateCompositorVisibility() to ensure state is correctly cleaned up.
- if (visible != compositor()->IsVisible() || is_transitioning_to_hidden())
- UpdateCompositorVisibility(visible);
- }
- }
- for (WindowTreeHostObserver& observer : observers_)
- observer.OnOcclusionStateChanged(this, state, occluded_region);
- }
- void WindowTreeHost::UpdateRootWindowSize() {
- // Validate that the LocalSurfaceId does not change.
- bool compositor_inited = !!compositor()->root_layer();
- ScopedLocalSurfaceIdValidator lsi_validator(compositor_inited ? window()
- : nullptr);
- window()->SetBounds(CalculateRootWindowBounds());
- }
- gfx::Rect WindowTreeHost::CalculateRootWindowBounds() const {
- return GetTransformedRootWindowBoundsFromPixelSize(
- GetBoundsInPixels().size());
- }
- std::unique_ptr<ScopedEnableUnadjustedMouseEvents>
- WindowTreeHost::RequestUnadjustedMovement() {
- NOTIMPLEMENTED();
- return nullptr;
- }
- bool WindowTreeHost::SupportsMouseLock() {
- return false;
- }
- void WindowTreeHost::LockMouse(Window* window) {
- Window* root_window = window->GetRootWindow();
- DCHECK(root_window);
- auto* cursor_client = client::GetCursorClient(root_window);
- if (cursor_client) {
- cursor_client->HideCursor();
- cursor_client->LockCursor();
- }
- }
- void WindowTreeHost::UnlockMouse(Window* window) {
- Window* root_window = window->GetRootWindow();
- DCHECK(root_window);
- if (window->HasCapture())
- window->ReleaseCapture();
- auto* cursor_client = client::GetCursorClient(root_window);
- if (cursor_client) {
- cursor_client->UnlockCursor();
- cursor_client->ShowCursor();
- }
- }
- std::unique_ptr<WindowTreeHost::VideoCaptureLock>
- WindowTreeHost::CreateVideoCaptureLock() {
- if (!NativeWindowOcclusionTracker::
- IsNativeWindowOcclusionTrackingAlwaysEnabled(this)) {
- return nullptr;
- }
- // Throtting doesn't actually change the visibility, so no need for the lock.
- if (ShouldThrottleWhenOccluded())
- return nullptr;
- ++video_capture_count_;
- MaybeUpdateComposibleVisibilityForVideoLockCountChange();
- // WrapUnique() is used as constructor is private.
- return base::WrapUnique(new VideoCaptureLock(this));
- }
- ////////////////////////////////////////////////////////////////////////////////
- // WindowTreeHost, protected:
- WindowTreeHost::WindowTreeHost(std::unique_ptr<Window> window)
- : window_(window.release()) { // See header for details on ownership.
- if (!window_)
- window_ = new Window(nullptr);
- auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
- device_scale_factor_ = display.device_scale_factor();
- #if BUILDFLAG(IS_WIN)
- // The feature state is necessary but not sufficient for checking if
- // occlusion is enabled. It may be disabled by other means (e.g., policy).
- native_window_occlusion_enabled_ =
- !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless) &&
- base::FeatureList::IsEnabled(features::kCalculateNativeWinOcclusion);
- #endif
- }
- void WindowTreeHost::UpdateCompositorVisibility(bool visible) {
- if (!compositor())
- return;
- if (ShouldThrottleWhenOccluded()) {
- // If ShouldThrottleWhenOccluded() is true, then this function should only
- // be called if visibility is changed externally. In this case, assume
- // `occlusion_state_` is being ignored, and that throtting should be
- // disabled. For the most part, if ShouldThrottleWhenOccluded() is true,
- // the handling of occlusion changing is done in
- // SetNativeWindowOcclusionState().
- HostFrameRateThrottler::GetInstance().RemoveHost(this);
- }
- if (visible) {
- if (is_transitioning_to_hidden())
- RestoreHideTransitionState();
- } else {
- if (is_transitioning_to_hidden())
- return;
- if (ShouldReleaseResourcesWhenHidden()) {
- StartReleasingResourcesForHide();
- // Compositor visibility is changed once transition completes.
- return;
- }
- }
- compositor()->SetVisible(visible);
- }
- void WindowTreeHost::DestroyCompositor() {
- if (!compositor_)
- return;
- HostFrameRateThrottler::GetInstance().RemoveHost(this);
- // Explicitly delete the HideHelper early as it makes use of `compositor_`
- // and `window_`.
- hide_helper_.reset();
- compositor_->RemoveObserver(this);
- compositor_.reset();
- if (NativeWindowOcclusionTracker::
- IsNativeWindowOcclusionTrackingAlwaysEnabled(this)) {
- NativeWindowOcclusionTracker::DisableNativeWindowOcclusionTracking(this);
- }
- }
- void WindowTreeHost::DestroyDispatcher() {
- Env::GetInstance()->NotifyHostDestroyed(this);
- delete window_;
- window_ = nullptr;
- dispatcher_.reset();
- // TODO(beng): this comment is no longer quite valid since this function
- // isn't called from WED, and WED isn't a subclass of Window. So it seems
- // like we could just rely on ~Window now.
- // Destroy child windows while we're still valid. This is also done by
- // ~Window, but by that time any calls to virtual methods overriden here (such
- // as GetRootWindow()) result in Window's implementation. By destroying here
- // we ensure GetRootWindow() still returns this.
- // window()->RemoveOrDestroyChildren();
- }
- void WindowTreeHost::OnAcceleratedWidgetMadeVisible(bool value) {
- if (accelerated_widget_made_visible_ == value)
- return;
- accelerated_widget_made_visible_ = value;
- // Always update the compositor (ignoring occlusion-state) as it is entirely
- // possible the occlusion-state is out of date at this point. It is expected
- // that the proper occlusion state is provided soon after this.
- UpdateCompositorVisibility(value);
- }
- void WindowTreeHost::CreateCompositor(bool force_software_compositor,
- bool use_external_begin_frame_control,
- bool enable_compositing_based_throttling,
- size_t memory_limit_when_visible_mb) {
- Env* env = Env::GetInstance();
- ui::ContextFactory* context_factory = env->context_factory();
- DCHECK(context_factory);
- compositor_ = std::make_unique<ui::Compositor>(
- context_factory->AllocateFrameSinkId(), context_factory,
- base::ThreadTaskRunnerHandle::Get(), ui::IsPixelCanvasRecordingEnabled(),
- use_external_begin_frame_control, force_software_compositor,
- enable_compositing_based_throttling, memory_limit_when_visible_mb);
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- compositor_->AddObserver(this);
- #endif
- if (!dispatcher()) {
- window()->Init(ui::LAYER_NOT_DRAWN);
- window()->set_host(this);
- window()->SetName("RootWindow");
- dispatcher_ = std::make_unique<WindowEventDispatcher>(this);
- }
- }
- void WindowTreeHost::InitCompositor() {
- DCHECK(!compositor_->root_layer());
- compositor_->SetScaleAndSize(device_scale_factor_, GetBoundsInPixels().size(),
- window()->GetLocalSurfaceId());
- compositor_->SetRootLayer(window()->layer());
- display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
- compositor_->SetDisplayColorSpaces(display.color_spaces());
- }
- void WindowTreeHost::OnAcceleratedWidgetAvailable() {
- compositor_->SetAcceleratedWidget(GetAcceleratedWidget());
- prop_ = std::make_unique<ui::ViewProp>(
- GetAcceleratedWidget(), kWindowTreeHostForAcceleratedWidget, this);
- if (NativeWindowOcclusionTracker::
- IsNativeWindowOcclusionTrackingAlwaysEnabled(this)) {
- NativeWindowOcclusionTracker::EnableNativeWindowOcclusionTracking(this);
- }
- }
- void WindowTreeHost::OnHostMovedInPixels() {
- TRACE_EVENT0("ui", "WindowTreeHost::OnHostMovedInPixels");
- for (WindowTreeHostObserver& observer : observers_)
- observer.OnHostMovedInPixels(this);
- }
- void WindowTreeHost::OnHostResizedInPixels(
- const gfx::Size& new_size_in_pixels) {
- // The compositor is deleted from WM_DESTROY, but we don't delete things until
- // WM_NCDESTROY, and it must be possible to still get some messages between
- // these two.
- if (!compositor_)
- return;
- display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
- // If we don't have the actual display, don't overwrite the scale factor with
- // the default value. See https://crbug.com/1285476 for details.
- if (display.is_valid())
- device_scale_factor_ = display.device_scale_factor();
- UpdateRootWindowSize();
- // Passing |new_size_in_pixels| to set compositor size. It could be different
- // from GetBoundsInPixels() on Windows to contain extra space for window
- // transition animations and should be used to set compositor size instead of
- // GetBoundsInPixels() in such case.
- UpdateCompositorScaleAndSize(new_size_in_pixels);
- for (WindowTreeHostObserver& observer : observers_)
- observer.OnHostResized(this);
- }
- void WindowTreeHost::OnHostWorkspaceChanged() {
- for (WindowTreeHostObserver& observer : observers_)
- observer.OnHostWorkspaceChanged(this);
- }
- void WindowTreeHost::OnHostDisplayChanged() {
- if (!compositor_)
- return;
- display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
- compositor_->SetDisplayColorSpaces(display.color_spaces());
- }
- void WindowTreeHost::OnHostCloseRequested() {
- for (WindowTreeHostObserver& observer : observers_)
- observer.OnHostCloseRequested(this);
- }
- void WindowTreeHost::OnHostLostWindowCapture() {
- // It is possible for this function to be called during destruction, after the
- // root window has already been destroyed (e.g. when the ui::PlatformWindow is
- // destroyed, and during destruction, it loses capture. See more details in
- // http://crbug.com/770670)
- if (!window())
- return;
- Window* capture_window = client::GetCaptureWindow(window());
- if (capture_window && capture_window->GetRootWindow() == window())
- capture_window->ReleaseCapture();
- }
- void WindowTreeHost::OnDisplayMetricsChanged(const display::Display& display,
- uint32_t metrics) {
- if (metrics & DisplayObserver::DISPLAY_METRIC_COLOR_SPACE && compositor_ &&
- display.id() == GetDisplayId())
- compositor_->SetDisplayColorSpaces(display.color_spaces());
- // Chrome OS is handled in WindowTreeHostManager::OnDisplayMetricsChanged.
- // Chrome OS requires additional handling for the bounds that we do not need to
- // do for other OSes.
- #if !BUILDFLAG(IS_CHROMEOS_ASH)
- if (metrics & DISPLAY_METRIC_DEVICE_SCALE_FACTOR &&
- display.id() == GetDisplayId())
- OnHostResizedInPixels(GetBoundsInPixels().size());
- #endif
- }
- gfx::Rect WindowTreeHost::GetTransformedRootWindowBoundsFromPixelSize(
- const gfx::Size& size_in_pixels) const {
- gfx::RectF new_bounds = gfx::RectF(gfx::Rect(size_in_pixels));
- GetInverseRootTransform().TransformRect(&new_bounds);
- return gfx::ToEnclosingRect(new_bounds);
- }
- void WindowTreeHost::SetNativeWindowOcclusionEnabled(bool enable) {
- native_window_occlusion_enabled_ = enable;
- // TODO(crbug.com/1051306) If enabled is false, make this
- // turn off native window occlusion on this window. Only Windows has
- // native window occlusion currently.
- }
- ////////////////////////////////////////////////////////////////////////////////
- // WindowTreeHost, private:
- void WindowTreeHost::DecrementVideoCaptureCount() {
- DCHECK_GT(video_capture_count_, 0);
- --video_capture_count_;
- MaybeUpdateComposibleVisibilityForVideoLockCountChange();
- }
- void WindowTreeHost::MaybeUpdateComposibleVisibilityForVideoLockCountChange() {
- // Should only be called if the occlusion is applied to the compositor.
- DCHECK(!ShouldThrottleWhenOccluded());
- // Only need to check for changes when transitioning between lock and no lock.
- if (video_capture_count_ > 1 || !compositor() ||
- !accelerated_widget_made_visible_) {
- return;
- }
- const bool visible = CalculateCompositorVisibilityFromOcclusionState();
- if (visible != compositor()->IsVisible() || is_transitioning_to_hidden())
- UpdateCompositorVisibility(visible);
- }
- bool WindowTreeHost::CalculateCompositorVisibilityFromOcclusionState() const {
- switch (occlusion_state_) {
- case Window::OcclusionState::UNKNOWN:
- return true;
- case Window::OcclusionState::VISIBLE:
- return true;
- case Window::OcclusionState::OCCLUDED: {
- // The compositor needs to be visible when capturing video.
- return video_capture_count_ != 0;
- }
- case Window::OcclusionState::HIDDEN:
- // TODO: this should really return true if `video_capture_count_` is
- // not zero, but this likely needs other changes to really work (such
- // as on windows when an HWND is iconified it is sized to 0x0).
- return false;
- }
- }
- bool WindowTreeHost::ShouldReleaseResourcesWhenHidden() const {
- #if BUILDFLAG(IS_WIN)
- if (!base::FeatureList::IsEnabled(
- features::kApplyNativeOcclusionToCompositor) ||
- !IsNativeWindowOcclusionEnabled()) {
- return false;
- }
- const std::string type = base::GetFieldTrialParamValueByFeature(
- features::kApplyNativeOcclusionToCompositor,
- features::kApplyNativeOcclusionToCompositorType);
- return type == features::kApplyNativeOcclusionToCompositorTypeRelease;
- #else
- return false;
- #endif
- }
- bool WindowTreeHost::ShouldThrottleWhenOccluded() const {
- #if BUILDFLAG(IS_WIN)
- if (!base::FeatureList::IsEnabled(
- features::kApplyNativeOcclusionToCompositor) ||
- !IsNativeWindowOcclusionEnabled()) {
- return false;
- }
- const std::string type = base::GetFieldTrialParamValueByFeature(
- features::kApplyNativeOcclusionToCompositor,
- features::kApplyNativeOcclusionToCompositorType);
- return type == features::kApplyNativeOcclusionToCompositorTypeThrottle;
- #else
- return false;
- #endif
- }
- void WindowTreeHost::RestoreHideTransitionState() {
- DCHECK(is_transitioning_to_hidden());
- hide_helper_.reset();
- }
- void WindowTreeHost::FinishHideTransition() {
- DCHECK(is_transitioning_to_hidden());
- compositor_->SetVisible(false);
- RestoreHideTransitionState();
- }
- // static
- const base::flat_set<WindowTreeHost*>&
- WindowTreeHost::GetThrottledHostsForTesting() {
- return HostFrameRateThrottler::GetInstance().hosts();
- }
- void WindowTreeHost::StartReleasingResourcesForHide() {
- DCHECK(!is_transitioning_to_hidden());
- if (compositor_->size().IsEmpty()) {
- // This should generally only happen during startup as Compositor silently
- // ignores changing the size to empty.
- compositor_->SetVisible(false);
- return;
- }
- hide_helper_ = std::make_unique<HideHelper>(this);
- }
- void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location,
- const gfx::Point& host_location) {
- last_cursor_request_position_in_host_ = host_location;
- MoveCursorToScreenLocationInPixels(host_location);
- client::CursorClient* cursor_client = client::GetCursorClient(window());
- if (cursor_client) {
- const display::Display& display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window());
- cursor_client->SetDisplay(display);
- }
- dispatcher()->OnCursorMovedToRootLocation(root_location);
- }
- void WindowTreeHost::OnCompositingEnded(ui::Compositor* compositor) {
- if (!holding_pointer_moves_)
- return;
- dispatcher_->ReleasePointerMoves();
- holding_pointer_moves_ = false;
- }
- void WindowTreeHost::OnCompositingChildResizing(ui::Compositor* compositor) {
- if (!Env::GetInstance()->throttle_input_on_resize() || holding_pointer_moves_)
- return;
- dispatcher_->HoldPointerMoves();
- holding_pointer_moves_ = true;
- }
- void WindowTreeHost::OnFrameSinksToThrottleUpdated(
- const base::flat_set<viz::FrameSinkId>& ids) {
- for (auto& observer : observers_)
- observer.OnCompositingFrameSinksToThrottleUpdated(this, ids);
- }
- } // namespace aura
|