[go: nahoru, domu]

CC Animation: Speed up AnimationTimeline PushPropertiesTo by using a hash map.

Use a hash map to store all the animation players for a given timeline.
This makes the average performance for PushPropertiesTo
to be O(n) instead of O(n^2).

Perf test: https://codereview.chromium.org/1679923004/
BUG=574859
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1680043002

Cr-Commit-Position: refs/heads/master@{#374326}
diff --git a/cc/animation/animation_timeline.cc b/cc/animation/animation_timeline.cc
index a5d320b..cb173310 100644
--- a/cc/animation/animation_timeline.cc
+++ b/cc/animation/animation_timeline.cc
@@ -19,8 +19,8 @@
 }
 
 AnimationTimeline::~AnimationTimeline() {
-  for (auto& player : players_)
-    player->SetAnimationTimeline(nullptr);
+  for (auto& kv : id_to_player_map_)
+    kv.second->SetAnimationTimeline(nullptr);
 }
 
 scoped_refptr<AnimationTimeline> AnimationTimeline::CreateImplInstance() const {
@@ -30,37 +30,32 @@
 
 void AnimationTimeline::SetAnimationHost(AnimationHost* animation_host) {
   animation_host_ = animation_host;
-  for (auto& player : players_)
-    player->SetAnimationHost(animation_host);
+  for (auto& kv : id_to_player_map_)
+    kv.second->SetAnimationHost(animation_host);
 }
 
 void AnimationTimeline::AttachPlayer(scoped_refptr<AnimationPlayer> player) {
+  DCHECK(player->id());
   player->SetAnimationHost(animation_host_);
-
   player->SetAnimationTimeline(this);
-  players_.push_back(player);
+  id_to_player_map_.insert(std::make_pair(player->id(), player));
 }
 
 void AnimationTimeline::DetachPlayer(scoped_refptr<AnimationPlayer> player) {
-  for (AnimationPlayerList::iterator iter = players_.begin();
-       iter != players_.end(); ++iter) {
-    if (iter->get() != player)
-      continue;
-
-    ErasePlayers(iter, iter + 1);
-    break;
-  }
+  DCHECK(player->id());
+  ErasePlayer(player);
+  id_to_player_map_.erase(player->id());
 }
 
 AnimationPlayer* AnimationTimeline::GetPlayerById(int player_id) const {
-  for (auto& player : players_)
-    if (player->id() == player_id)
-      return player.get();
-  return nullptr;
+  auto f = id_to_player_map_.find(player_id);
+  return f == id_to_player_map_.end() ? nullptr : f->second.get();
 }
 
 void AnimationTimeline::ClearPlayers() {
-  ErasePlayers(players_.begin(), players_.end());
+  for (auto& kv : id_to_player_map_)
+    ErasePlayer(kv.second);
+  id_to_player_map_.clear();
 }
 
 void AnimationTimeline::PushPropertiesTo(AnimationTimeline* timeline_impl) {
@@ -71,7 +66,8 @@
 
 void AnimationTimeline::PushAttachedPlayersToImplThread(
     AnimationTimeline* timeline_impl) const {
-  for (auto& player : players_) {
+  for (auto& kv : id_to_player_map_) {
+    auto& player = kv.second;
     AnimationPlayer* player_impl = timeline_impl->GetPlayerById(player->id());
     if (player_impl)
       continue;
@@ -83,33 +79,30 @@
 
 void AnimationTimeline::RemoveDetachedPlayersFromImplThread(
     AnimationTimeline* timeline_impl) const {
-  AnimationPlayerList& players_impl = timeline_impl->players_;
+  IdToPlayerMap& players_impl = timeline_impl->id_to_player_map_;
 
-  auto to_erase =
-      std::partition(players_impl.begin(), players_impl.end(),
-                     [this](AnimationPlayerList::value_type player_impl) {
-                       return GetPlayerById(player_impl->id());
-                     });
-
-  timeline_impl->ErasePlayers(to_erase, players_impl.end());
+  // Erase all the impl players which |this| doesn't have.
+  for (auto it = players_impl.begin(); it != players_impl.end();) {
+    if (GetPlayerById(it->second->id())) {
+      ++it;
+    } else {
+      timeline_impl->ErasePlayer(it->second);
+      it = players_impl.erase(it);
+    }
+  }
 }
 
-void AnimationTimeline::ErasePlayers(AnimationPlayerList::iterator begin,
-                                     AnimationPlayerList::iterator end) {
-  for (auto i = begin; i != end; ++i) {
-    auto& player = *i;
-    if (player->element_animations())
-      player->DetachLayer();
-    player->SetAnimationTimeline(nullptr);
-    player->SetAnimationHost(nullptr);
-  }
-
-  players_.erase(begin, end);
+void AnimationTimeline::ErasePlayer(scoped_refptr<AnimationPlayer> player) {
+  if (player->element_animations())
+    player->DetachLayer();
+  player->SetAnimationTimeline(nullptr);
+  player->SetAnimationHost(nullptr);
 }
 
 void AnimationTimeline::PushPropertiesToImplThread(
     AnimationTimeline* timeline_impl) {
-  for (auto& player : players_) {
+  for (auto& kv : id_to_player_map_) {
+    AnimationPlayer* player = kv.second.get();
     AnimationPlayer* player_impl = timeline_impl->GetPlayerById(player->id());
     if (player_impl)
       player->PushPropertiesTo(player_impl);