window_mirror_view.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright 2016 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. #include "ash/wm/window_mirror_view.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include "ash/wm/desks/desks_util.h"
  8. #include "ash/wm/window_state.h"
  9. #include "ui/aura/client/aura_constants.h"
  10. #include "ui/aura/env.h"
  11. #include "ui/aura/window.h"
  12. #include "ui/aura/window_occlusion_tracker.h"
  13. #include "ui/compositor/layer.h"
  14. #include "ui/compositor/layer_tree_owner.h"
  15. #include "ui/gfx/geometry/transform.h"
  16. #include "ui/views/widget/widget.h"
  17. #include "ui/wm/core/window_util.h"
  18. namespace ash {
  19. namespace {
  20. void EnsureAllChildrenAreVisible(ui::Layer* layer) {
  21. for (auto* child : layer->children())
  22. EnsureAllChildrenAreVisible(child);
  23. layer->SetVisible(true);
  24. layer->SetOpacity(1);
  25. }
  26. } // namespace
  27. WindowMirrorView::WindowMirrorView(aura::Window* source,
  28. bool trilinear_filtering_on_init,
  29. bool show_non_client_view)
  30. : source_(source),
  31. trilinear_filtering_on_init_(trilinear_filtering_on_init),
  32. show_non_client_view_(show_non_client_view) {
  33. source_->AddObserver(this);
  34. DCHECK(source);
  35. }
  36. WindowMirrorView::~WindowMirrorView() {
  37. // Make sure |source_| has outlived |this|. See crbug.com/681207
  38. if (source_) {
  39. DCHECK(source_->layer());
  40. source_->RemoveObserver(this);
  41. }
  42. }
  43. void WindowMirrorView::RecreateMirrorLayers() {
  44. if (layer_owner_)
  45. layer_owner_.reset();
  46. InitLayerOwner();
  47. }
  48. void WindowMirrorView::OnWindowDestroying(aura::Window* window) {
  49. DCHECK_EQ(source_, window);
  50. if (source_ == window) {
  51. source_->RemoveObserver(this);
  52. source_ = nullptr;
  53. }
  54. }
  55. gfx::Size WindowMirrorView::CalculatePreferredSize() const {
  56. return show_non_client_view_ ? source_->bounds().size()
  57. : GetClientAreaBounds().size();
  58. }
  59. void WindowMirrorView::Layout() {
  60. // If |layer_owner_| hasn't been initialized (|this| isn't on screen), no-op.
  61. if (!layer_owner_ || !source_)
  62. return;
  63. // Position at 0, 0.
  64. GetMirrorLayer()->SetBounds(gfx::Rect(GetMirrorLayer()->bounds().size()));
  65. if (show_non_client_view_) {
  66. GetMirrorLayer()->SetTransform(gfx::Transform());
  67. return;
  68. }
  69. gfx::Transform transform;
  70. gfx::Rect client_area_bounds = GetClientAreaBounds();
  71. // Scale if necessary.
  72. if (size() != source_->bounds().size()) {
  73. const float scale_x =
  74. width() / static_cast<float>(client_area_bounds.width());
  75. const float scale_y =
  76. height() / static_cast<float>(client_area_bounds.height());
  77. transform.Scale(scale_x, scale_y);
  78. }
  79. // Reposition such that the client area is the only part visible.
  80. transform.Translate(-client_area_bounds.x(), -client_area_bounds.y());
  81. GetMirrorLayer()->SetTransform(transform);
  82. }
  83. bool WindowMirrorView::GetNeedsNotificationWhenVisibleBoundsChange() const {
  84. return true;
  85. }
  86. void WindowMirrorView::OnVisibleBoundsChanged() {
  87. if (!layer_owner_ && !GetVisibleBounds().IsEmpty())
  88. InitLayerOwner();
  89. }
  90. void WindowMirrorView::AddedToWidget() {
  91. // Set and insert the new target window associated with this mirror view.
  92. target_ = GetWidget()->GetNativeWindow();
  93. target_->TrackOcclusionState();
  94. if (source_) {
  95. // Force the occlusion tracker to treat the source as visible.
  96. force_occlusion_tracker_visible_ =
  97. std::make_unique<aura::WindowOcclusionTracker::ScopedForceVisible>(
  98. source_);
  99. } else {
  100. force_occlusion_tracker_visible_.reset();
  101. }
  102. }
  103. void WindowMirrorView::RemovedFromWidget() {
  104. target_ = nullptr;
  105. }
  106. ui::Layer* WindowMirrorView::GetMirrorLayerForTesting() {
  107. return GetMirrorLayer();
  108. }
  109. void WindowMirrorView::InitLayerOwner() {
  110. layer_owner_ = wm::MirrorLayers(source_, /*sync_bounds=*/false);
  111. layer_owner_->root()->SetOpacity(1.f);
  112. SetPaintToLayer();
  113. ui::Layer* mirror_layer = GetMirrorLayer();
  114. layer()->Add(mirror_layer);
  115. // This causes us to clip the non-client areas of the window.
  116. layer()->SetMasksToBounds(true);
  117. // Some extra work is needed when the source window is minimized or is on an
  118. // inactive desk.
  119. if (WindowState::Get(source_)->IsMinimized() ||
  120. !desks_util::BelongsToActiveDesk(source_)) {
  121. EnsureAllChildrenAreVisible(mirror_layer);
  122. }
  123. if (trilinear_filtering_on_init_) {
  124. mirror_layer->AddCacheRenderSurfaceRequest();
  125. mirror_layer->AddTrilinearFilteringRequest();
  126. }
  127. Layout();
  128. }
  129. ui::Layer* WindowMirrorView::GetMirrorLayer() {
  130. return layer_owner_->root();
  131. }
  132. gfx::Rect WindowMirrorView::GetClientAreaBounds() const {
  133. DCHECK(!show_non_client_view_);
  134. const int inset = source_->GetProperty(aura::client::kTopViewInset);
  135. if (inset > 0) {
  136. gfx::Rect bounds(source_->bounds().size());
  137. bounds.Inset(gfx::Insets::TLBR(inset, 0, 0, 0));
  138. return bounds;
  139. }
  140. // The source window may not have a widget in unit tests.
  141. views::Widget* widget = views::Widget::GetWidgetForNativeWindow(source_);
  142. if (!widget || !widget->client_view())
  143. return gfx::Rect();
  144. views::View* client_view = widget->client_view();
  145. return client_view->ConvertRectToWidget(client_view->GetLocalBounds());
  146. }
  147. } // namespace ash