ca_transaction_observer.mm 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright 2018 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 "ui/accelerated_widget_mac/ca_transaction_observer.h"
  5. #include "base/no_destructor.h"
  6. #include "base/time/default_tick_clock.h"
  7. #include "base/trace_event/trace_event.h"
  8. #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
  9. #import <AppKit/AppKit.h>
  10. #import <CoreFoundation/CoreFoundation.h>
  11. #import <QuartzCore/QuartzCore.h>
  12. typedef NS_ENUM(unsigned int, CATransactionPhase) {
  13. kCATransactionPhasePreLayout,
  14. kCATransactionPhasePreCommit,
  15. kCATransactionPhasePostCommit,
  16. };
  17. @interface CATransaction ()
  18. + (void)addCommitHandler:(void (^)(void))block
  19. forPhase:(CATransactionPhase)phase;
  20. @end
  21. namespace ui {
  22. namespace {
  23. NSString* kRunLoopMode = @"Chrome CATransactionCoordinator commit handler";
  24. constexpr auto kPostCommitTimeout = base::Milliseconds(50);
  25. } // namespace
  26. CATransactionCoordinator& CATransactionCoordinator::Get() {
  27. static base::NoDestructor<CATransactionCoordinator> instance;
  28. return *instance;
  29. }
  30. void CATransactionCoordinator::SynchronizeImpl() {
  31. static bool registeredRunLoopMode = false;
  32. if (!registeredRunLoopMode) {
  33. CFRunLoopAddCommonMode(CFRunLoopGetCurrent(),
  34. static_cast<CFStringRef>(kRunLoopMode));
  35. registeredRunLoopMode = true;
  36. }
  37. if (active_)
  38. return;
  39. active_ = true;
  40. for (auto& observer : post_commit_observers_)
  41. observer->OnActivateForTransaction();
  42. [CATransaction addCommitHandler:^{
  43. PreCommitHandler();
  44. }
  45. forPhase:kCATransactionPhasePreCommit];
  46. [CATransaction addCommitHandler:^{
  47. PostCommitHandler();
  48. }
  49. forPhase:kCATransactionPhasePostCommit];
  50. }
  51. void CATransactionCoordinator::PreCommitHandler() {
  52. TRACE_EVENT0("ui", "CATransactionCoordinator: pre-commit handler");
  53. auto* clock = base::DefaultTickClock::GetInstance();
  54. const base::TimeTicks start_time = clock->NowTicks();
  55. while (true) {
  56. bool continue_waiting = false;
  57. base::TimeTicks deadline = start_time;
  58. for (auto& observer : pre_commit_observers_) {
  59. if (observer.ShouldWaitInPreCommit()) {
  60. continue_waiting = true;
  61. deadline = std::max(deadline, start_time + observer.PreCommitTimeout());
  62. }
  63. }
  64. if (!continue_waiting)
  65. break; // success
  66. base::TimeDelta time_left = deadline - clock->NowTicks();
  67. if (time_left <= base::Seconds(0))
  68. break; // timeout
  69. ui::WindowResizeHelperMac::Get()->WaitForSingleTaskToRun(time_left);
  70. }
  71. }
  72. void CATransactionCoordinator::PostCommitHandler() {
  73. TRACE_EVENT0("ui", "CATransactionCoordinator: post-commit handler");
  74. for (auto& observer : post_commit_observers_)
  75. observer->OnEnterPostCommit();
  76. auto* clock = base::DefaultTickClock::GetInstance();
  77. const base::TimeTicks deadline = clock->NowTicks() + kPostCommitTimeout;
  78. while (true) {
  79. bool continue_waiting = std::any_of(
  80. post_commit_observers_.begin(), post_commit_observers_.end(),
  81. std::mem_fn(&PostCommitObserver::ShouldWaitInPostCommit));
  82. if (!continue_waiting)
  83. break; // success
  84. base::TimeDelta time_left = deadline - clock->NowTicks();
  85. if (time_left <= base::Seconds(0))
  86. break; // timeout
  87. ui::WindowResizeHelperMac::Get()->WaitForSingleTaskToRun(time_left);
  88. }
  89. active_ = false;
  90. }
  91. CATransactionCoordinator::CATransactionCoordinator() = default;
  92. CATransactionCoordinator::~CATransactionCoordinator() = default;
  93. void CATransactionCoordinator::Synchronize() {
  94. if (disabled_for_testing_)
  95. return;
  96. SynchronizeImpl();
  97. }
  98. void CATransactionCoordinator::AddPreCommitObserver(
  99. PreCommitObserver* observer) {
  100. pre_commit_observers_.AddObserver(observer);
  101. }
  102. void CATransactionCoordinator::RemovePreCommitObserver(
  103. PreCommitObserver* observer) {
  104. pre_commit_observers_.RemoveObserver(observer);
  105. }
  106. void CATransactionCoordinator::AddPostCommitObserver(
  107. scoped_refptr<PostCommitObserver> observer) {
  108. DCHECK(!post_commit_observers_.count(observer));
  109. post_commit_observers_.insert(std::move(observer));
  110. }
  111. void CATransactionCoordinator::RemovePostCommitObserver(
  112. scoped_refptr<PostCommitObserver> observer) {
  113. DCHECK(post_commit_observers_.count(observer));
  114. post_commit_observers_.erase(std::move(observer));
  115. }
  116. } // namespace ui