notification_surface.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 "components/exo/notification_surface.h"
  5. #include <cmath>
  6. #include "components/exo/notification_surface_manager.h"
  7. #include "components/exo/shell_surface_util.h"
  8. #include "components/exo/surface.h"
  9. #include "components/viz/host/host_frame_sink_manager.h"
  10. #include "ui/aura/client/aura_constants.h"
  11. #include "ui/aura/env.h"
  12. #include "ui/aura/window.h"
  13. #include "ui/compositor/compositor.h"
  14. #include "ui/compositor/layer.h"
  15. #include "ui/gfx/geometry/rect.h"
  16. #include "ui/gfx/geometry/size_conversions.h"
  17. namespace exo {
  18. NotificationSurface::NotificationSurface(NotificationSurfaceManager* manager,
  19. Surface* surface,
  20. const std::string& notification_key)
  21. : SurfaceTreeHost("ExoNotificationSurface"),
  22. manager_(manager),
  23. notification_key_(notification_key) {
  24. surface->AddSurfaceObserver(this);
  25. SetRootSurface(surface);
  26. host_window()->Show();
  27. host_window()->AddObserver(this);
  28. }
  29. NotificationSurface::~NotificationSurface() {
  30. if (host_window())
  31. host_window()->RemoveObserver(this);
  32. if (added_to_manager_)
  33. manager_->RemoveSurface(this);
  34. if (root_surface())
  35. root_surface()->RemoveSurfaceObserver(this);
  36. }
  37. gfx::Size NotificationSurface::GetContentSize() const {
  38. float int_part;
  39. DCHECK(std::modf(root_surface()->content_size().width(), &int_part) == 0.0f &&
  40. std::modf(root_surface()->content_size().height(), &int_part) == 0.0f);
  41. return gfx::ToRoundedSize(root_surface()->content_size());
  42. }
  43. void NotificationSurface::SetApplicationId(const char* application_id) {
  44. SetShellApplicationId(host_window(), absl::make_optional(application_id));
  45. }
  46. void NotificationSurface::OnSurfaceCommit() {
  47. SurfaceTreeHost::OnSurfaceCommit();
  48. // Defer AddSurface until there are contents to show.
  49. if (!added_to_manager_ && !host_window()->bounds().IsEmpty()) {
  50. added_to_manager_ = true;
  51. manager_->AddSurface(this);
  52. }
  53. // Only submit a compositor frame if the notification is being shown.
  54. // Submitting compositor frames while invisible causes Viz to hold on to
  55. // references to each notification buffer while it waits for an embedding (
  56. // or a timeout occurs). This can cause buffer starvation on the Android side,
  57. // leading to ANRs.
  58. if (is_embedded_)
  59. SubmitCompositorFrame();
  60. }
  61. void NotificationSurface::OnSurfaceDestroying(Surface* surface) {
  62. DCHECK_EQ(surface, root_surface());
  63. surface->RemoveSurfaceObserver(this);
  64. SetRootSurface(nullptr);
  65. }
  66. void NotificationSurface::OnWindowDestroying(aura::Window* window) {
  67. window->RemoveObserver(this);
  68. }
  69. void NotificationSurface::OnWindowPropertyChanged(aura::Window* window,
  70. const void* key,
  71. intptr_t old_value) {
  72. if (key == aura::client::kSkipImeProcessing) {
  73. SetSkipImeProcessingToDescendentSurfaces(
  74. window, window->GetProperty(aura::client::kSkipImeProcessing));
  75. }
  76. }
  77. void NotificationSurface::OnWindowAddedToRootWindow(aura::Window* window) {
  78. // Force recreating resources to submit the compositor frame w/o
  79. // commit request.
  80. root_surface()->SurfaceHierarchyResourcesLost();
  81. SubmitCompositorFrame();
  82. is_embedded_ = true;
  83. }
  84. void NotificationSurface::OnWindowRemovingFromRootWindow(
  85. aura::Window* window,
  86. aura::Window* new_root) {
  87. if (!new_root) {
  88. // Submit an empty compositor frame if the notification becomes invisible to
  89. // notify Viz that it can release its reference to the existing notification
  90. // buffer. We can't just evict the surface, because LayerTreeFrameSinkHolder
  91. // needs to hold on to resources that were used in the previous frame, if it
  92. // was associated with a different local surface id.
  93. SubmitEmptyCompositorFrame();
  94. // Evict the current surface. We can't only submit
  95. // an empty compositor frame, because then when re-opening the message
  96. // center, Viz may think it can use the empty compositor frame to display.
  97. // This will force viz to wait the given deadline for the next notification
  98. // compositor frame when showing the message center. This is to prevent
  99. // flashes when opening the message center.
  100. aura::Env::GetInstance()
  101. ->context_factory()
  102. ->GetHostFrameSinkManager()
  103. ->EvictSurfaces({host_window()->GetSurfaceId()});
  104. // Allocate a new local surface id for the next compositor frame.
  105. host_window()->AllocateLocalSurfaceId();
  106. is_embedded_ = false;
  107. // Set the deadline to default so Viz waits a while for the notification
  108. // compositor frame to arrive before showing the message center.
  109. host_window()->layer()->SetShowSurface(
  110. host_window()->GetSurfaceId(), host_window()->bounds().size(),
  111. SK_ColorWHITE, cc::DeadlinePolicy::UseDefaultDeadline(),
  112. /*stretch_content_to_fill_bounds=*/false);
  113. }
  114. }
  115. } // namespace exo