summaryrefslogtreecommitdiff
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-09-01 11:08:40 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-01 12:16:21 +0000
commit03c549e0392f92c02536d3f86d5e1d8dfa3435ac (patch)
treefe49d170a929b34ba82cd10db1a0bd8e3760fa4b /chromium/cc
parent5d013f5804a0d91fcf6c626b2d6fb6eca5c845b0 (diff)
downloadqtwebengine-chromium-03c549e0392f92c02536d3f86d5e1d8dfa3435ac.tar.gz
BASELINE: Update Chromium to 91.0.4472.160
Change-Id: I0def1f08a2412aeed79a9ab95dd50eb5c3f65f31 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn10
-rw-r--r--chromium/cc/OWNERS2
-rw-r--r--chromium/cc/animation/animation.cc6
-rw-r--r--chromium/cc/animation/element_animations.cc3
-rw-r--r--chromium/cc/animation/element_animations_unittest.cc100
-rw-r--r--chromium/cc/animation/filter_animation_curve.cc93
-rw-r--r--chromium/cc/animation/filter_animation_curve.h1
-rw-r--r--chromium/cc/animation/filter_animation_curve_unittest.cc8
-rw-r--r--chromium/cc/animation/keyframe_effect.cc383
-rw-r--r--chromium/cc/animation/keyframe_effect.h25
-rw-r--r--chromium/cc/animation/worklet_animation_unittest.cc34
-rw-r--r--chromium/cc/base/devtools_instrumentation.cc9
-rw-r--r--chromium/cc/base/devtools_instrumentation.h33
-rw-r--r--chromium/cc/base/features.cc42
-rw-r--r--chromium/cc/base/features.h17
-rw-r--r--chromium/cc/base/math_util.cc1
-rw-r--r--chromium/cc/document_transition/document_transition_request.cc59
-rw-r--r--chromium/cc/document_transition/document_transition_request.h40
-rw-r--r--chromium/cc/document_transition/document_transition_request_unittest.cc39
-rw-r--r--chromium/cc/document_transition/document_transition_shared_element_id.h37
-rw-r--r--chromium/cc/input/browser_controls_offset_manager.cc36
-rw-r--r--chromium/cc/input/browser_controls_offset_manager.h12
-rw-r--r--chromium/cc/input/browser_controls_offset_manager_unittest.cc65
-rw-r--r--chromium/cc/input/scroll_snap_data.cc98
-rw-r--r--chromium/cc/input/scroll_snap_data.h3
-rw-r--r--chromium/cc/input/scroll_state.h8
-rw-r--r--chromium/cc/input/scroll_state_data.cc1
-rw-r--r--chromium/cc/input/scroll_state_data.h2
-rw-r--r--chromium/cc/input/threaded_input_handler.cc50
-rw-r--r--chromium/cc/input/threaded_input_handler.h2
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc9
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h1
-rw-r--r--chromium/cc/layers/layer_impl.cc2
-rw-r--r--chromium/cc/layers/layer_unittest.cc5
-rw-r--r--chromium/cc/layers/picture_layer.cc2
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc17
-rw-r--r--chromium/cc/layers/picture_layer_impl.h30
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc28
-rw-r--r--chromium/cc/layers/render_surface_impl.cc5
-rw-r--r--chromium/cc/layers/render_surface_impl.h4
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc5
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.cc71
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.h35
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter_unittest.cc174
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller.cc148
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller.h30
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc376
-rw-r--r--chromium/cc/metrics/compositor_timing_history.cc54
-rw-r--r--chromium/cc/metrics/compositor_timing_history.h11
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.cc35
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.h7
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker.cc17
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker.h3
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker_collection.cc4
-rw-r--r--chromium/cc/metrics/jank_injector.cc14
-rw-r--r--chromium/cc/metrics/jank_injector.h10
-rw-r--r--chromium/cc/metrics/jank_injector_unittest.cc1
-rw-r--r--chromium/cc/metrics/ukm_smoothness_data.h7
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc5
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h2
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc431
-rw-r--r--chromium/cc/paint/paint_filter.cc9
-rw-r--r--chromium/cc/paint/paint_flags.cc4
-rw-r--r--chromium/cc/paint/paint_image.h12
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc2
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc19
-rw-r--r--chromium/cc/paint/paint_op_reader.cc9
-rw-r--r--chromium/cc/paint/paint_shader.cc154
-rw-r--r--chromium/cc/paint/paint_shader.h17
-rw-r--r--chromium/cc/paint/scoped_raster_flags.cc4
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc7
-rw-r--r--chromium/cc/raster/raster_buffer_provider_unittest.cc1
-rw-r--r--chromium/cc/raster/single_thread_task_graph_runner.cc5
-rw-r--r--chromium/cc/scheduler/scheduler.cc79
-rw-r--r--chromium/cc/scheduler/scheduler.h16
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h1
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc19
-rw-r--r--chromium/cc/tiles/image_controller_unittest.cc5
-rw-r--r--chromium/cc/tiles/image_decode_cache.h2
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.cc26
-rw-r--r--chromium/cc/trees/damage_tracker.cc8
-rw-r--r--chromium/cc/trees/damage_tracker_unittest.cc187
-rw-r--r--chromium/cc/trees/debug_rect_history.cc1
-rw-r--r--chromium/cc/trees/draw_property_utils.cc20
-rw-r--r--chromium/cc/trees/effect_node.cc2
-rw-r--r--chromium/cc/trees/effect_node.h5
-rw-r--r--chromium/cc/trees/frame_rate_estimator.cc2
-rw-r--r--chromium/cc/trees/frame_rate_estimator.h1
-rw-r--r--chromium/cc/trees/frame_rate_estimator_unittest.cc24
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_client.h7
-rw-r--r--chromium/cc/trees/layer_tree_host.cc65
-rw-r--r--chromium/cc/trees/layer_tree_host.h33
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc65
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h20
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc70
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc65
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_readback.cc8
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc7
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc4
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc4
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc30
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc6
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc10
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc59
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc2
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc2
-rw-r--r--chromium/cc/trees/layer_tree_impl.h10
-rw-r--r--chromium/cc/trees/property_tree.cc18
-rw-r--r--chromium/cc/trees/property_tree.h5
-rw-r--r--chromium/cc/trees/property_tree_unittest.cc69
-rw-r--r--chromium/cc/trees/proxy_common.h1
-rw-r--r--chromium/cc/trees/proxy_impl.cc14
-rw-r--r--chromium/cc/trees/proxy_main.cc3
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc20
114 files changed, 2641 insertions, 1359 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index 3465bf70b6c..13098ad0074 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -35,6 +35,7 @@ cc_component("cc") {
"benchmarks/unittest_only_benchmark_impl.h",
"document_transition/document_transition_request.cc",
"document_transition/document_transition_request.h",
+ "document_transition/document_transition_shared_element_id.h",
"input/actively_scrolling_type.h",
"input/browser_controls_offset_manager.cc",
"input/browser_controls_offset_manager.h",
@@ -860,7 +861,14 @@ cc_test("cc_unittests") {
]
if (is_fuchsia) {
- manifest = "//build/config/fuchsia/gfx_tests.cmx"
+ additional_manifest_fragments = [
+ "//build/config/fuchsia/test/font_capabilities.test-cmx",
+
+ # TODO(crbug.com/1185811): Figure out why jit_capabilities is needed.
+ "//build/config/fuchsia/test/jit_capabilities.test-cmx",
+
+ "//build/config/fuchsia/test/vulkan_capabilities.test-cmx",
+ ]
}
if (enable_vulkan) {
diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS
index 6b427ed86d7..57a11c57c6f 100644
--- a/chromium/cc/OWNERS
+++ b/chromium/cc/OWNERS
@@ -7,7 +7,6 @@
set noparent
# layers
-danakj@chromium.org
pdr@chromium.org
wangxianzhu@chromium.org
@@ -57,5 +56,4 @@ sunnyps@chromium.org
vasilyt@chromium.org
# general
-danakj@chromium.org
vmpstr@chromium.org
diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc
index 0b8d96cd812..220347a9220 100644
--- a/chromium/cc/animation/animation.cc
+++ b/chromium/cc/animation/animation.cc
@@ -6,6 +6,7 @@
#include <inttypes.h>
#include <algorithm>
+#include <memory>
#include <string>
#include <utility>
@@ -32,7 +33,7 @@ Animation::Animation(int id, std::unique_ptr<KeyframeEffect> keyframe_effect)
: animation_host_(), animation_timeline_(), animation_delegate_(), id_(id) {
DCHECK(id_);
if (!keyframe_effect)
- keyframe_effect.reset(new KeyframeEffect(this));
+ keyframe_effect = std::make_unique<KeyframeEffect>(this);
keyframe_effect_ = std::move(keyframe_effect);
}
@@ -238,7 +239,8 @@ void Animation::ActivateKeyframeModels() {
KeyframeModel* Animation::GetKeyframeModel(
TargetProperty::Type target_property) const {
- return keyframe_effect_->GetKeyframeModel(target_property);
+ return KeyframeModel::ToCcKeyframeModel(
+ keyframe_effect_->GetKeyframeModel(target_property));
}
std::string Animation::ToString() const {
diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc
index c8e8637523c..a5e64cac011 100644
--- a/chromium/cc/animation/element_animations.cc
+++ b/chromium/cc/animation/element_animations.cc
@@ -570,7 +570,8 @@ PropertyToElementIdMap ElementAnimations::GetPropertyToElementIdMap() const {
static_cast<TargetProperty::Type>(property_index);
ElementId element_id_for_property;
for (auto& keyframe_effect : keyframe_effects_list_) {
- KeyframeModel* model = keyframe_effect.GetKeyframeModel(property);
+ KeyframeModel* model = KeyframeModel::ToCcKeyframeModel(
+ keyframe_effect.GetKeyframeModel(property));
if (model) {
// We deliberately use two branches here so that the DCHECK can
// differentiate between models with different element ids, and the case
diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc
index e5fecd65354..e151dc3db00 100644
--- a/chromium/cc/animation/element_animations_unittest.cc
+++ b/chromium/cc/animation/element_animations_unittest.cc
@@ -2539,11 +2539,13 @@ TEST_F(ElementAnimationsTest, NewlyPushedAnimationWaitsForActivation) {
animation_impl_->keyframe_effect()
->GetKeyframeModelById(keyframe_model_id)
->run_state());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_pending_elements());
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_active_elements());
animation_impl_->Tick(kInitialTickTime);
@@ -2567,11 +2569,13 @@ TEST_F(ElementAnimationsTest, NewlyPushedAnimationWaitsForActivation) {
EXPECT_EQ(0.f, client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE));
animation_impl_->ActivateKeyframeModels();
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_pending_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_active_elements());
animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
@@ -2607,11 +2611,13 @@ TEST_F(ElementAnimationsTest, ActivationBetweenAnimateAndUpdateState) {
animation_impl_->keyframe_effect()
->GetKeyframeModelById(keyframe_model_id)
->run_state());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_pending_elements());
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_active_elements());
animation_impl_->Tick(kInitialTickTime);
@@ -2623,11 +2629,13 @@ TEST_F(ElementAnimationsTest, ActivationBetweenAnimateAndUpdateState) {
EXPECT_EQ(0.f, client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE));
animation_impl_->ActivateKeyframeModels();
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_pending_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_active_elements());
animation_impl_->UpdateState(true, events.get());
@@ -3568,11 +3576,13 @@ TEST_F(ElementAnimationsTest, PushedDeletedAnimationWaitsForActivation) {
EXPECT_EQ(0.5f,
client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE));
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_pending_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_active_elements());
// Delete the animation on the main-thread animations.
@@ -3581,11 +3591,13 @@ TEST_F(ElementAnimationsTest, PushedDeletedAnimationWaitsForActivation) {
PushProperties();
// The animation should no longer affect pending elements.
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_pending_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ keyframe_model_id))
->affects_active_elements());
animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(500));
@@ -3644,17 +3656,21 @@ TEST_F(ElementAnimationsTest, StartAnimationsAffectingDifferentObservers) {
// The original animation should only affect active elements, and the new
// animation should only affect pending elements.
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(first_keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ first_keyframe_model_id))
->affects_pending_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(first_keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ first_keyframe_model_id))
->affects_active_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(second_keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ second_keyframe_model_id))
->affects_pending_elements());
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(second_keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ second_keyframe_model_id))
->affects_active_elements());
animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(500));
@@ -3682,17 +3698,21 @@ TEST_F(ElementAnimationsTest, StartAnimationsAffectingDifferentObservers) {
// The original animation no longer affect either elements, and the new
// animation should now affect both elements.
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(first_keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ first_keyframe_model_id))
->affects_pending_elements());
- EXPECT_FALSE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(first_keyframe_model_id)
+ EXPECT_FALSE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ first_keyframe_model_id))
->affects_active_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(second_keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ second_keyframe_model_id))
->affects_pending_elements());
- EXPECT_TRUE(animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(second_keyframe_model_id)
+ EXPECT_TRUE(KeyframeModel::ToCcKeyframeModel(
+ animation_impl_->keyframe_effect()->GetKeyframeModelById(
+ second_keyframe_model_id))
->affects_active_elements());
animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
diff --git a/chromium/cc/animation/filter_animation_curve.cc b/chromium/cc/animation/filter_animation_curve.cc
index 83d991c0662..38ee1e8d1b6 100644
--- a/chromium/cc/animation/filter_animation_curve.cc
+++ b/chromium/cc/animation/filter_animation_curve.cc
@@ -5,97 +5,10 @@
#include "cc/animation/filter_animation_curve.h"
#include "base/memory/ptr_util.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve-inl.h"
namespace cc {
-// TODO(crbug.com/747185): All code in this namespace duplicates code from
-// ui/gfx/keyframe/animation/ unnecessarily.
-namespace {
-
-template <class KeyframeType>
-void InsertKeyframe(std::unique_ptr<KeyframeType> keyframe,
- std::vector<std::unique_ptr<KeyframeType>>* keyframes) {
- // Usually, the keyframes will be added in order, so this loop would be
- // unnecessary and we should skip it if possible.
- if (!keyframes->empty() && keyframe->Time() < keyframes->back()->Time()) {
- for (size_t i = 0; i < keyframes->size(); ++i) {
- if (keyframe->Time() < keyframes->at(i)->Time()) {
- keyframes->insert(keyframes->begin() + i, std::move(keyframe));
- return;
- }
- }
- }
-
- keyframes->push_back(std::move(keyframe));
-}
-
-struct TimeValues {
- base::TimeDelta start_time;
- base::TimeDelta duration;
- double progress;
-};
-
-template <typename KeyframeType>
-TimeValues GetTimeValues(const KeyframeType& start_frame,
- const KeyframeType& end_frame,
- double scaled_duration,
- base::TimeDelta time) {
- TimeValues values;
- values.start_time = start_frame.Time() * scaled_duration;
- values.duration = (end_frame.Time() * scaled_duration) - values.start_time;
- const base::TimeDelta elapsed = time - values.start_time;
- values.progress = (elapsed.is_inf() || values.duration.is_zero())
- ? 1.0
- : (elapsed / values.duration);
- return values;
-}
-
-template <typename KeyframeType>
-base::TimeDelta TransformedAnimationTime(
- const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
- const std::unique_ptr<gfx::TimingFunction>& timing_function,
- double scaled_duration,
- base::TimeDelta time) {
- if (timing_function) {
- const auto values = GetTimeValues(*keyframes.front(), *keyframes.back(),
- scaled_duration, time);
- time = (values.duration * timing_function->GetValue(values.progress)) +
- values.start_time;
- }
-
- return time;
-}
-
-template <typename KeyframeType>
-size_t GetActiveKeyframe(
- const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
- double scaled_duration,
- base::TimeDelta time) {
- DCHECK_GE(keyframes.size(), 2ul);
- size_t i = 0;
- while ((i < keyframes.size() - 2) && // Last keyframe is never active.
- (time >= (keyframes[i + 1]->Time() * scaled_duration)))
- ++i;
-
- return i;
-}
-
-template <typename KeyframeType>
-double TransformedKeyframeProgress(
- const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
- double scaled_duration,
- base::TimeDelta time,
- size_t i) {
- const double progress =
- GetTimeValues(*keyframes[i], *keyframes[i + 1], scaled_duration, time)
- .progress;
- return keyframes[i]->timing_function()
- ? keyframes[i]->timing_function()->GetValue(progress)
- : progress;
-}
-
-} // namespace
-
void FilterAnimationCurve::Tick(base::TimeDelta t,
int property_id,
gfx::KeyframeModel* keyframe_model) const {
@@ -151,6 +64,10 @@ std::unique_ptr<FilterKeyframe> FilterKeyframe::Clone() const {
return FilterKeyframe::Create(Time(), Value(), std::move(func));
}
+base::TimeDelta KeyframedFilterAnimationCurve::TickInterval() const {
+ return ComputeTickInterval(timing_function_, scaled_duration(), keyframes_);
+}
+
void KeyframedFilterAnimationCurve::AddKeyframe(
std::unique_ptr<FilterKeyframe> keyframe) {
InsertKeyframe(std::move(keyframe), &keyframes_);
diff --git a/chromium/cc/animation/filter_animation_curve.h b/chromium/cc/animation/filter_animation_curve.h
index 0455d67df19..af8d7355a47 100644
--- a/chromium/cc/animation/filter_animation_curve.h
+++ b/chromium/cc/animation/filter_animation_curve.h
@@ -64,6 +64,7 @@ class CC_ANIMATION_EXPORT KeyframedFilterAnimationCurve
// AnimationCurve implementation
base::TimeDelta Duration() const override;
std::unique_ptr<gfx::AnimationCurve> Clone() const override;
+ base::TimeDelta TickInterval() const override;
// FilterAnimationCurve implementation
FilterOperations GetValue(base::TimeDelta t) const override;
diff --git a/chromium/cc/animation/filter_animation_curve_unittest.cc b/chromium/cc/animation/filter_animation_curve_unittest.cc
index e7401a78a11..81ef211d841 100644
--- a/chromium/cc/animation/filter_animation_curve_unittest.cc
+++ b/chromium/cc/animation/filter_animation_curve_unittest.cc
@@ -24,7 +24,7 @@ void ExpectBrightness(double brightness, const FilterOperations& filter) {
}
// Tests that a filter animation with one keyframe works as expected.
-TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) {
+TEST(FilterAnimationCurveTest, OneFilterKeyframe) {
std::unique_ptr<KeyframedFilterAnimationCurve> curve(
KeyframedFilterAnimationCurve::Create());
FilterOperations operations;
@@ -40,7 +40,7 @@ TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) {
}
// Tests that a filter animation with two keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, TwoFilterKeyframe) {
+TEST(FilterAnimationCurveTest, TwoFilterKeyframe) {
std::unique_ptr<KeyframedFilterAnimationCurve> curve(
KeyframedFilterAnimationCurve::Create());
FilterOperations operations1;
@@ -60,7 +60,7 @@ TEST(KeyframedAnimationCurveTest, TwoFilterKeyframe) {
}
// Tests that a filter animation with three keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, ThreeFilterKeyframe) {
+TEST(FilterAnimationCurveTest, ThreeFilterKeyframe) {
std::unique_ptr<KeyframedFilterAnimationCurve> curve(
KeyframedFilterAnimationCurve::Create());
FilterOperations operations1;
@@ -86,7 +86,7 @@ TEST(KeyframedAnimationCurveTest, ThreeFilterKeyframe) {
// Tests that a filter animation with multiple keys at a given time works
// sanely.
-TEST(KeyframedAnimationCurveTest, RepeatedFilterKeyTimes) {
+TEST(FilterAnimationCurveTest, RepeatedFilterKeyTimes) {
std::unique_ptr<KeyframedFilterAnimationCurve> curve(
KeyframedFilterAnimationCurve::Create());
// A step function.
diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc
index ef4ec75cb45..9b34b0c2adb 100644
--- a/chromium/cc/animation/keyframe_effect.cc
+++ b/chromium/cc/animation/keyframe_effect.cc
@@ -35,13 +35,14 @@ bool NeedsFinishedEvent(KeyframeModel* keyframe_model) {
// Returns indices for keyframe_models that have matching group id.
std::vector<size_t> FindAnimationsWithSameGroupId(
- const std::vector<std::unique_ptr<KeyframeModel>>& keyframe_models,
+ const std::vector<std::unique_ptr<gfx::KeyframeModel>>& keyframe_models,
int group_id) {
std::vector<size_t> group;
for (size_t i = 0; i < keyframe_models.size(); ++i) {
- if (keyframe_models[i]->group() != group_id)
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_models[i].get());
+ if (cc_keyframe_model->group() != group_id)
continue;
-
group.push_back(i);
}
return group;
@@ -110,7 +111,7 @@ void KeyframeEffect::Tick(base::TimeTicks monotonic_time) {
if (needs_to_start_keyframe_models_)
StartKeyframeModels(monotonic_time);
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
TickKeyframeModel(monotonic_time, keyframe_model.get());
}
@@ -118,21 +119,6 @@ void KeyframeEffect::Tick(base::TimeTicks monotonic_time) {
element_animations_->UpdateClientAnimationState();
}
-void KeyframeEffect::TickKeyframeModel(base::TimeTicks monotonic_time,
- KeyframeModel* keyframe_model) {
- if ((keyframe_model->run_state() != gfx::KeyframeModel::STARTING &&
- keyframe_model->run_state() != gfx::KeyframeModel::RUNNING &&
- keyframe_model->run_state() != gfx::KeyframeModel::PAUSED) ||
- !keyframe_model->InEffect(monotonic_time)) {
- return;
- }
-
- gfx::AnimationCurve* curve = keyframe_model->curve();
- base::TimeDelta trimmed =
- keyframe_model->TrimTimeToCurrentIteration(monotonic_time);
- curve->Tick(trimmed, keyframe_model->TargetProperty(), keyframe_model);
-}
-
void KeyframeEffect::RemoveFromTicking() {
is_ticking_ = false;
// Resetting last_tick_time_ here ensures that calling ::UpdateState
@@ -186,7 +172,7 @@ void KeyframeEffect::UpdateTickingState() {
void KeyframeEffect::Pause(base::TimeDelta pause_offset,
PauseCondition pause_condition) {
bool did_pause = false;
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
// TODO(crbug.com/1076012): KeyframeEffect is paused with local time for
// scroll-linked animations. To make sure the start event of a keyframe
// model is sent to blink, we should not set its run state to PAUSED until
@@ -208,17 +194,22 @@ void KeyframeEffect::Pause(base::TimeDelta pause_offset,
}
void KeyframeEffect::AddKeyframeModel(
- std::unique_ptr<KeyframeModel> keyframe_model) {
- DCHECK(!keyframe_model->is_impl_only() ||
+ std::unique_ptr<gfx::KeyframeModel> keyframe_model) {
+ KeyframeModel* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+ DCHECK(!cc_keyframe_model->is_impl_only() ||
keyframe_model->TargetProperty() == TargetProperty::SCROLL_OFFSET);
// This is to make sure that keyframe models in the same group, i.e., start
// together, don't animate the same property.
- DCHECK(std::none_of(keyframe_models_.begin(), keyframe_models_.end(),
+ DCHECK(std::none_of(keyframe_models().begin(), keyframe_models().end(),
[&](const auto& existing_keyframe_model) {
+ auto* cc_existing_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(
+ existing_keyframe_model.get());
return keyframe_model->TargetProperty() ==
existing_keyframe_model->TargetProperty() &&
- keyframe_model->group() ==
- existing_keyframe_model->group();
+ cc_keyframe_model->group() ==
+ cc_existing_keyframe_model->group();
}));
if (keyframe_model->TargetProperty() == TargetProperty::SCROLL_OFFSET) {
@@ -226,17 +217,19 @@ void KeyframeEffect::AddKeyframeModel(
// same scrolling element as this would result in multiple automated
// scrolls.
DCHECK(std::none_of(
- keyframe_models_.begin(), keyframe_models_.end(),
+ keyframe_models().begin(), keyframe_models().end(),
[&](const auto& existing_keyframe_model) {
- return existing_keyframe_model->TargetProperty() ==
+ auto* cc_existing_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(existing_keyframe_model.get());
+ return cc_existing_keyframe_model->TargetProperty() ==
TargetProperty::SCROLL_OFFSET &&
- !existing_keyframe_model->is_finished() &&
- (!existing_keyframe_model->is_controlling_instance() ||
- existing_keyframe_model->affects_pending_elements());
+ !cc_existing_keyframe_model->is_finished() &&
+ (!cc_existing_keyframe_model->is_controlling_instance() ||
+ cc_existing_keyframe_model->affects_pending_elements());
}));
}
- keyframe_models_.push_back(std::move(keyframe_model));
+ gfx::KeyframeEffect::AddKeyframeModel(std::move(keyframe_model));
if (has_bound_element_animations()) {
KeyframeModelAdded();
@@ -246,7 +239,7 @@ void KeyframeEffect::AddKeyframeModel(
void KeyframeEffect::PauseKeyframeModel(int keyframe_model_id,
base::TimeDelta time_offset) {
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
if (keyframe_model->id() == keyframe_model_id) {
keyframe_model->Pause(time_offset);
}
@@ -258,41 +251,9 @@ void KeyframeEffect::PauseKeyframeModel(int keyframe_model_id,
}
}
-void KeyframeEffect::RemoveKeyframeModel(int keyframe_model_id) {
- bool keyframe_model_removed = false;
-
- // Since we want to use the KeyframeModels that we're going to remove, we
- // need to use a stable_partition here instead of remove_if. remove_if leaves
- // the removed items in an unspecified state.
- auto keyframe_models_to_remove = std::stable_partition(
- keyframe_models_.begin(), keyframe_models_.end(),
- [keyframe_model_id](
- const std::unique_ptr<KeyframeModel>& keyframe_model) {
- return keyframe_model->id() != keyframe_model_id;
- });
- for (auto it = keyframe_models_to_remove; it != keyframe_models_.end();
- ++it) {
- if ((*it)->TargetProperty() == TargetProperty::SCROLL_OFFSET) {
- if (has_bound_element_animations())
- scroll_offset_animation_was_interrupted_ = true;
- } else if (!(*it)->is_finished()) {
- keyframe_model_removed = true;
- }
- }
-
- keyframe_models_.erase(keyframe_models_to_remove, keyframe_models_.end());
-
- if (has_bound_element_animations()) {
- UpdateTickingState();
- if (keyframe_model_removed)
- element_animations_->UpdateClientAnimationState();
- animation_->SetNeedsCommit();
- SetNeedsPushProperties();
- }
-}
-
void KeyframeEffect::AbortKeyframeModel(int keyframe_model_id) {
- if (KeyframeModel* keyframe_model = GetKeyframeModelById(keyframe_model_id)) {
+ if (gfx::KeyframeModel* keyframe_model =
+ GetKeyframeModelById(keyframe_model_id)) {
if (!keyframe_model->is_finished()) {
keyframe_model->SetRunState(gfx::KeyframeModel::ABORTED,
last_tick_time_.value_or(base::TimeTicks()));
@@ -314,12 +275,14 @@ void KeyframeEffect::AbortKeyframeModelsWithProperty(
DCHECK(target_property == TargetProperty::SCROLL_OFFSET);
bool aborted_keyframe_model = false;
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
if (keyframe_model->TargetProperty() == target_property &&
!keyframe_model->is_finished()) {
// Currently only impl-only scroll offset KeyframeModels can be completed
// on the main thread.
- if (needs_completion && keyframe_model->is_impl_only()) {
+ if (needs_completion &&
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->is_impl_only()) {
keyframe_model->SetRunState(
gfx::KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION,
last_tick_time_.value_or(base::TimeTicks()));
@@ -344,13 +307,15 @@ void KeyframeEffect::ActivateKeyframeModels() {
DCHECK(has_bound_element_animations());
bool keyframe_model_activated = false;
- for (auto& keyframe_model : keyframe_models_) {
- if (keyframe_model->affects_active_elements() !=
- keyframe_model->affects_pending_elements()) {
+ for (auto& keyframe_model : keyframe_models()) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+ if (cc_keyframe_model->affects_active_elements() !=
+ cc_keyframe_model->affects_pending_elements()) {
keyframe_model_activated = true;
}
- keyframe_model->set_affects_active_elements(
- keyframe_model->affects_pending_elements());
+ cc_keyframe_model->set_affects_active_elements(
+ cc_keyframe_model->affects_pending_elements());
}
if (keyframe_model_activated)
@@ -366,7 +331,7 @@ void KeyframeEffect::KeyframeModelAdded() {
needs_to_start_keyframe_models_ = true;
UpdateTickingState();
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
element_animations_->AttachToCurve(keyframe_model->curve());
}
element_animations_->UpdateClientAnimationState();
@@ -375,7 +340,8 @@ void KeyframeEffect::KeyframeModelAdded() {
bool KeyframeEffect::DispatchAnimationEventToKeyframeModel(
const AnimationEvent& event) {
DCHECK(!event.is_impl_only);
- KeyframeModel* keyframe_model = GetKeyframeModelById(event.uid.model_id);
+ KeyframeModel* keyframe_model = KeyframeModel::ToCcKeyframeModel(
+ GetKeyframeModelById(event.uid.model_id));
bool dispatched = false;
switch (event.type) {
case AnimationEvent::STARTED:
@@ -434,7 +400,7 @@ bool KeyframeEffect::DispatchAnimationEventToKeyframeModel(
}
bool KeyframeEffect::HasTickingKeyframeModel() const {
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
if (!keyframe_model->is_finished())
return true;
}
@@ -442,14 +408,14 @@ bool KeyframeEffect::HasTickingKeyframeModel() const {
}
bool KeyframeEffect::AffectsCustomProperty() const {
- for (const auto& it : keyframe_models_)
+ for (const auto& it : keyframe_models())
if (it->TargetProperty() == TargetProperty::CSS_CUSTOM_PROPERTY)
return true;
return false;
}
bool KeyframeEffect::HasNonDeletedKeyframeModel() const {
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
if (keyframe_model->run_state() != gfx::KeyframeModel::WAITING_FOR_DELETION)
return true;
}
@@ -457,7 +423,7 @@ bool KeyframeEffect::HasNonDeletedKeyframeModel() const {
}
bool KeyframeEffect::AnimationsPreserveAxisAlignment() const {
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
if (keyframe_model->is_finished())
continue;
@@ -469,14 +435,17 @@ bool KeyframeEffect::AnimationsPreserveAxisAlignment() const {
float KeyframeEffect::MaximumScale(ElementListType list_type) const {
float maximum_scale = kInvalidScale;
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
if (keyframe_model->is_finished())
continue;
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+
if ((list_type == ElementListType::ACTIVE &&
- !keyframe_model->affects_active_elements()) ||
+ !cc_keyframe_model->affects_active_elements()) ||
(list_type == ElementListType::PENDING &&
- !keyframe_model->affects_pending_elements()))
+ !cc_keyframe_model->affects_pending_elements()))
continue;
float curve_maximum_scale = kInvalidScale;
@@ -489,13 +458,15 @@ float KeyframeEffect::MaximumScale(ElementListType list_type) const {
bool KeyframeEffect::IsPotentiallyAnimatingProperty(
TargetProperty::Type target_property,
ElementListType list_type) const {
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
if (!keyframe_model->is_finished() &&
keyframe_model->TargetProperty() == target_property) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
if ((list_type == ElementListType::ACTIVE &&
- keyframe_model->affects_active_elements()) ||
+ cc_keyframe_model->affects_active_elements()) ||
(list_type == ElementListType::PENDING &&
- keyframe_model->affects_pending_elements()))
+ cc_keyframe_model->affects_pending_elements()))
return true;
}
}
@@ -505,50 +476,37 @@ bool KeyframeEffect::IsPotentiallyAnimatingProperty(
bool KeyframeEffect::IsCurrentlyAnimatingProperty(
TargetProperty::Type target_property,
ElementListType list_type) const {
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
if (!keyframe_model->is_finished() &&
- keyframe_model->InEffect(last_tick_time_.value_or(base::TimeTicks())) &&
+ cc_keyframe_model->InEffect(
+ last_tick_time_.value_or(base::TimeTicks())) &&
keyframe_model->TargetProperty() == target_property) {
if ((list_type == ElementListType::ACTIVE &&
- keyframe_model->affects_active_elements()) ||
+ cc_keyframe_model->affects_active_elements()) ||
(list_type == ElementListType::PENDING &&
- keyframe_model->affects_pending_elements()))
+ cc_keyframe_model->affects_pending_elements()))
return true;
}
}
return false;
}
-KeyframeModel* KeyframeEffect::GetKeyframeModel(
- TargetProperty::Type target_property) const {
- for (size_t i = 0; i < keyframe_models_.size(); ++i) {
- size_t index = keyframe_models_.size() - i - 1;
- if (keyframe_models_[index]->TargetProperty() == target_property)
- return keyframe_models_[index].get();
- }
- return nullptr;
-}
-
-KeyframeModel* KeyframeEffect::GetKeyframeModelById(
- int keyframe_model_id) const {
- for (auto& keyframe_model : keyframe_models_)
- if (keyframe_model->id() == keyframe_model_id)
- return keyframe_model.get();
- return nullptr;
-}
-
void KeyframeEffect::GetPropertyAnimationState(
PropertyAnimationState* pending_state,
PropertyAnimationState* active_state) const {
pending_state->Clear();
active_state->Clear();
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
if (!keyframe_model->is_finished()) {
- bool in_effect =
- keyframe_model->InEffect(last_tick_time_.value_or(base::TimeTicks()));
- bool active = keyframe_model->affects_active_elements();
- bool pending = keyframe_model->affects_pending_elements();
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+ bool in_effect = cc_keyframe_model->InEffect(
+ last_tick_time_.value_or(base::TimeTicks()));
+ bool active = cc_keyframe_model->affects_active_elements();
+ bool pending = cc_keyframe_model->affects_pending_elements();
int property = keyframe_model->TargetProperty();
if (pending)
@@ -568,11 +526,11 @@ void KeyframeEffect::MarkAbortedKeyframeModelsForDeletion(
KeyframeEffect* keyframe_effect_impl) {
bool keyframe_model_aborted = false;
- auto& keyframe_models_impl = keyframe_effect_impl->keyframe_models_;
+ auto& keyframe_models_impl = keyframe_effect_impl->keyframe_models();
for (const auto& keyframe_model_impl : keyframe_models_impl) {
// If the keyframe_model has been aborted on the main thread, mark it for
// deletion.
- if (KeyframeModel* keyframe_model =
+ if (gfx::KeyframeModel* keyframe_model =
GetKeyframeModelById(keyframe_model_impl->id())) {
if (keyframe_model->run_state() == gfx::KeyframeModel::ABORTED) {
keyframe_model_impl->SetRunState(
@@ -591,29 +549,28 @@ void KeyframeEffect::MarkAbortedKeyframeModelsForDeletion(
}
void KeyframeEffect::PurgeKeyframeModelsMarkedForDeletion(bool impl_only) {
- base::EraseIf(
- keyframe_models_,
- [impl_only](const std::unique_ptr<KeyframeModel>& keyframe_model) {
- return keyframe_model->run_state() ==
- gfx::KeyframeModel::WAITING_FOR_DELETION &&
- (!impl_only || keyframe_model->is_impl_only());
- });
+ base::EraseIf(keyframe_models(), [impl_only](const auto& keyframe_model) {
+ return keyframe_model->run_state() ==
+ gfx::KeyframeModel::WAITING_FOR_DELETION &&
+ (!impl_only || KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->is_impl_only());
+ });
}
void KeyframeEffect::PurgeDeletedKeyframeModels() {
- base::EraseIf(keyframe_models_,
- [](const std::unique_ptr<KeyframeModel>& keyframe_model) {
- return keyframe_model->run_state() ==
- gfx::KeyframeModel::WAITING_FOR_DELETION &&
- !keyframe_model->affects_pending_elements();
- });
+ base::EraseIf(keyframe_models(), [](const auto& keyframe_model) {
+ return keyframe_model->run_state() ==
+ gfx::KeyframeModel::WAITING_FOR_DELETION &&
+ !KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->affects_pending_elements();
+ });
}
void KeyframeEffect::PushNewKeyframeModelsToImplThread(
KeyframeEffect* keyframe_effect_impl) const {
// Any new KeyframeModels owned by the main thread's Animation are
// cloned and added to the impl thread's Animation.
- for (const auto& keyframe_model : keyframe_models_) {
+ for (const auto& keyframe_model : keyframe_models()) {
// If the keyframe_model is finished, do not copy it over to impl since the
// impl instance, if there was one, was just removed in
// |RemoveKeyframeModelsCompletedOnMainThread|.
@@ -647,7 +604,8 @@ void KeyframeEffect::PushNewKeyframeModelsToImplThread(
gfx::KeyframeModel::RunState initial_run_state =
gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY;
std::unique_ptr<KeyframeModel> to_add(
- keyframe_model->CreateImplInstance(initial_run_state));
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->CreateImplInstance(initial_run_state));
DCHECK(!to_add->needs_synchronized_start_time());
to_add->set_affects_active_elements(false);
keyframe_effect_impl->AddKeyframeModel(std::move(to_add));
@@ -655,13 +613,13 @@ void KeyframeEffect::PushNewKeyframeModelsToImplThread(
}
namespace {
-bool IsCompleted(KeyframeModel* keyframe_model,
+bool IsCompleted(gfx::KeyframeModel* keyframe_model,
const KeyframeEffect* main_thread_keyframe_effect) {
- if (keyframe_model->is_impl_only()) {
+ if (KeyframeModel::ToCcKeyframeModel(keyframe_model)->is_impl_only()) {
return (keyframe_model->run_state() ==
gfx::KeyframeModel::WAITING_FOR_DELETION);
} else {
- KeyframeModel* main_thread_keyframe_model =
+ gfx::KeyframeModel* main_thread_keyframe_model =
main_thread_keyframe_effect->GetKeyframeModelById(keyframe_model->id());
return !main_thread_keyframe_model ||
main_thread_keyframe_model->is_finished();
@@ -677,10 +635,10 @@ void KeyframeEffect::RemoveKeyframeModelsCompletedOnMainThread(
// elements, and should stop affecting active elements after the next call
// to ActivateKeyframeEffects. If already WAITING_FOR_DELETION, they can be
// removed immediately.
- for (const std::unique_ptr<KeyframeModel>& keyframe_model :
- keyframe_effect_impl->keyframe_models_) {
+ for (auto& keyframe_model : keyframe_effect_impl->keyframe_models()) {
if (IsCompleted(keyframe_model.get(), this)) {
- keyframe_model->set_affects_pending_elements(false);
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->set_affects_pending_elements(false);
keyframe_model_completed = true;
}
}
@@ -728,11 +686,12 @@ void KeyframeEffect::PushPropertiesTo(KeyframeEffect* keyframe_effect_impl) {
// Now that the keyframe model lists are synchronized, push the properties for
// the individual KeyframeModels.
- for (const auto& keyframe_model : keyframe_models_) {
- KeyframeModel* current_impl =
- keyframe_effect_impl->GetKeyframeModelById(keyframe_model->id());
+ for (const auto& keyframe_model : keyframe_models()) {
+ KeyframeModel* current_impl = KeyframeModel::ToCcKeyframeModel(
+ keyframe_effect_impl->GetKeyframeModelById(keyframe_model->id()));
if (current_impl)
- keyframe_model->PushPropertiesTo(current_impl);
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->PushPropertiesTo(current_impl);
}
keyframe_effect_impl->UpdateTickingState();
@@ -740,17 +699,18 @@ void KeyframeEffect::PushPropertiesTo(KeyframeEffect* keyframe_effect_impl) {
std::string KeyframeEffect::KeyframeModelsToString() const {
std::string str;
- for (size_t i = 0; i < keyframe_models_.size(); i++) {
+ for (size_t i = 0; i < keyframe_models().size(); i++) {
if (i > 0)
str.append(", ");
- str.append(keyframe_models_[i]->ToString());
+ str.append(KeyframeModel::ToCcKeyframeModel(keyframe_models()[i].get())
+ ->ToString());
}
return str;
}
base::TimeDelta KeyframeEffect::MinimumTickInterval() const {
base::TimeDelta min_interval = base::TimeDelta::Max();
- for (const auto& model : keyframe_models_) {
+ for (const auto& model : keyframe_models()) {
base::TimeDelta interval = model->curve()->TickInterval();
if (interval.is_zero())
return interval;
@@ -760,6 +720,30 @@ base::TimeDelta KeyframeEffect::MinimumTickInterval() const {
return min_interval;
}
+void KeyframeEffect::RemoveKeyframeModelRange(
+ typename KeyframeModels::iterator to_remove_begin,
+ typename KeyframeModels::iterator to_remove_end) {
+ bool keyframe_model_removed = false;
+ for (auto it = to_remove_begin; it != to_remove_end; ++it) {
+ if ((*it)->TargetProperty() == TargetProperty::SCROLL_OFFSET) {
+ if (has_bound_element_animations())
+ scroll_offset_animation_was_interrupted_ = true;
+ } else if (!(*it)->is_finished()) {
+ keyframe_model_removed = true;
+ }
+ }
+
+ gfx::KeyframeEffect::RemoveKeyframeModelRange(to_remove_begin, to_remove_end);
+
+ if (has_bound_element_animations()) {
+ UpdateTickingState();
+ if (keyframe_model_removed)
+ element_animations_->UpdateClientAnimationState();
+ animation_->SetNeedsCommit();
+ SetNeedsPushProperties();
+ }
+}
+
void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
DCHECK(needs_to_start_keyframe_models_);
needs_to_start_keyframe_models_ = false;
@@ -769,19 +753,20 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
gfx::TargetProperties blocked_properties_for_pending_elements;
std::vector<size_t> keyframe_models_waiting_for_target;
- keyframe_models_waiting_for_target.reserve(keyframe_models_.size());
- for (size_t i = 0; i < keyframe_models_.size(); ++i) {
- auto& keyframe_model = keyframe_models_[i];
- if (keyframe_model->run_state() == gfx::KeyframeModel::STARTING ||
- keyframe_model->run_state() == gfx::KeyframeModel::RUNNING) {
- int property = keyframe_model->TargetProperty();
- if (keyframe_model->affects_active_elements()) {
+ keyframe_models_waiting_for_target.reserve(keyframe_models().size());
+ for (size_t i = 0; i < keyframe_models().size(); ++i) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_models()[i].get());
+ if (cc_keyframe_model->run_state() == gfx::KeyframeModel::STARTING ||
+ cc_keyframe_model->run_state() == gfx::KeyframeModel::RUNNING) {
+ int property = cc_keyframe_model->TargetProperty();
+ if (cc_keyframe_model->affects_active_elements()) {
blocked_properties_for_active_elements[property] = true;
}
- if (keyframe_model->affects_pending_elements()) {
+ if (cc_keyframe_model->affects_pending_elements()) {
blocked_properties_for_pending_elements[property] = true;
}
- } else if (keyframe_model->run_state() ==
+ } else if (cc_keyframe_model->run_state() ==
gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY) {
keyframe_models_waiting_for_target.push_back(i);
}
@@ -792,7 +777,8 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
// should all also be in the list of KeyframeModels).
size_t keyframe_model_index = keyframe_models_waiting_for_target[i];
KeyframeModel* keyframe_model_waiting_for_target =
- keyframe_models_[keyframe_model_index].get();
+ KeyframeModel::ToCcKeyframeModel(
+ keyframe_models()[keyframe_model_index].get());
// Check for the run state again even though the keyframe_model was waiting
// for target because it might have changed the run state while handling
// previous keyframe_model in this loop (if they belong to same group).
@@ -805,15 +791,17 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
keyframe_model_waiting_for_target->affects_pending_elements();
enqueued_properties[keyframe_model_waiting_for_target->TargetProperty()] =
true;
- for (size_t j = keyframe_model_index + 1; j < keyframe_models_.size();
+ for (size_t j = keyframe_model_index + 1; j < keyframe_models().size();
++j) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_models()[j].get());
if (keyframe_model_waiting_for_target->group() ==
- keyframe_models_[j]->group()) {
- enqueued_properties[keyframe_models_[j]->TargetProperty()] = true;
+ cc_keyframe_model->group()) {
+ enqueued_properties[cc_keyframe_model->TargetProperty()] = true;
affects_active_elements |=
- keyframe_models_[j]->affects_active_elements();
+ cc_keyframe_model->affects_active_elements();
affects_pending_elements |=
- keyframe_models_[j]->affects_pending_elements();
+ cc_keyframe_model->affects_pending_elements();
}
}
@@ -846,12 +834,14 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
if (null_intersection) {
keyframe_model_waiting_for_target->SetRunState(
gfx::KeyframeModel::STARTING, monotonic_time);
- for (size_t j = keyframe_model_index + 1; j < keyframe_models_.size();
+ for (size_t j = keyframe_model_index + 1; j < keyframe_models().size();
++j) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_models()[j].get());
if (keyframe_model_waiting_for_target->group() ==
- keyframe_models_[j]->group()) {
- keyframe_models_[j]->SetRunState(gfx::KeyframeModel::STARTING,
- monotonic_time);
+ cc_keyframe_model->group()) {
+ cc_keyframe_model->SetRunState(gfx::KeyframeModel::STARTING,
+ monotonic_time);
}
}
} else {
@@ -862,23 +852,27 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
}
void KeyframeEffect::PromoteStartedKeyframeModels(AnimationEvents* events) {
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
if (keyframe_model->run_state() == gfx::KeyframeModel::STARTING &&
- keyframe_model->affects_active_elements()) {
- keyframe_model->SetRunState(gfx::KeyframeModel::RUNNING,
- last_tick_time_.value_or(base::TimeTicks()));
- if (!keyframe_model->has_set_start_time() &&
- !keyframe_model->needs_synchronized_start_time())
- keyframe_model->set_start_time(
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get())
+ ->affects_active_elements()) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+ cc_keyframe_model->SetRunState(
+ gfx::KeyframeModel::RUNNING,
+ last_tick_time_.value_or(base::TimeTicks()));
+ if (!cc_keyframe_model->has_set_start_time() &&
+ !cc_keyframe_model->needs_synchronized_start_time())
+ cc_keyframe_model->set_start_time(
last_tick_time_.value_or(base::TimeTicks()));
base::TimeTicks start_time;
- if (keyframe_model->has_set_start_time())
- start_time = keyframe_model->start_time();
+ if (cc_keyframe_model->has_set_start_time())
+ start_time = cc_keyframe_model->start_time();
else
start_time = last_tick_time_.value_or(base::TimeTicks());
- GenerateEvent(events, *keyframe_model, AnimationEvent::STARTED,
+ GenerateEvent(events, *cc_keyframe_model, AnimationEvent::STARTED,
start_time);
}
}
@@ -899,50 +893,52 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
// we don't have an events vector, we must ensure that non-aborted
// KeyframeModels have received a finished event before marking them for
// deletion.
- for (size_t i = 0; i < keyframe_models_.size(); i++) {
- KeyframeModel* keyframe_model = keyframe_models_[i].get();
- if (keyframe_model->run_state() == gfx::KeyframeModel::ABORTED) {
- GenerateEvent(events, *keyframe_model, AnimationEvent::ABORTED,
+ for (auto& keyframe_model : keyframe_models()) {
+ KeyframeModel* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+ if (cc_keyframe_model->run_state() == gfx::KeyframeModel::ABORTED) {
+ GenerateEvent(events, *cc_keyframe_model, AnimationEvent::ABORTED,
monotonic_time);
// If this is the controlling instance or it has already received finish
// event, keyframe model can be marked for deletion.
- if (!NeedsFinishedEvent(keyframe_model))
- MarkForDeletion(keyframe_model);
+ if (!NeedsFinishedEvent(cc_keyframe_model))
+ MarkForDeletion(cc_keyframe_model);
continue;
}
// If this is an aborted controlling instance that need completion on the
// main thread, generate takeover event.
- if (keyframe_model->is_controlling_instance() &&
- keyframe_model->run_state() ==
+ if (cc_keyframe_model->is_controlling_instance() &&
+ cc_keyframe_model->run_state() ==
gfx::KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION) {
- GenerateTakeoverEventForScrollAnimation(events, *keyframe_model,
+ GenerateTakeoverEventForScrollAnimation(events, *cc_keyframe_model,
monotonic_time);
// Remove the keyframe model from the impl thread.
- MarkForDeletion(keyframe_model);
+ MarkForDeletion(cc_keyframe_model);
continue;
}
- if (keyframe_model->run_state() != gfx::KeyframeModel::FINISHED)
+ if (cc_keyframe_model->run_state() != gfx::KeyframeModel::FINISHED)
continue;
// Since deleting an animation on the main thread leads to its deletion
// on the impl thread, we only mark a FINISHED main thread animation for
// deletion once it has received a FINISHED event from the impl thread.
- if (NeedsFinishedEvent(keyframe_model))
+ if (NeedsFinishedEvent(cc_keyframe_model))
continue;
// If a keyframe model is finished, and not already marked for deletion,
// find out if all other keyframe models in the same group are also
// finished.
std::vector<size_t> keyframe_models_in_same_group =
- FindAnimationsWithSameGroupId(keyframe_models_,
- keyframe_model->group());
+ FindAnimationsWithSameGroupId(keyframe_models(),
+ cc_keyframe_model->group());
bool a_keyframe_model_in_same_group_is_not_finished = std::any_of(
keyframe_models_in_same_group.cbegin(),
keyframe_models_in_same_group.cend(), [&](size_t index) {
- KeyframeModel* keyframe_model = keyframe_models_[index].get();
+ auto* keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_models()[index].get());
return !keyframe_model->is_finished() ||
(keyframe_model->run_state() == gfx::KeyframeModel::FINISHED &&
NeedsFinishedEvent(keyframe_model));
@@ -956,7 +952,8 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
// ensures we don't try to delete them again.
for (size_t j = 0; j < keyframe_models_in_same_group.size(); ++j) {
KeyframeModel* same_group_keyframe_model =
- keyframe_models_[keyframe_models_in_same_group[j]].get();
+ KeyframeModel::ToCcKeyframeModel(
+ keyframe_models()[keyframe_models_in_same_group[j]].get());
// Skip any keyframe model in this group which is already processed.
if (same_group_keyframe_model->run_state() ==
@@ -981,15 +978,18 @@ void KeyframeEffect::MarkFinishedKeyframeModels(
DCHECK(has_bound_element_animations());
bool keyframe_model_finished = false;
- for (auto& keyframe_model : keyframe_models_) {
+ for (auto& keyframe_model : keyframe_models()) {
if (!keyframe_model->is_finished() &&
keyframe_model->IsFinishedAt(monotonic_time)) {
keyframe_model->SetRunState(gfx::KeyframeModel::FINISHED, monotonic_time);
keyframe_model_finished = true;
SetNeedsPushProperties();
}
- if (!keyframe_model->affects_active_elements() &&
- !keyframe_model->affects_pending_elements()) {
+ auto* cc_keyframe_model =
+ KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+
+ if (!cc_keyframe_model->affects_active_elements() &&
+ !cc_keyframe_model->affects_pending_elements()) {
switch (keyframe_model->run_state()) {
case gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY:
case gfx::KeyframeModel::STARTING:
@@ -1030,7 +1030,8 @@ void KeyframeEffect::GenerateEvent(AnimationEvents* events,
animation_->id(), keyframe_model.id()},
keyframe_model.group(), keyframe_model.TargetProperty(),
monotonic_time);
- event.is_impl_only = keyframe_model.is_impl_only();
+ event.is_impl_only =
+ KeyframeModel::ToCcKeyframeModel(&keyframe_model)->is_impl_only();
if (!event.is_impl_only) {
events->events_.push_back(event);
return;
diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h
index 9e511add1f8..2cf4079c392 100644
--- a/chromium/cc/animation/keyframe_effect.h
+++ b/chromium/cc/animation/keyframe_effect.h
@@ -18,6 +18,7 @@
#include "cc/paint/element_id.h"
#include "cc/trees/mutator_host_client.h"
#include "cc/trees/target_property.h"
+#include "ui/gfx/animation/keyframe/keyframe_effect.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -38,7 +39,7 @@ struct PropertyAnimationState;
// KeyframeModels. The commonality between keyframe models on the same target
// is found via ElementAnimations - there is only one ElementAnimations for a
// given target.
-class CC_ANIMATION_EXPORT KeyframeEffect {
+class CC_ANIMATION_EXPORT KeyframeEffect : public gfx::KeyframeEffect {
public:
explicit KeyframeEffect(Animation* animation);
KeyframeEffect(const KeyframeEffect&) = delete;
@@ -58,7 +59,7 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
ElementId element_id() const { return element_id_; }
// Returns true if there are any KeyframeModels at all to process.
- bool has_any_keyframe_model() const { return !keyframe_models_.empty(); }
+ bool has_any_keyframe_model() const { return !keyframe_models().empty(); }
// When a scroll animation is removed on the main thread, its compositor
// thread counterpart continues producing scroll deltas until activation.
@@ -80,9 +81,7 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
void AttachElement(ElementId element_id);
void DetachElement();
- virtual void Tick(base::TimeTicks monotonic_time);
- static void TickKeyframeModel(base::TimeTicks monotonic_time,
- KeyframeModel* keyframe_model);
+ void Tick(base::TimeTicks monotonic_time) override;
void RemoveFromTicking();
void UpdateState(bool start_ready_keyframe_models, AnimationEvents* events);
@@ -91,9 +90,9 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
void Pause(base::TimeDelta pause_offset,
PauseCondition = PauseCondition::kUnconditional);
- void AddKeyframeModel(std::unique_ptr<KeyframeModel> keyframe_model);
+ void AddKeyframeModel(
+ std::unique_ptr<gfx::KeyframeModel> keyframe_model) override;
void PauseKeyframeModel(int keyframe_model_id, base::TimeDelta time_offset);
- void RemoveKeyframeModel(int keyframe_model_id);
void AbortKeyframeModel(int keyframe_model_id);
void AbortKeyframeModelsWithProperty(TargetProperty::Type target_property,
bool needs_completion);
@@ -132,9 +131,6 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
bool IsCurrentlyAnimatingProperty(TargetProperty::Type target_property,
ElementListType list_type) const;
- KeyframeModel* GetKeyframeModel(TargetProperty::Type target_property) const;
- KeyframeModel* GetKeyframeModelById(int keyframe_model_id) const;
-
void GetPropertyAnimationState(PropertyAnimationState* pending_state,
PropertyAnimationState* active_state) const;
@@ -155,6 +151,14 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
// fast as possible.
base::TimeDelta MinimumTickInterval() const;
+ protected:
+ // We override this because we have additional bookkeeping (eg, noting if
+ // we've aborted a scroll animation, updating ticking state, sending updates
+ // to the impl instance, informing |element_animations_|).
+ void RemoveKeyframeModelRange(
+ typename KeyframeModels::iterator to_remove_begin,
+ typename KeyframeModels::iterator to_remove_end) override;
+
private:
void StartKeyframeModels(base::TimeTicks monotonic_time);
void PromoteStartedKeyframeModels(AnimationEvents* events);
@@ -174,7 +178,6 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
const KeyframeModel& keyframe_model,
base::TimeTicks monotonic_time);
- std::vector<std::unique_ptr<KeyframeModel>> keyframe_models_;
Animation* animation_;
ElementId element_id_;
diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc
index b286e57d14e..7edc3f2e15f 100644
--- a/chromium/cc/animation/worklet_animation_unittest.cc
+++ b/chromium/cc/animation/worklet_animation_unittest.cc
@@ -215,13 +215,13 @@ TEST_F(WorkletAnimationTest,
std::unique_ptr<AnimationWorkletInput> input =
state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_EQ(0, input->added_and_updated_animations[0].current_time);
- state.reset(new MutatorInputState);
+ state = std::make_unique<MutatorInputState>();
worklet_animation->UpdateInputState(state.get(), second_ticks, scroll_tree,
true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_EQ(123.4, input->updated_animations[0].current_time);
// Should always offset from start time.
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
worklet_animation->UpdateInputState(state.get(), third_ticks, scroll_tree,
true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
@@ -255,7 +255,7 @@ TEST_F(WorkletAnimationTest, DocumentTimelineSetPlaybackRate) {
// Start the animation.
worklet_animation->UpdateInputState(state.get(), first_ticks, scroll_tree,
true);
- state.reset(new MutatorInputState);
+ state = std::make_unique<MutatorInputState>();
// Play until second_ticks.
worklet_animation->UpdateInputState(state.get(), second_ticks, scroll_tree,
@@ -270,7 +270,7 @@ TEST_F(WorkletAnimationTest, DocumentTimelineSetPlaybackRate) {
// Update the playback rate.
worklet_animation->SetPlaybackRateForTesting(playback_rate_half);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Play until third_ticks.
worklet_animation->UpdateInputState(state.get(), third_ticks, scroll_tree,
@@ -319,7 +319,7 @@ TEST_F(WorkletAnimationTest, ScrollTimelineSetPlaybackRate) {
// Update the playback rate.
worklet_animation->SetPlaybackRateForTesting(playback_rate_half);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Continue playing the animation.
EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true));
@@ -362,7 +362,7 @@ TEST_F(WorkletAnimationTest, InactiveScrollTimeline) {
std::unique_ptr<AnimationWorkletInput> input =
state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_FALSE(input);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Now the timeline is active.
EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true));
@@ -376,7 +376,7 @@ TEST_F(WorkletAnimationTest, InactiveScrollTimeline) {
// Verify that the current time is updated when the timeline becomes newly
// active.
EXPECT_EQ(100, input->added_and_updated_animations[0].current_time);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Now the timeline is inactive.
EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(false));
@@ -421,7 +421,7 @@ TEST_F(WorkletAnimationTest, UpdateInputStateProducesCorrectState) {
// The state of WorkletAnimation is updated to RUNNING after calling
// UpdateInputState above.
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
time += base::TimeDelta::FromSecondsD(0.1);
worklet_animation_->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
@@ -432,7 +432,7 @@ TEST_F(WorkletAnimationTest, UpdateInputStateProducesCorrectState) {
// Operating on individual KeyframeModel doesn't affect the state of
// WorkletAnimation.
keyframe_model->SetRunState(KeyframeModel::FINISHED, time);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
time += base::TimeDelta::FromSecondsD(0.1);
worklet_animation_->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
@@ -444,7 +444,7 @@ TEST_F(WorkletAnimationTest, UpdateInputStateProducesCorrectState) {
// leads to RemoveKeyframeModel.
worklet_animation_->RemoveKeyframeModel(keyframe_model_id);
worklet_animation_->UpdateState(true, nullptr);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
worklet_animation_->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
@@ -475,20 +475,20 @@ TEST_F(WorkletAnimationTest, SkipUnchangedAnimations) {
EXPECT_EQ(input->added_and_updated_animations.size(), 1u);
EXPECT_EQ(input->updated_animations.size(), 0u);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// No update on the input state if input time stays the same.
worklet_animation_->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_FALSE(input);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Different input time causes the input state to be updated.
time += base::TimeDelta::FromSecondsD(0.1);
worklet_animation_->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_EQ(input->updated_animations.size(), 1u);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Input state gets updated when the worklet animation is to be removed even
// the input time doesn't change.
worklet_animation_->RemoveKeyframeModel(keyframe_model_id);
@@ -528,20 +528,20 @@ TEST_F(WorkletAnimationTest, SkipLockedAnimations) {
EXPECT_EQ(input->added_and_updated_animations.size(), 1u);
EXPECT_EQ(input->updated_animations.size(), 0u);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Different scroll time causes the input state to be updated.
worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_EQ(input->updated_animations.size(), 1u);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Different scroll time causes the input state to be updated. Pending
// mutation will grab a lock.
worklet_animation->UpdateInputState(state.get(), time, scroll_tree, false);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
EXPECT_EQ(input->updated_animations.size(), 1u);
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Pending lock has not been released.
worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
@@ -549,7 +549,7 @@ TEST_F(WorkletAnimationTest, SkipLockedAnimations) {
worklet_animation->ReleasePendingTreeLock();
- state.reset(new MutatorInputState());
+ state = std::make_unique<MutatorInputState>();
// Pending lock has been released.
worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true);
input = state->TakeWorkletState(worklet_animation_id_.worklet_id);
diff --git a/chromium/cc/base/devtools_instrumentation.cc b/chromium/cc/base/devtools_instrumentation.cc
index b65c1546655..d0210ca1a5d 100644
--- a/chromium/cc/base/devtools_instrumentation.cc
+++ b/chromium/cc/base/devtools_instrumentation.cc
@@ -4,6 +4,8 @@
#include "cc/base/devtools_instrumentation.h"
+#include <string>
+
namespace cc {
namespace devtools_instrumentation {
namespace {
@@ -36,6 +38,7 @@ const char kFrameId[] = "frameId";
const char kLayerId[] = "layerId";
const char kLayerTreeId[] = "layerTreeId";
const char kPixelRefId[] = "pixelRefId";
+const char kPresentationTimestamp[] = "presentationTimestamp";
const char kImageUploadTask[] = "ImageUploadTask";
const char kImageDecodeTask[] = "ImageDecodeTask";
@@ -69,6 +72,9 @@ ScopedImageUploadTask::~ScopedImageUploadTask() {
auto duration = base::TimeTicks::Now() - start_time_;
const char* histogram_name = nullptr;
switch (image_type_) {
+ case ImageType::kJxl:
+ histogram_name = "Renderer4.ImageUploadTaskDurationUs.Jxl";
+ break;
case ImageType::kAvif:
histogram_name = "Renderer4.ImageUploadTaskDurationUs.Avif";
break;
@@ -118,6 +124,9 @@ ScopedImageDecodeTask::~ScopedImageDecodeTask() {
auto duration = base::TimeTicks::Now() - start_time_;
const char* histogram_name = nullptr;
switch (image_type_) {
+ case ImageType::kJxl:
+ histogram_name = "Renderer4.ImageUploadTaskDurationUs.Jxl";
+ break;
case ImageType::kAvif:
histogram_name = "Renderer4.ImageDecodeTaskDurationUs.Avif";
break;
diff --git a/chromium/cc/base/devtools_instrumentation.h b/chromium/cc/base/devtools_instrumentation.h
index 02f0254e25f..46327e9aff8 100644
--- a/chromium/cc/base/devtools_instrumentation.h
+++ b/chromium/cc/base/devtools_instrumentation.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include <utility>
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
@@ -32,6 +33,7 @@ CC_BASE_EXPORT extern const char kFrameId[];
CC_BASE_EXPORT extern const char kLayerId[];
CC_BASE_EXPORT extern const char kLayerTreeId[];
CC_BASE_EXPORT extern const char kPixelRefId[];
+CC_BASE_EXPORT extern const char kPresentationTimestamp[];
CC_BASE_EXPORT extern const char kImageDecodeTask[];
CC_BASE_EXPORT extern const char kBeginFrame[];
@@ -67,7 +69,7 @@ class CC_BASE_EXPORT ScopedLayerTask {
class CC_BASE_EXPORT ScopedImageTask {
public:
- enum ImageType { kAvif, kBmp, kGif, kIco, kJpeg, kPng, kWebP, kOther };
+ enum ImageType { kJxl, kAvif, kBmp, kGif, kIco, kJpeg, kPng, kWebP, kOther };
explicit ScopedImageTask(ImageType image_type)
: image_type_(image_type), start_time_(base::TimeTicks::Now()) {}
@@ -181,10 +183,31 @@ inline void CC_BASE_EXPORT DidBeginFrame(int layer_tree_host_id) {
internal::kLayerTreeId, layer_tree_host_id);
}
-inline void CC_BASE_EXPORT DidDrawFrame(int layer_tree_host_id) {
- TRACE_EVENT_INSTANT1(internal::CategoryName::kTimelineFrame,
- internal::kDrawFrame, TRACE_EVENT_SCOPE_THREAD,
- internal::kLayerTreeId, layer_tree_host_id);
+constexpr uint64_t GetUniqueIDFromLayerTreeHostIdAndFrameToken(
+ int layer_tree_host_id,
+ uint32_t frame_token) {
+ return static_cast<uint64_t>(layer_tree_host_id) << 32 |
+ static_cast<uint64_t>(frame_token);
+}
+
+inline void CC_BASE_EXPORT DidDrawFrame(int layer_tree_host_id,
+ uint32_t frame_token) {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(internal::CategoryName::kTimelineFrame,
+ internal::kDrawFrame,
+ GetUniqueIDFromLayerTreeHostIdAndFrameToken(
+ layer_tree_host_id, frame_token),
+ internal::kLayerTreeId, layer_tree_host_id);
+}
+
+inline void CC_BASE_EXPORT
+DidPresentFrame(int layer_tree_host_id,
+ uint32_t frame_token,
+ base::TimeTicks presentation_timestamp) {
+ TRACE_EVENT_NESTABLE_ASYNC_END1(
+ internal::CategoryName::kTimelineFrame, internal::kDrawFrame,
+ GetUniqueIDFromLayerTreeHostIdAndFrameToken(layer_tree_host_id,
+ frame_token),
+ internal::kPresentationTimestamp, presentation_timestamp);
}
inline void CC_BASE_EXPORT DidRequestMainThreadFrame(int layer_tree_host_id) {
diff --git a/chromium/cc/base/features.cc b/chromium/cc/base/features.cc
index 5e95d7db995..9b1496fbb33 100644
--- a/chromium/cc/base/features.cc
+++ b/chromium/cc/base/features.cc
@@ -4,6 +4,7 @@
#include "cc/base/features.h"
+#include "base/feature_list.h"
#include "build/build_config.h"
namespace features {
@@ -34,36 +35,23 @@ const base::Feature kSynchronizedScrolling = {
base::FEATURE_ENABLED_BY_DEFAULT};
#endif
-#if !defined(OS_ANDROID)
-// Enables latency recovery on the impl thread.
-const base::Feature kImplLatencyRecovery = {"ImplLatencyRecovery",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Enables latency recovery on the main thread.
-const base::Feature kMainLatencyRecovery = {"MainLatencyRecovery",
- base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // !defined(OS_ANDROID)
-
bool IsImplLatencyRecoveryEnabled() {
-#if defined(OS_ANDROID)
- // TODO(crbug.com/933846): LatencyRecovery is causing jank on Android. Disable
- // for now, with plan to disable more widely on all platforms.
+ // TODO(crbug.com/1142598): Latency recovery has been disabled by default
+ // since M87. For now, only the flag is removed. If all goes well, remove the
+ // code supporting latency recovery.
return false;
-#else
- return base::FeatureList::IsEnabled(kImplLatencyRecovery);
-#endif
}
bool IsMainLatencyRecoveryEnabled() {
-#if defined(OS_ANDROID)
- // TODO(crbug.com/933846): LatencyRecovery is causing jank on Android. Disable
- // for now, with plan to disable more widely on all platforms.
+ // TODO(crbug.com/1142598): Latency recovery has been disabled by default
+ // since M87. For now, only the flag is removed. If all goes well, remove the
+ // code supporting latency recovery.
return false;
-#else
- return base::FeatureList::IsEnabled(kMainLatencyRecovery);
-#endif
}
+const base::Feature kRemoveMobileViewportDoubleTap{
+ "RemoveMobileViewportDoubleTap", base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kScrollUnification{"ScrollUnification",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -71,11 +59,19 @@ const base::Feature kSchedulerSmoothnessForAnimatedScrolls{
"SmoothnessModeForAnimatedScrolls", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kWheelEventRegions{"WheelEventRegions",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kHudDisplayForPerformanceMetrics{
"HudDisplayForPerformanceMetrics", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kJankInjectionAblationFeature{
"JankInjectionAblation", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kDocumentTransition{"DocumentTransition",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsDocumentTransitionEnabled() {
+ return base::FeatureList::IsEnabled(kDocumentTransition);
+}
+
} // namespace features
diff --git a/chromium/cc/base/features.h b/chromium/cc/base/features.h
index 8fef93721ec..6068e0b46fa 100644
--- a/chromium/cc/base/features.h
+++ b/chromium/cc/base/features.h
@@ -15,14 +15,14 @@ CC_BASE_EXPORT extern const base::Feature kAnimatedImageResume;
CC_BASE_EXPORT extern const base::Feature kImpulseScrollAnimations;
CC_BASE_EXPORT extern const base::Feature kSynchronizedScrolling;
-#if !defined(OS_ANDROID)
-CC_BASE_EXPORT extern const base::Feature kImplLatencyRecovery;
-CC_BASE_EXPORT extern const base::Feature kMainLatencyRecovery;
-#endif // !defined(OS_ANDROID)
-
CC_BASE_EXPORT bool IsImplLatencyRecoveryEnabled();
CC_BASE_EXPORT bool IsMainLatencyRecoveryEnabled();
+// When enabled, the double tap to zoom will be disabled when the viewport
+// meta tag is properly set for mobile using content=width=device-width
+// or content=initial-scale=1.0
+CC_BASE_EXPORT extern const base::Feature kRemoveMobileViewportDoubleTap;
+
// When enabled, all scrolling is performed on the compositor thread -
// delegating only the hit test to Blink. This causes Blink to send additional
// information in the scroll property tree. When a scroll can't be hit tested
@@ -50,6 +50,13 @@ CC_BASE_EXPORT extern const base::Feature kHudDisplayForPerformanceMetrics;
// When enabled, some jank is injected to the animation/scrolling pipeline.
CC_BASE_EXPORT extern const base::Feature kJankInjectionAblationFeature;
+// Controls the DocumentTransition feature. More information at
+// third_party/blink/renderer/core/document_transition/README.md
+CC_BASE_EXPORT extern const base::Feature kDocumentTransition;
+
+// Helper for DocumentTransition feature.
+CC_BASE_EXPORT bool IsDocumentTransitionEnabled();
+
} // namespace features
#endif // CC_BASE_FEATURES_H_
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index 6af60ed1cf4..26a7156d9b4 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -280,6 +280,7 @@ gfx::QuadF MathUtil::InverseMapQuadToLocalSpace(
const gfx::QuadF& device_quad) {
gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization);
DCHECK(device_transform.IsInvertible());
+ DCHECK(device_transform.IsFlat());
bool did_invert = device_transform.GetInverse(&inverse_device_transform);
DCHECK(did_invert);
bool clipped = false;
diff --git a/chromium/cc/document_transition/document_transition_request.cc b/chromium/cc/document_transition/document_transition_request.cc
index 220d097f1ff..408d1112210 100644
--- a/chromium/cc/document_transition/document_transition_request.cc
+++ b/chromium/cc/document_transition/document_transition_request.cc
@@ -4,13 +4,17 @@
#include "cc/document_transition/document_transition_request.h"
+#include <map>
#include <memory>
#include <sstream>
#include <utility>
+#include <vector>
#include "base/callback.h"
#include "base/memory/ptr_util.h"
+#include "cc/document_transition/document_transition_shared_element_id.h"
#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+#include "components/viz/common/quads/compositor_render_pass.h"
namespace cc {
namespace {
@@ -63,51 +67,68 @@ uint32_t DocumentTransitionRequest::s_next_sequence_id_ = 1;
// static
std::unique_ptr<DocumentTransitionRequest>
DocumentTransitionRequest::CreatePrepare(Effect effect,
- base::TimeDelta duration,
+ uint32_t document_tag,
+ uint32_t shared_element_count,
base::OnceClosure commit_callback) {
return base::WrapUnique(new DocumentTransitionRequest(
- effect, duration, std::move(commit_callback)));
+ effect, document_tag, shared_element_count, std::move(commit_callback)));
}
// static
std::unique_ptr<DocumentTransitionRequest>
-DocumentTransitionRequest::CreateStart(base::OnceClosure commit_callback) {
- return base::WrapUnique(
- new DocumentTransitionRequest(std::move(commit_callback)));
+DocumentTransitionRequest::CreateStart(uint32_t document_tag,
+ uint32_t shared_element_count,
+ base::OnceClosure commit_callback) {
+ return base::WrapUnique(new DocumentTransitionRequest(
+ document_tag, shared_element_count, std::move(commit_callback)));
}
DocumentTransitionRequest::DocumentTransitionRequest(
Effect effect,
- base::TimeDelta duration,
+ uint32_t document_tag,
+ uint32_t shared_element_count,
base::OnceClosure commit_callback)
: type_(Type::kSave),
effect_(effect),
- duration_(duration),
- commit_callback_(std::move(commit_callback)) {}
+ document_tag_(document_tag),
+ shared_element_count_(shared_element_count),
+ commit_callback_(std::move(commit_callback)),
+ sequence_id_(s_next_sequence_id_++) {}
DocumentTransitionRequest::DocumentTransitionRequest(
+ uint32_t document_tag,
+ uint32_t shared_element_count,
base::OnceClosure commit_callback)
- : type_(Type::kAnimate), commit_callback_(std::move(commit_callback)) {}
+ : type_(Type::kAnimate),
+ document_tag_(document_tag),
+ shared_element_count_(shared_element_count),
+ commit_callback_(std::move(commit_callback)),
+ sequence_id_(s_next_sequence_id_++) {}
DocumentTransitionRequest::~DocumentTransitionRequest() = default;
viz::CompositorFrameTransitionDirective
-DocumentTransitionRequest::ConstructDirective() const {
- // Note that the clamped_duration is also verified at
- // CompositorFrameTransitionDirective deserialization time.
- auto clamped_duration =
- duration_ < viz::CompositorFrameTransitionDirective::kMaxDuration
- ? duration_
- : viz::CompositorFrameTransitionDirective::kMaxDuration;
- return viz::CompositorFrameTransitionDirective(s_next_sequence_id_++, type_,
- effect_, clamped_duration);
+DocumentTransitionRequest::ConstructDirective(
+ const std::map<DocumentTransitionSharedElementId,
+ viz::CompositorRenderPassId>&
+ shared_element_render_pass_id_map) const {
+ std::vector<viz::CompositorRenderPassId> shared_passes(shared_element_count_);
+ for (uint32_t i = 0; i < shared_passes.size(); ++i) {
+ auto it = shared_element_render_pass_id_map.find(
+ DocumentTransitionSharedElementId{document_tag_, i});
+ if (it == shared_element_render_pass_id_map.end())
+ continue;
+ shared_passes[i] = it->second;
+ }
+ return viz::CompositorFrameTransitionDirective(sequence_id_, type_, effect_,
+ std::move(shared_passes));
}
std::string DocumentTransitionRequest::ToString() const {
std::ostringstream str;
str << "[type: " << TypeToString(type_)
<< " effect: " << EffectToString(effect_)
- << " duration: " << duration_.InMillisecondsF() << "ms]";
+ << " sequence_id: " << sequence_id_ << "]";
return str.str();
}
diff --git a/chromium/cc/document_transition/document_transition_request.h b/chromium/cc/document_transition/document_transition_request.h
index dddfd4a9fd9..2f2ecdd2012 100644
--- a/chromium/cc/document_transition/document_transition_request.h
+++ b/chromium/cc/document_transition/document_transition_request.h
@@ -5,13 +5,16 @@
#ifndef CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
#define CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
+#include <map>
#include <memory>
#include <string>
#include <utility>
#include "base/callback.h"
#include "cc/cc_export.h"
+#include "cc/document_transition/document_transition_shared_element_id.h"
#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+#include "components/viz/common/quads/compositor_render_pass.h"
namespace cc {
@@ -25,11 +28,14 @@ class CC_EXPORT DocumentTransitionRequest {
// Creates a Type::kPrepare type of request.
static std::unique_ptr<DocumentTransitionRequest> CreatePrepare(
Effect effect,
- base::TimeDelta duration,
+ uint32_t document_tag,
+ uint32_t shared_element_count,
base::OnceClosure commit_callback);
// Creates a Type::kSave type of request.
static std::unique_ptr<DocumentTransitionRequest> CreateStart(
+ uint32_t document_tag,
+ uint32_t shared_element_count,
base::OnceClosure commit_callback);
DocumentTransitionRequest(DocumentTransitionRequest&) = delete;
@@ -37,17 +43,24 @@ class CC_EXPORT DocumentTransitionRequest {
DocumentTransitionRequest& operator=(DocumentTransitionRequest&) = delete;
- // The callback is run when the request is committed from the main thread onto
- // the compositor thread. This is used to indicate that the request has been
- // submitted for processing and that script may now change the page in some
- // way. In other words, this callback would resolve the prepare promise that
- // script may be waiting for.
- base::OnceClosure TakeCommitCallback() { return std::move(commit_callback_); }
+ // The callback is run when the request is sufficiently processed for us to be
+ // able to begin the next step in the animation. In other words, when this
+ // callback is invoked it can resolve a script promise that is gating this
+ // step.
+ base::OnceClosure TakeFinishedCallback() {
+ return std::move(commit_callback_);
+ }
// This constructs a viz directive. Note that repeated calls to this function
// would create a new sequence id for the directive, which means it would be
// processed again by viz.
- viz::CompositorFrameTransitionDirective ConstructDirective() const;
+ viz::CompositorFrameTransitionDirective ConstructDirective(
+ const std::map<DocumentTransitionSharedElementId,
+ viz::CompositorRenderPassId>&
+ shared_element_render_pass_id_map) const;
+
+ // Returns the sequence id for this request.
+ uint32_t sequence_id() const { return sequence_id_; }
// Testing / debugging functionality.
std::string ToString() const;
@@ -56,14 +69,19 @@ class CC_EXPORT DocumentTransitionRequest {
using Type = viz::CompositorFrameTransitionDirective::Type;
DocumentTransitionRequest(Effect effect,
- base::TimeDelta duration,
+ uint32_t document_tag,
+ uint32_t shared_element_count,
base::OnceClosure commit_callback);
- explicit DocumentTransitionRequest(base::OnceClosure commit_callback);
+ explicit DocumentTransitionRequest(uint32_t document_tag,
+ uint32_t shared_element_count,
+ base::OnceClosure commit_callback);
const Type type_;
const Effect effect_ = Effect::kNone;
- const base::TimeDelta duration_;
+ const uint32_t document_tag_;
+ const uint32_t shared_element_count_;
base::OnceClosure commit_callback_;
+ const uint32_t sequence_id_;
static uint32_t s_next_sequence_id_;
};
diff --git a/chromium/cc/document_transition/document_transition_request_unittest.cc b/chromium/cc/document_transition/document_transition_request_unittest.cc
index e5001d1f2df..bd686565d50 100644
--- a/chromium/cc/document_transition/document_transition_request_unittest.cc
+++ b/chromium/cc/document_transition/document_transition_request_unittest.cc
@@ -17,54 +17,39 @@ TEST(DocumentTransitionRequestTest, PrepareRequest) {
auto request = DocumentTransitionRequest::CreatePrepare(
DocumentTransitionRequest::Effect::kRevealLeft,
- base::TimeDelta::FromMilliseconds(123), std::move(callback));
+ /*document_tag=*/0,
+ /*shared_element_count=*/0, std::move(callback));
EXPECT_FALSE(called);
- request->TakeCommitCallback().Run();
+ request->TakeFinishedCallback().Run();
EXPECT_TRUE(called);
- EXPECT_TRUE(request->TakeCommitCallback().is_null());
+ EXPECT_TRUE(request->TakeFinishedCallback().is_null());
- auto directive = request->ConstructDirective();
+ auto directive = request->ConstructDirective({});
EXPECT_GT(directive.sequence_id(), 0u);
EXPECT_EQ(DocumentTransitionRequest::Effect::kRevealLeft, directive.effect());
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(123), directive.duration());
EXPECT_EQ(viz::CompositorFrameTransitionDirective::Type::kSave,
directive.type());
- auto duplicate = request->ConstructDirective();
- EXPECT_GT(duplicate.sequence_id(), directive.sequence_id());
+ auto duplicate = request->ConstructDirective({});
+ EXPECT_EQ(duplicate.sequence_id(), directive.sequence_id());
EXPECT_EQ(duplicate.effect(), directive.effect());
- EXPECT_EQ(duplicate.duration(), directive.duration());
EXPECT_EQ(duplicate.type(), directive.type());
}
-TEST(DocumentTransitionRequestTest, PrepareRequestLongDurationIsCapped) {
- auto long_duration = base::TimeDelta::FromSeconds(1);
-
- ASSERT_GT(long_duration,
- viz::CompositorFrameTransitionDirective::kMaxDuration);
-
- auto request = DocumentTransitionRequest::CreatePrepare(
- DocumentTransitionRequest::Effect::kRevealLeft, long_duration,
- base::OnceCallback<void()>());
-
- auto directive = request->ConstructDirective();
- EXPECT_EQ(viz::CompositorFrameTransitionDirective::kMaxDuration,
- directive.duration());
-}
-
TEST(DocumentTransitionRequestTest, StartRequest) {
bool called = false;
auto callback = base::BindLambdaForTesting([&called]() { called = true; });
- auto request = DocumentTransitionRequest::CreateStart(std::move(callback));
+ auto request = DocumentTransitionRequest::CreateStart(
+ /*document_tag=*/0, /*shared_element_transition=*/0, std::move(callback));
EXPECT_FALSE(called);
- request->TakeCommitCallback().Run();
+ request->TakeFinishedCallback().Run();
EXPECT_TRUE(called);
- EXPECT_TRUE(request->TakeCommitCallback().is_null());
+ EXPECT_TRUE(request->TakeFinishedCallback().is_null());
- auto directive = request->ConstructDirective();
+ auto directive = request->ConstructDirective({});
EXPECT_GT(directive.sequence_id(), 0u);
EXPECT_EQ(viz::CompositorFrameTransitionDirective::Type::kAnimate,
directive.type());
diff --git a/chromium/cc/document_transition/document_transition_shared_element_id.h b/chromium/cc/document_transition/document_transition_shared_element_id.h
new file mode 100644
index 00000000000..8a94cad1c81
--- /dev/null
+++ b/chromium/cc/document_transition/document_transition_shared_element_id.h
@@ -0,0 +1,37 @@
+// Copyright 2021 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.
+
+#ifndef CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SHARED_ELEMENT_ID_H_
+#define CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SHARED_ELEMENT_ID_H_
+
+#include <stdint.h>
+
+#include <tuple>
+
+namespace cc {
+
+struct DocumentTransitionSharedElementId {
+ uint32_t document_tag = 0u;
+ uint32_t element_index = 0u;
+
+ bool operator==(const DocumentTransitionSharedElementId& other) const {
+ return element_index == other.element_index &&
+ document_tag == other.document_tag;
+ }
+
+ bool operator!=(const DocumentTransitionSharedElementId& other) const {
+ return !(*this == other);
+ }
+
+ bool operator<(const DocumentTransitionSharedElementId& other) const {
+ return std::tie(document_tag, element_index) <
+ std::tie(other.document_tag, other.element_index);
+ }
+
+ bool valid() const { return document_tag != 0u; }
+};
+
+} // namespace cc
+
+#endif // CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SHARED_ELEMENT_ID_H_
diff --git a/chromium/cc/input/browser_controls_offset_manager.cc b/chromium/cc/input/browser_controls_offset_manager.cc
index 052f621a775..2f2878adc59 100644
--- a/chromium/cc/input/browser_controls_offset_manager.cc
+++ b/chromium/cc/input/browser_controls_offset_manager.cc
@@ -350,6 +350,8 @@ void BrowserControlsOffsetManager::OnBrowserControlsParamsChanged(
top_controls_min_height_offset_ =
old_browser_controls_params_.top_controls_min_height;
top_min_height_change_in_progress_ = true;
+ SetTopMinHeightOffsetAnimationRange(top_controls_min_height_offset_,
+ TopControlsMinHeight());
}
} else {
top_controls_min_height_offset_ = TopControlsMinHeight();
@@ -363,6 +365,8 @@ void BrowserControlsOffsetManager::OnBrowserControlsParamsChanged(
bottom_controls_min_height_offset_ =
old_browser_controls_params_.bottom_controls_min_height;
bottom_min_height_change_in_progress_ = true;
+ SetBottomMinHeightOffsetAnimationRange(bottom_controls_min_height_offset_,
+ BottomControlsMinHeight());
}
} else {
bottom_controls_min_height_offset_ = BottomControlsMinHeight();
@@ -509,14 +513,26 @@ gfx::Vector2dF BrowserControlsOffsetManager::Animate(
float bottom_offset_delta = ContentBottomOffset() - old_bottom_offset;
if (top_min_height_change_in_progress_) {
- top_controls_min_height_offset_ += top_offset_delta;
+ // The change in top offset may be larger than the min-height, resulting in
+ // too low or too high |top_controls_min_height_offset_| values. So, we
+ // should clamp it to a valid range.
+ top_controls_min_height_offset_ =
+ base::ClampToRange(top_controls_min_height_offset_ + top_offset_delta,
+ top_min_height_offset_animation_range_->first,
+ top_min_height_offset_animation_range_->second);
// Ticking the animation might reset it if it's at the final value.
top_min_height_change_in_progress_ =
top_controls_animation_.IsInitialized();
}
if (bottom_min_height_change_in_progress_) {
+ // The change in bottom offset may be larger than the min-height, resulting
+ // in too low or too high |bottom_controls_min_height_offset_| values. So,
+ // we should clamp it to a valid range.
+ bottom_controls_min_height_offset_ = base::ClampToRange(
+ bottom_controls_min_height_offset_ + bottom_offset_delta,
+ bottom_min_height_offset_animation_range_->first,
+ bottom_min_height_offset_animation_range_->second);
// Ticking the animation might reset it if it's at the final value.
- bottom_controls_min_height_offset_ += bottom_offset_delta;
bottom_min_height_change_in_progress_ =
bottom_controls_animation_.IsInitialized();
}
@@ -552,6 +568,8 @@ void BrowserControlsOffsetManager::ResetAnimations() {
}
top_min_height_change_in_progress_ = false;
bottom_min_height_change_in_progress_ = false;
+ top_min_height_offset_animation_range_.reset();
+ bottom_min_height_offset_animation_range_.reset();
}
void BrowserControlsOffsetManager::SetupAnimation(
@@ -663,6 +681,20 @@ void BrowserControlsOffsetManager::UpdateOldBrowserControlsParams() {
BottomControlsMinHeight();
}
+void BrowserControlsOffsetManager::SetTopMinHeightOffsetAnimationRange(
+ float from,
+ float to) {
+ top_min_height_offset_animation_range_ =
+ std::make_pair(std::min(from, to), std::max(from, to));
+}
+
+void BrowserControlsOffsetManager::SetBottomMinHeightOffsetAnimationRange(
+ float from,
+ float to) {
+ bottom_min_height_offset_animation_range_ =
+ std::make_pair(std::min(from, to), std::max(from, to));
+}
+
// class Animation
BrowserControlsOffsetManager::Animation::Animation() {}
diff --git a/chromium/cc/input/browser_controls_offset_manager.h b/chromium/cc/input/browser_controls_offset_manager.h
index bd6f0438aa6..a2ce20981ba 100644
--- a/chromium/cc/input/browser_controls_offset_manager.h
+++ b/chromium/cc/input/browser_controls_offset_manager.h
@@ -6,6 +6,7 @@
#define CC_INPUT_BROWSER_CONTROLS_OFFSET_MANAGER_H_
#include <memory>
+#include <utility>
#include "base/time/time.h"
#include "cc/input/browser_controls_state.h"
@@ -117,6 +118,8 @@ class CC_EXPORT BrowserControlsOffsetManager {
void InitAnimationForHeightChange(Animation* animation,
float start_ratio,
float stop_ratio);
+ void SetTopMinHeightOffsetAnimationRange(float from, float to);
+ void SetBottomMinHeightOffsetAnimationRange(float from, float to);
// The client manages the lifecycle of this.
BrowserControlsOffsetManagerClient* client_;
@@ -156,6 +159,15 @@ class CC_EXPORT BrowserControlsOffsetManager {
float top_controls_min_height_offset_;
float bottom_controls_min_height_offset_;
+ // Minimum and maximum values |top_controls_min_height_offset_| can take
+ // during the current min-height change animation.
+ base::Optional<std::pair<float, float>>
+ top_min_height_offset_animation_range_;
+ // Minimum and maximum values |bottom_controls_min_height_offset_| can take
+ // during the current min-height change animation.
+ base::Optional<std::pair<float, float>>
+ bottom_min_height_offset_animation_range_;
+
// Class that holds and manages the state of the controls animations.
class Animation {
public:
diff --git a/chromium/cc/input/browser_controls_offset_manager_unittest.cc b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
index 7c64038668f..69a6e62d17f 100644
--- a/chromium/cc/input/browser_controls_offset_manager_unittest.cc
+++ b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
@@ -1234,5 +1234,70 @@ TEST(BrowserControlsOffsetManagerTest, MinHeightChangeUpdatesAnimation) {
EXPECT_FLOAT_EQ(0.1f, manager->TopControlsShownRatio());
}
+// Tests that setting a top height and min-height with animation when both were
+// 0 doesn't cause invalid |TopControlsMinHeightOffset| values.
+// See: https://crbug.com/1184902.
+TEST(BrowserControlsOffsetManagerTest,
+ ChangingTopMinHeightFromInitialZeroAnimatesCorrectly) {
+ MockBrowserControlsOffsetManagerClient client(0, 0.5f, 0.5f);
+ BrowserControlsOffsetManager* manager = client.manager();
+
+ client.SetBrowserControlsParams({100, 30, 0, 0, true, false});
+ EXPECT_TRUE(manager->HasAnimation());
+ EXPECT_FLOAT_EQ(0.f, client.CurrentTopControlsShownRatio());
+
+ base::TimeTicks time = base::TimeTicks::Now();
+
+ // First animate will establish the animation.
+ float previous_min_height_offset = 0.f;
+ manager->Animate(time);
+ EXPECT_EQ(manager->TopControlsMinHeightOffset(), previous_min_height_offset);
+
+ while (manager->HasAnimation()) {
+ previous_min_height_offset = manager->TopControlsMinHeightOffset();
+ time = base::TimeDelta::FromMicroseconds(100) + time;
+ manager->Animate(time);
+ EXPECT_GE(manager->TopControlsMinHeightOffset(),
+ previous_min_height_offset);
+ EXPECT_LE(manager->TopControlsMinHeightOffset(),
+ manager->TopControlsMinHeight());
+ }
+
+ EXPECT_FLOAT_EQ(30.f, manager->TopControlsMinHeightOffset());
+}
+
+// Tests that reducing both height and min-height with animation doesn't cause
+// invalid |TopControlsMinHeightOffset| values.
+TEST(BrowserControlsOffsetManagerTest,
+ ReducingTopHeightAndMinHeightAnimatesCorrectly) {
+ MockBrowserControlsOffsetManagerClient client(0, 0.5f, 0.5f);
+ BrowserControlsOffsetManager* manager = client.manager();
+
+ client.SetBrowserControlsParams({100, 30, 0, 0, false, false});
+ EXPECT_FALSE(manager->HasAnimation());
+ EXPECT_EQ(30, manager->TopControlsMinHeightOffset());
+ client.SetBrowserControlsParams({50, 20, 0, 0, true, false});
+ EXPECT_TRUE(manager->HasAnimation());
+
+ base::TimeTicks time = base::TimeTicks::Now();
+
+ // First animate will establish the animation.
+ float previous_min_height_offset = 30.f;
+ manager->Animate(time);
+ EXPECT_EQ(manager->TopControlsMinHeightOffset(), previous_min_height_offset);
+
+ while (manager->HasAnimation()) {
+ previous_min_height_offset = manager->TopControlsMinHeightOffset();
+ time = base::TimeDelta::FromMicroseconds(100) + time;
+ manager->Animate(time);
+ EXPECT_LE(manager->TopControlsMinHeightOffset(),
+ previous_min_height_offset);
+ EXPECT_GE(manager->TopControlsMinHeightOffset(),
+ manager->TopControlsMinHeight());
+ }
+
+ EXPECT_FLOAT_EQ(20.f, manager->TopControlsMinHeightOffset());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/input/scroll_snap_data.cc b/chromium/cc/input/scroll_snap_data.cc
index f2586f2b976..7633c4f4336 100644
--- a/chromium/cc/input/scroll_snap_data.cc
+++ b/chromium/cc/input/scroll_snap_data.cc
@@ -4,17 +4,42 @@
#include "cc/input/scroll_snap_data.h"
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <memory>
+
#include "base/check.h"
#include "base/notreached.h"
#include "base/numerics/ranges.h"
#include "cc/input/snap_selection_strategy.h"
-
-#include <algorithm>
-#include <cmath>
+#include "ui/gfx/geometry/vector2d_f.h"
namespace cc {
namespace {
+gfx::Vector2dF DistanceFromCorridor(double dx,
+ double dy,
+ const gfx::RectF& area) {
+ gfx::Vector2dF distance;
+
+ if (dx < 0)
+ distance.set_x(-dx);
+ else if (dx > area.width())
+ distance.set_x(dx - area.width());
+ else
+ distance.set_x(0);
+
+ if (dy < 0)
+ distance.set_y(-dy);
+ else if (dy > area.height())
+ distance.set_y(dy - area.height());
+ else
+ distance.set_y(0);
+
+ return distance;
+}
+
bool IsMutualVisible(const SnapSearchResult& a, const SnapSearchResult& b) {
return gfx::RangeF(b.snap_offset()).IsBoundedBy(a.visible_range()) &&
gfx::RangeF(a.snap_offset()).IsBoundedBy(b.visible_range());
@@ -152,7 +177,6 @@ bool SnapContainerData::FindSnapPosition(
SnapSearchResult initial_snap_position_y = {
base::ClampToRange(base_position.y(), 0.f, max_position_.y()),
gfx::RangeF(0, max_position_.x())};
-
selected_x = FindClosestValidArea(SearchAxis::kX, strategy,
initial_snap_position_y);
}
@@ -170,8 +194,15 @@ bool SnapContainerData::FindSnapPosition(
}
}
- if (!selected_x.has_value() && !selected_y.has_value())
+ if (!selected_x.has_value() && !selected_y.has_value()) {
+ // Searching along each axis separately can miss valid snap positions if
+ // snapping along both axes and the snap positions are off screen.
+ if (should_snap_on_x && should_snap_on_y &&
+ !strategy.ShouldRespectSnapStop())
+ return FindSnapPositionForMutualSnap(strategy, snap_position);
+
return false;
+ }
// If snapping in one axis pushes off-screen the other snap area, this snap
// position is invalid. https://drafts.csswg.org/css-scroll-snap-1/#snap-scope
@@ -211,6 +242,61 @@ bool SnapContainerData::FindSnapPosition(
return true;
}
+// This method is called only if the preferred algorithm fails to find either an
+// x or a y snap position.
+// The base algorithm searches on x (if appropriate) and then y (if
+// appropriate). Each search is along the corridor in the search direction.
+// For a search in the x-direction, areas as excluded from consideration if the
+// range in the y-direction does not overlap the y base position (i.e. can
+// scroll-snap in the x-direction without scrolling in the y-direction). Rules
+// for scroll-snap in the y-direction are symmetric. This is the preferred
+// approach, though the ordering of the searches should perhaps be determined
+// based on axis locking.
+// In cases where no valid snap points are found via searches along the axis
+// corridors, the snap selection strategy allows for selection of areas outside
+// of the corridors.
+bool SnapContainerData::FindSnapPositionForMutualSnap(
+ const SnapSelectionStrategy& strategy,
+ gfx::ScrollOffset* snap_position) const {
+ DCHECK(strategy.ShouldSnapOnX() && strategy.ShouldSnapOnY());
+ bool found = false;
+ gfx::Vector2dF smallest_distance(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max());
+
+ // Snap to same element for x & y if possible.
+ for (const SnapAreaData& area : snap_area_list_) {
+ if (!strategy.IsValidSnapArea(SearchAxis::kX, area))
+ continue;
+
+ if (!strategy.IsValidSnapArea(SearchAxis::kY, area))
+ continue;
+
+ SnapSearchResult x_candidate = GetSnapSearchResult(SearchAxis::kX, area);
+ float dx = x_candidate.snap_offset() - strategy.current_position().x();
+ if (std::abs(dx) > proximity_range_.x())
+ continue;
+
+ SnapSearchResult y_candidate = GetSnapSearchResult(SearchAxis::kY, area);
+ float dy = y_candidate.snap_offset() - strategy.current_position().y();
+ if (std::abs(dy) > proximity_range_.y())
+ continue;
+
+ // Preferentially minimize block scrolling distance. Ties in block scrolling
+ // distance are resolved by considering inline scrolling distance.
+ gfx::Vector2dF distance = DistanceFromCorridor(dx, dy, rect_);
+ if (distance.y() < smallest_distance.y() ||
+ (distance.y() == smallest_distance.y() &&
+ distance.x() < smallest_distance.x())) {
+ smallest_distance = distance;
+ snap_position->set_x(x_candidate.snap_offset());
+ snap_position->set_y(y_candidate.snap_offset());
+ found = true;
+ }
+ }
+
+ return found;
+}
+
base::Optional<SnapSearchResult>
SnapContainerData::GetTargetSnapAreaSearchResult(SearchAxis axis) const {
ElementId target_id = axis == SearchAxis::kX
@@ -384,6 +470,8 @@ SnapSearchResult SnapContainerData::GetSnapSearchResult(
result.set_visible_range(gfx::RangeF(area.rect.y() - rect_.bottom(),
area.rect.bottom() - rect_.y()));
// https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-align
+ // Snap alignment has been normalized for a horizontal left to right and top
+ // to bottom writing mode.
switch (area.scroll_snap_align.alignment_inline) {
case SnapAlignment::kStart:
result.set_snap_offset(area.rect.x() - rect_.x());
diff --git a/chromium/cc/input/scroll_snap_data.h b/chromium/cc/input/scroll_snap_data.h
index 8c80440d5cf..e22fc9b6a84 100644
--- a/chromium/cc/input/scroll_snap_data.h
+++ b/chromium/cc/input/scroll_snap_data.h
@@ -275,6 +275,9 @@ class CC_EXPORT SnapContainerData {
const SnapSelectionStrategy& strategy,
const SnapSearchResult& cross_axis_snap_result) const;
+ bool FindSnapPositionForMutualSnap(const SnapSelectionStrategy& strategy,
+ gfx::ScrollOffset* snap_position) const;
+
// Finds the snap area associated with the target snap area element id for the
// given axis.
base::Optional<SnapSearchResult> GetTargetSnapAreaSearchResult(
diff --git a/chromium/cc/input/scroll_state.h b/chromium/cc/input/scroll_state.h
index 8ac3850ca51..5589879a82f 100644
--- a/chromium/cc/input/scroll_state.h
+++ b/chromium/cc/input/scroll_state.h
@@ -59,6 +59,14 @@ class CC_EXPORT ScrollState {
data_.is_direct_manipulation = is_direct_manipulation;
}
+ // True if the user interacts with the scrollbar.
+ bool is_scrollbar_interaction() const {
+ return data_.is_scrollbar_interaction;
+ }
+ void set_is_scrollbar_interaction(bool is_scrollbar_interaction) {
+ data_.is_scrollbar_interaction = is_scrollbar_interaction;
+ }
+
bool delta_consumed_for_scroll_sequence() const {
return data_.delta_consumed_for_scroll_sequence;
}
diff --git a/chromium/cc/input/scroll_state_data.cc b/chromium/cc/input/scroll_state_data.cc
index f18676f4b85..3409421c5a2 100644
--- a/chromium/cc/input/scroll_state_data.cc
+++ b/chromium/cc/input/scroll_state_data.cc
@@ -22,6 +22,7 @@ ScrollStateData::ScrollStateData()
from_user_input(false),
delta_consumed_for_scroll_sequence(false),
is_direct_manipulation(false),
+ is_scrollbar_interaction(false),
delta_granularity(ui::ScrollGranularity::kScrollByPrecisePixel),
caused_scroll_x(false),
caused_scroll_y(false),
diff --git a/chromium/cc/input/scroll_state_data.h b/chromium/cc/input/scroll_state_data.h
index a3a2755c61b..82ea52fa607 100644
--- a/chromium/cc/input/scroll_state_data.h
+++ b/chromium/cc/input/scroll_state_data.h
@@ -47,6 +47,8 @@ class CC_EXPORT ScrollStateData {
// True if the user interacts directly with the display, e.g., via
// touch.
bool is_direct_manipulation;
+ // True if the scroll is the result of a scrollbar interaction.
+ bool is_scrollbar_interaction;
// Granularity units for the scroll delta.
ui::ScrollGranularity delta_granularity;
diff --git a/chromium/cc/input/threaded_input_handler.cc b/chromium/cc/input/threaded_input_handler.cc
index a22f04db5f7..18804b0c370 100644
--- a/chromium/cc/input/threaded_input_handler.cc
+++ b/chromium/cc/input/threaded_input_handler.cc
@@ -366,6 +366,15 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate(
last_scroll_update_state_ = *scroll_state;
+ // Snap on update if interacting with the scrollbar track or arrow buttons.
+ // Interactions with the scrollbar thumb have kScrollByPrecisePixel
+ // granularity.
+ if (scroll_state->is_scrollbar_interaction() &&
+ scroll_state->delta_granularity() !=
+ ui::ScrollGranularity::kScrollByPrecisePixel) {
+ AdjustScrollDeltaForScrollbarSnap(scroll_state);
+ }
+
gfx::Vector2dF resolvedScrollDelta = ResolveScrollGranularityToPixels(
*CurrentlyScrollingNode(),
gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y()),
@@ -466,6 +475,36 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate(
return scroll_result;
}
+void ThreadedInputHandler::AdjustScrollDeltaForScrollbarSnap(
+ ScrollState* scroll_state) {
+ ScrollNode* scroll_node = CurrentlyScrollingNode();
+ if (!scroll_node || !scroll_node->snap_container_data)
+ return;
+
+ // Ideally, scrollbar track and arrow interactions would have
+ // kScrollByPage and kScrollByLine, respectively. Currently, both have
+ // kScrollByPixel granularity.
+ // TODO(crbug.com/959441): Update snap strategy once the granularity is
+ // properly set. Currently, track and arrow scrolls both use a direction
+ // strategy; however, the track should be using an "end and direction"
+ // strategy.
+ gfx::ScrollOffset current_position = GetVisualScrollOffset(*scroll_node);
+ const SnapContainerData& data = scroll_node->snap_container_data.value();
+ std::unique_ptr<SnapSelectionStrategy> strategy =
+ SnapSelectionStrategy::CreateForDirection(
+ gfx::ScrollOffset(current_position.x(), current_position.y()),
+ gfx::ScrollOffset(scroll_state->delta_x(), scroll_state->delta_y()),
+ true);
+
+ gfx::ScrollOffset snap_position;
+ TargetSnapAreaElementIds snap_target_ids;
+ if (!data.FindSnapPosition(*strategy, &snap_position, &snap_target_ids))
+ return;
+
+ scroll_state->data()->delta_x = snap_position.x() - current_position.x();
+ scroll_state->data()->delta_y = snap_position.y() - current_position.y();
+}
+
void ThreadedInputHandler::ScrollEnd(bool should_snap) {
scrollbar_controller_->ResetState();
if (!CurrentlyScrollingNode())
@@ -1967,18 +2006,7 @@ bool ThreadedInputHandler::ShouldAnimateScroll(
bool has_precise_scroll_deltas = scroll_state.delta_granularity() ==
ui::ScrollGranularity::kScrollByPrecisePixel;
-#if defined(OS_MAC)
- if (has_precise_scroll_deltas)
- return false;
-
- // Mac does not smooth scroll wheel events (crbug.com/574283). We allow tests
- // to force it on.
- return latched_scroll_type_ == ui::ScrollInputType::kScrollbar
- ? true
- : force_smooth_wheel_scrolling_for_testing_;
-#else
return !has_precise_scroll_deltas;
-#endif
}
bool ThreadedInputHandler::SnapAtScrollEnd() {
diff --git a/chromium/cc/input/threaded_input_handler.h b/chromium/cc/input/threaded_input_handler.h
index 80b33189b2f..3467d942f1c 100644
--- a/chromium/cc/input/threaded_input_handler.h
+++ b/chromium/cc/input/threaded_input_handler.h
@@ -340,6 +340,8 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler,
gfx::Vector2dF UserScrollableDelta(const ScrollNode& node,
const gfx::Vector2dF& delta) const;
+ void AdjustScrollDeltaForScrollbarSnap(ScrollState* scroll_state);
+
FrameSequenceTrackerType GetTrackerTypeForScroll(
ui::ScrollInputType input_type) const;
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index de7936aad42..e755b3b37fd 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -272,6 +272,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
// Allocate a backing for the resource if needed, either for gpu or software
// compositing.
ResourcePool::InUsePoolResource pool_resource;
+ bool needs_clear = false;
if (draw_mode == DRAW_MODE_HARDWARE) {
DCHECK(raster_context_provider || context_provider);
const auto& caps = raster_context_provider
@@ -317,6 +318,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
}
pool_resource.set_gpu_backing(std::move(backing));
+ needs_clear = true;
} else if (pool_resource.gpu_backing()->returned_sync_token.HasData()) {
if (raster_context_provider) {
auto* ri = raster_context_provider->RasterInterface();
@@ -373,7 +375,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
constexpr GLuint background_color = SkColorSetARGB(0, 0, 0, 0);
constexpr GLuint msaa_sample_count = -1;
constexpr bool can_use_lcd_text = true;
- ri->BeginRasterCHROMIUM(background_color, msaa_sample_count,
+ ri->BeginRasterCHROMIUM(background_color, needs_clear, msaa_sample_count,
can_use_lcd_text, gfx::ColorSpace::CreateSRGB(),
backing->mailbox.name);
gfx::Vector2dF post_translate(0.f, 0.f);
@@ -553,6 +555,10 @@ void HeadsUpDisplayLayerImpl::SetLayoutShiftRects(
layout_shift_rects_ = rects;
}
+void HeadsUpDisplayLayerImpl::ClearLayoutShiftRects() {
+ layout_shift_rects_.clear();
+}
+
void HeadsUpDisplayLayerImpl::SetWebVitalMetrics(
std::unique_ptr<WebVitalMetrics> web_vital_metrics) {
web_vital_metrics_ = std::move(web_vital_metrics);
@@ -1075,7 +1081,6 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
DebugColors::PaintRectBorderWidth(), "");
}
}
-
if (new_layout_shift_rects.size()) {
layout_shift_debug_rects_.swap(new_layout_shift_rects);
layout_shift_rects_fade_step_ = DebugColors::kFadeSteps;
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index 804201da7d9..bfd8b775aae 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -68,6 +68,7 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void SetHUDTypeface(sk_sp<SkTypeface> typeface);
void SetLayoutShiftRects(const std::vector<gfx::Rect>& rects);
+ void ClearLayoutShiftRects();
const std::vector<gfx::Rect>& LayoutShiftRects() const;
void SetWebVitalMetrics(std::unique_ptr<WebVitalMetrics> web_vital_metrics);
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 2d69deaaddd..29fb9db2e05 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -661,6 +661,8 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetInteger("effect_tree_index", effect_tree_index());
state->SetInteger("scroll_tree_index", scroll_tree_index());
+ state->SetInteger("sorting_context_id", GetSortingContextId());
+
state->SetInteger("draws_content", DrawsContent());
state->SetInteger("gpu_memory_usage",
base::saturated_cast<int>(GPUMemoryUsageInBytes()));
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index 9770b8c6873..0164391ffbb 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -149,8 +150,8 @@ class LayerTest : public testing::Test {
params.task_graph_runner = &task_graph_runner_;
params.mutator_host = animation_host_.get();
- layer_tree_host_.reset(new StrictMock<MockLayerTreeHost>(
- &single_thread_client_, std::move(params)));
+ layer_tree_host_ = std::make_unique<StrictMock<MockLayerTreeHost>>(
+ &single_thread_client_, std::move(params));
}
void TearDown() override {
diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc
index 900533c2d38..bd0e801e304 100644
--- a/chromium/cc/layers/picture_layer.cc
+++ b/chromium/cc/layers/picture_layer.cc
@@ -94,7 +94,7 @@ void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
return;
if (!recording_source_)
- recording_source_.reset(new RecordingSource);
+ recording_source_ = std::make_unique<RecordingSource>();
recording_source_->SetSlowdownRasterScaleFactor(
host->GetDebugState().slow_down_raster_scale_factor);
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index e49acdc47ec..08b2552ac9f 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -98,25 +98,10 @@ gfx::Rect SafeIntersectRects(const gfx::Rect& one, const gfx::Rect& two) {
PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id, /*will_always_push_properties=*/true),
- twin_layer_(nullptr),
- tilings_(CreatePictureLayerTilingSet()),
- ideal_page_scale_(0.f),
- ideal_device_scale_(0.f),
- ideal_source_scale_(0.f),
- ideal_contents_scale_(0.f),
- raster_page_scale_(0.f),
- raster_device_scale_(0.f),
- raster_source_scale_(0.f),
- raster_contents_scale_(0.f),
- low_res_raster_contents_scale_(0.f),
is_backdrop_filter_mask_(false),
was_screen_space_transform_animating_(false),
only_used_low_res_last_append_quads_(false),
- nearest_neighbor_(false),
- lcd_text_disallowed_reason_(LCDTextDisallowedReason::kNone),
- directly_composited_image_size_(base::nullopt),
- directly_composited_image_initial_raster_scale_(0.f),
- tile_size_calculator_(this) {
+ nearest_neighbor_(false) {
layer_tree_impl()->RegisterPictureLayerImpl(this);
}
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index e526ef44341..67b1ea5faad 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -236,31 +236,32 @@ class CC_EXPORT PictureLayerImpl
// will change transform.
bool HasWillChangeTransformHint() const;
- PictureLayerImpl* twin_layer_;
+ PictureLayerImpl* twin_layer_ = nullptr;
- std::unique_ptr<PictureLayerTilingSet> tilings_;
+ std::unique_ptr<PictureLayerTilingSet> tilings_ =
+ CreatePictureLayerTilingSet();
scoped_refptr<RasterSource> raster_source_;
Region invalidation_;
// Ideal scales are calcuated from the transforms applied to the layer. They
// represent the best known scale from the layer to the final output.
// Page scale is from user pinch/zoom.
- float ideal_page_scale_;
+ float ideal_page_scale_ = 0.f;
// Device scale is from screen dpi, and it comes from device scale facter.
- float ideal_device_scale_;
+ float ideal_device_scale_ = 0.f;
// Source scale comes from javascript css scale.
- float ideal_source_scale_;
+ float ideal_source_scale_ = 0.f;
// Contents scale = device scale * page scale * source scale.
- float ideal_contents_scale_;
+ float ideal_contents_scale_ = 0.f;
// Raster scales are set from ideal scales. They are scales we choose to
// raster at. They may not match the ideal scales at times to avoid raster for
// performance reasons.
- float raster_page_scale_;
- float raster_device_scale_;
- float raster_source_scale_;
- float raster_contents_scale_;
- float low_res_raster_contents_scale_;
+ float raster_page_scale_ = 0.f;
+ float raster_device_scale_ = 0.f;
+ float raster_source_scale_ = 0.f;
+ float raster_contents_scale_ = 0.f;
+ float low_res_raster_contents_scale_ = 0.f;
bool is_backdrop_filter_mask_ : 1;
@@ -269,7 +270,8 @@ class CC_EXPORT PictureLayerImpl
bool nearest_neighbor_ : 1;
- LCDTextDisallowedReason lcd_text_disallowed_reason_;
+ LCDTextDisallowedReason lcd_text_disallowed_reason_ =
+ LCDTextDisallowedReason::kNone;
// The intrinsic size of the directly composited image. A directly composited
// image is an image which is the only thing drawn into a layer. In these
@@ -280,7 +282,7 @@ class CC_EXPORT PictureLayerImpl
// time raster scales were calculated. This will be the same as
// |raster_source_scale_| if no adjustments were made in
// |CalculateDirectlyCompositedImageRasterScale()|.
- float directly_composited_image_initial_raster_scale_;
+ float directly_composited_image_initial_raster_scale_ = 0.f;
// Use this instead of |visible_layer_rect()| for tiling calculations. This
// takes external viewport and transform for tile priority into account.
@@ -303,7 +305,7 @@ class CC_EXPORT PictureLayerImpl
PaintWorkletRecordMap paint_worklet_records_;
gfx::Size content_bounds_;
- TileSizeCalculator tile_size_calculator_;
+ TileSizeCalculator tile_size_calculator_{this};
// Denotes an area that is damaged and needs redraw. This is in the layer's
// space.
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index 61ac7452a91..dbf6b3b2b7b 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -3229,9 +3229,9 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetRasterQueue) {
RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
EXPECT_TRUE(required_queue->IsEmpty());
- required_queue.reset(new TilingSetRasterQueueRequired(
+ required_queue = std::make_unique<TilingSetRasterQueueRequired>(
pending_layer()->picture_layer_tiling_set(),
- RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
EXPECT_FALSE(required_queue->IsEmpty());
int required_for_activation_count = 0;
while (!required_queue->IsEmpty()) {
@@ -3255,8 +3255,8 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetRasterQueue) {
unique_tiles.clear();
high_res_tile_count = 0u;
- queue.reset(new TilingSetRasterQueueAll(
- pending_layer()->picture_layer_tiling_set(), false, false));
+ queue = std::make_unique<TilingSetRasterQueueAll>(
+ pending_layer()->picture_layer_tiling_set(), false, false);
while (!queue->IsEmpty()) {
PrioritizedTile prioritized_tile = queue->Top();
TilePriority priority = prioritized_tile.priority();
@@ -3291,8 +3291,8 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetRasterQueue) {
draw_info.SetSolidColorForTesting(SK_ColorRED);
}
- queue.reset(new TilingSetRasterQueueAll(
- pending_layer()->picture_layer_tiling_set(), true, false));
+ queue = std::make_unique<TilingSetRasterQueueAll>(
+ pending_layer()->picture_layer_tiling_set(), true, false);
EXPECT_TRUE(queue->IsEmpty());
}
@@ -3322,9 +3322,9 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetRasterQueueActiveTree) {
queue->Pop();
}
- queue.reset(new TilingSetRasterQueueRequired(
+ queue = std::make_unique<TilingSetRasterQueueRequired>(
active_layer()->picture_layer_tiling_set(),
- RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
EXPECT_TRUE(queue->IsEmpty());
}
@@ -3407,9 +3407,9 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetEvictionQueue) {
PrioritizedTile last_tile;
size_t distance_decreasing = 0;
size_t distance_increasing = 0;
- queue.reset(new TilingSetEvictionQueue(
+ queue = std::make_unique<TilingSetEvictionQueue>(
pending_layer()->picture_layer_tiling_set(),
- pending_layer()->contributes_to_drawn_render_surface()));
+ pending_layer()->contributes_to_drawn_render_surface());
while (!queue->IsEmpty()) {
PrioritizedTile prioritized_tile = queue->Top();
Tile* tile = prioritized_tile.tile();
@@ -4258,8 +4258,8 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
UpdateDrawProperties(host_impl()->pending_tree());
unoccluded_tile_count = 0;
- queue.reset(new TilingSetRasterQueueAll(
- pending_layer()->picture_layer_tiling_set(), false, false));
+ queue = std::make_unique<TilingSetRasterQueueAll>(
+ pending_layer()->picture_layer_tiling_set(), false, false);
while (!queue->IsEmpty()) {
PrioritizedTile prioritized_tile = queue->Top();
Tile* tile = prioritized_tile.tile();
@@ -4282,8 +4282,8 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
UpdateDrawProperties(host_impl()->pending_tree());
unoccluded_tile_count = 0;
- queue.reset(new TilingSetRasterQueueAll(
- pending_layer()->picture_layer_tiling_set(), false, false));
+ queue = std::make_unique<TilingSetRasterQueueAll>(
+ pending_layer()->picture_layer_tiling_set(), false, false);
while (!queue->IsEmpty()) {
PrioritizedTile prioritized_tile = queue->Top();
Tile* tile = prioritized_tile.tile();
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index 25d5ca89aa5..305ef1cde13 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -187,6 +187,11 @@ const EffectNode* RenderSurfaceImpl::OwningEffectNode() const {
EffectTreeIndex());
}
+const DocumentTransitionSharedElementId&
+RenderSurfaceImpl::GetDocumentTransitionSharedElementId() const {
+ return OwningEffectNode()->document_transition_shared_element_id;
+}
+
void RenderSurfaceImpl::SetClipRect(const gfx::Rect& clip_rect) {
if (clip_rect == draw_properties_.clip_rect)
return;
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 105e04a7067..eb18ec27ef8 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -12,6 +12,7 @@
#include <vector>
#include "cc/cc_export.h"
+#include "cc/document_transition/document_transition_shared_element_id.h"
#include "cc/layers/draw_mode.h"
#include "cc/layers/layer_collections.h"
#include "cc/trees/occlusion.h"
@@ -210,6 +211,9 @@ class CC_EXPORT RenderSurfaceImpl {
const EffectNode* OwningEffectNode() const;
+ const DocumentTransitionSharedElementId&
+ GetDocumentTransitionSharedElementId() const;
+
private:
void SetContentRect(const gfx::Rect& content_rect);
gfx::Rect CalculateClippedAccumulatedContentRect();
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 69f004aa98e..c237739b5f7 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -4,6 +4,7 @@
#include <stddef.h>
+#include <memory>
#include <unordered_map>
#include "base/threading/thread_task_runner_handle.h"
@@ -1019,8 +1020,8 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
public:
ScrollbarLayerSolidColorThumbTest() {
LayerTreeSettings layer_tree_settings;
- host_impl_.reset(new FakeLayerTreeHostImpl(
- layer_tree_settings, &task_runner_provider_, &task_graph_runner_));
+ host_impl_ = std::make_unique<FakeLayerTreeHostImpl>(
+ layer_tree_settings, &task_runner_provider_, &task_graph_runner_);
const int kThumbThickness = 3;
const int kTrackStart = 0;
diff --git a/chromium/cc/metrics/compositor_frame_reporter.cc b/chromium/cc/metrics/compositor_frame_reporter.cc
index fcad7a8cd4e..16e58f6ecef 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter.cc
@@ -46,6 +46,12 @@ constexpr int kBlinkBreakdownInitialIndex =
constexpr int kFrameSequenceTrackerTypeCount =
static_cast<int>(FrameSequenceTrackerType::kMaxType) + 1;
+// Maximum number of partial update dependents a reporter can own. When a
+// reporter with too many dependents is terminated, it will terminate all its
+// dependents which will block the pipeline for a long time. Too many dependents
+// also means too much memory usage.
+constexpr size_t kMaxOwnedPartialUpdateDependents = 300u;
+
// Names for the viz breakdowns that are shown in trace as substages under
// PipelineReporter -> SubmitCompositorFrameToPresentationCompositorFrame or
// EventLatency -> SubmitCompositorFrameToPresentationCompositorFrame.
@@ -539,16 +545,20 @@ CompositorFrameReporter::CompositorFrameReporter(
LatencyUkmReporter* latency_ukm_reporter,
bool should_report_metrics,
SmoothThread smooth_thread,
+ FrameSequenceMetrics::ThreadType scrolling_thread,
int layer_tree_host_id,
DroppedFrameCounter* dropped_frame_counter)
: should_report_metrics_(should_report_metrics),
args_(args),
active_trackers_(active_trackers),
+ scrolling_thread_(scrolling_thread),
latency_ukm_reporter_(latency_ukm_reporter),
dropped_frame_counter_(dropped_frame_counter),
smooth_thread_(smooth_thread),
layer_tree_host_id_(layer_tree_host_id) {
dropped_frame_counter_->OnBeginFrame(args, IsScrollActive(active_trackers_));
+ DCHECK(IsScrollActive(active_trackers_) ||
+ scrolling_thread_ == FrameSequenceMetrics::ThreadType::kUnknown);
}
std::unique_ptr<CompositorFrameReporter>
@@ -565,7 +575,8 @@ CompositorFrameReporter::CopyReporterAtBeginImplStage() {
}
auto new_reporter = std::make_unique<CompositorFrameReporter>(
active_trackers_, args_, latency_ukm_reporter_, should_report_metrics_,
- smooth_thread_, layer_tree_host_id_, dropped_frame_counter_);
+ smooth_thread_, scrolling_thread_, layer_tree_host_id_,
+ dropped_frame_counter_);
new_reporter->did_finish_impl_frame_ = did_finish_impl_frame_;
new_reporter->impl_frame_finish_time_ = impl_frame_finish_time_;
new_reporter->main_frame_abort_time_ = main_frame_abort_time_;
@@ -576,7 +587,7 @@ CompositorFrameReporter::CopyReporterAtBeginImplStage() {
// Set up the new reporter so that it depends on |this| for partial update
// information.
- new_reporter->SetPartialUpdateDecider(weak_factory_.GetWeakPtr());
+ new_reporter->SetPartialUpdateDecider(this);
return new_reporter;
}
@@ -672,10 +683,17 @@ void CompositorFrameReporter::SetVizBreakdown(
viz_breakdown_ = viz_breakdown;
}
-void CompositorFrameReporter::SetEventsMetrics(
+void CompositorFrameReporter::AddEventsMetrics(
EventMetrics::List events_metrics) {
- DCHECK_EQ(0u, events_metrics_.size());
- events_metrics_ = std::move(events_metrics);
+ events_metrics_.insert(events_metrics_.end(),
+ std::make_move_iterator(events_metrics.begin()),
+ std::make_move_iterator(events_metrics.end()));
+}
+
+EventMetrics::List CompositorFrameReporter::TakeEventsMetrics() {
+ EventMetrics::List result = std::move(events_metrics_);
+ events_metrics_.clear();
+ return result;
}
void CompositorFrameReporter::TerminateReporter() {
@@ -1059,11 +1077,26 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents() const {
reporter->set_state(state);
reporter->set_frame_source(args_.frame_id.source_id);
reporter->set_frame_sequence(args_.frame_id.sequence_number);
+ reporter->set_has_missing_content(has_missing_content_);
if (IsDroppedFrameAffectingSmoothness()) {
DCHECK(state == ChromeFrameReporter::STATE_DROPPED ||
state == ChromeFrameReporter::STATE_PRESENTED_PARTIAL);
reporter->set_affects_smoothness(true);
}
+ ChromeFrameReporter::ScrollState scroll_state;
+ switch (scrolling_thread_) {
+ case FrameSequenceMetrics::ThreadType::kMain:
+ scroll_state = ChromeFrameReporter::SCROLL_MAIN_THREAD;
+ break;
+ case FrameSequenceMetrics::ThreadType::kCompositor:
+ scroll_state = ChromeFrameReporter::SCROLL_COMPOSITOR_THREAD;
+ break;
+ case FrameSequenceMetrics::ThreadType::kUnknown:
+ scroll_state = ChromeFrameReporter::SCROLL_NONE;
+ break;
+ }
+ reporter->set_scroll_state(scroll_state);
+
// TODO(crbug.com/1086974): Set 'drop reason' if applicable.
});
@@ -1255,10 +1288,6 @@ bool CompositorFrameReporter::IsDroppedFrameAffectingSmoothness() const {
return false;
}
-base::WeakPtr<CompositorFrameReporter> CompositorFrameReporter::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
void CompositorFrameReporter::AdoptReporter(
std::unique_ptr<CompositorFrameReporter> reporter) {
// If |this| reporter is dependent on another reporter to decide about partial
@@ -1270,32 +1299,36 @@ void CompositorFrameReporter::AdoptReporter(
}
void CompositorFrameReporter::SetPartialUpdateDecider(
- base::WeakPtr<CompositorFrameReporter> decider) {
+ CompositorFrameReporter* decider) {
DCHECK(decider);
+ DCHECK(partial_update_dependents_.empty());
has_partial_update_ = true;
- partial_update_decider_ = decider;
+ partial_update_decider_ = decider->GetWeakPtr();
decider->partial_update_dependents_.push(GetWeakPtr());
- DCHECK(partial_update_dependents_.empty());
}
void CompositorFrameReporter::DiscardOldPartialUpdateReporters() {
DCHECK_LE(owned_partial_update_dependents_.size(),
partial_update_dependents_.size());
- while (owned_partial_update_dependents_.size() > 300u) {
+ // Remove old owned partial update dependents if there are too many.
+ while (owned_partial_update_dependents_.size() >
+ kMaxOwnedPartialUpdateDependents) {
auto& dependent = owned_partial_update_dependents_.front();
dependent->set_has_partial_update(false);
- partial_update_dependents_.pop();
owned_partial_update_dependents_.pop();
discarded_partial_update_dependents_count_++;
}
-}
-bool CompositorFrameReporter::MightHavePartialUpdate() const {
- return !!partial_update_decider_;
+ // Remove dependent reporters from the front of `partial_update_dependents_`
+ // queue if they are already destroyed.
+ while (!partial_update_dependents_.empty() &&
+ !partial_update_dependents_.front()) {
+ partial_update_dependents_.pop();
+ }
}
-size_t CompositorFrameReporter::GetPartialUpdateDependentsCount() const {
- return partial_update_dependents_.size();
+base::WeakPtr<CompositorFrameReporter> CompositorFrameReporter::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
}
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_frame_reporter.h b/chromium/cc/metrics/compositor_frame_reporter.h
index 0e9f0001b06..52cd56f5be1 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.h
+++ b/chromium/cc/metrics/compositor_frame_reporter.h
@@ -231,6 +231,7 @@ class CC_EXPORT CompositorFrameReporter {
LatencyUkmReporter* latency_ukm_reporter,
bool should_report_metrics,
SmoothThread smooth_thread,
+ FrameSequenceMetrics::ThreadType scrolling_thread,
int layer_tree_host_id,
DroppedFrameCounter* dropped_frame_counter);
~CompositorFrameReporter();
@@ -254,9 +255,11 @@ class CC_EXPORT CompositorFrameReporter {
void SetBlinkBreakdown(std::unique_ptr<BeginMainFrameMetrics> blink_breakdown,
base::TimeTicks begin_main_start);
void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown);
- void SetEventsMetrics(EventMetrics::List events_metrics);
- int StageHistorySizeForTesting() { return stage_history_.size(); }
+ void AddEventsMetrics(EventMetrics::List events_metrics);
+ EventMetrics::List TakeEventsMetrics();
+
+ int stage_history_size_for_testing() const { return stage_history_.size(); }
void OnFinishImplFrame(base::TimeTicks timestamp);
void OnAbortBeginMainFrame(base::TimeTicks timestamp);
@@ -288,10 +291,19 @@ class CC_EXPORT CompositorFrameReporter {
tick_clock_ = tick_clock;
}
- void SetPartialUpdateDecider(base::WeakPtr<CompositorFrameReporter> decider);
+ void set_has_missing_content(bool has_missing_content) {
+ has_missing_content_ = has_missing_content;
+ }
+
+ void SetPartialUpdateDecider(CompositorFrameReporter* decider);
- bool MightHavePartialUpdate() const;
- size_t GetPartialUpdateDependentsCount() const;
+ size_t partial_update_dependents_size_for_testing() const {
+ return partial_update_dependents_.size();
+ }
+
+ size_t owned_partial_update_dependents_size_for_testing() const {
+ return owned_partial_update_dependents_.size();
+ }
const viz::BeginFrameId& frame_id() const { return args_.frame_id; }
@@ -303,12 +315,10 @@ class CC_EXPORT CompositorFrameReporter {
// If this is a cloned reporter, then this returns a weak-ptr to the original
// reporter this was cloned from (using |CopyReporterAtBeginImplStage()|).
- base::WeakPtr<CompositorFrameReporter> partial_update_decider() {
- return partial_update_decider_;
+ CompositorFrameReporter* partial_update_decider() const {
+ return partial_update_decider_.get();
}
- base::WeakPtr<CompositorFrameReporter> GetWeakPtr();
-
protected:
void set_has_partial_update(bool has_partial_update) {
has_partial_update_ = has_partial_update;
@@ -354,6 +364,8 @@ class CC_EXPORT CompositorFrameReporter {
bool IsDroppedFrameAffectingSmoothness() const;
+ base::WeakPtr<CompositorFrameReporter> GetWeakPtr();
+
const bool should_report_metrics_;
const viz::BeginFrameArgs args_;
@@ -384,6 +396,7 @@ class CC_EXPORT CompositorFrameReporter {
FrameTerminationStatus::kUnknown;
const ActiveTrackers active_trackers_;
+ const FrameSequenceMetrics::ThreadType scrolling_thread_;
LatencyUkmReporter* latency_ukm_reporter_;
@@ -407,6 +420,10 @@ class CC_EXPORT CompositorFrameReporter {
const SmoothThread smooth_thread_;
const int layer_tree_host_id_;
+ // Indicates whether the submitted frame had any missing content (i.e. content
+ // with checkerboarding).
+ bool has_missing_content_ = false;
+
// For a reporter A, if the main-thread takes a long time to respond
// to a begin-main-frame, then all reporters created (and terminated) until
// the main-thread responds depends on this reporter to decide whether those
diff --git a/chromium/cc/metrics/compositor_frame_reporter_unittest.cc b/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
index e7a38ba77fc..48a06f46119 100644
--- a/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -30,16 +30,7 @@ using ::testing::NotNull;
class CompositorFrameReporterTest : public testing::Test {
public:
- CompositorFrameReporterTest()
- : pipeline_reporter_(std::make_unique<CompositorFrameReporter>(
- CompositorFrameReporter::ActiveTrackers(),
- viz::BeginFrameArgs(),
- nullptr,
- /*should_report_metrics=*/true,
- CompositorFrameReporter::SmoothThread::kSmoothBoth,
- /*layer_tree_host_id=*/1,
- &dropped_frame_counter_)) {
- pipeline_reporter_->set_tick_clock(&test_tick_clock_);
+ CompositorFrameReporterTest() : pipeline_reporter_(CreatePipelineReporter()) {
AdvanceNowByMs(1);
dropped_frame_counter_.set_total_counter(&total_frame_counter_);
}
@@ -115,6 +106,18 @@ class CompositorFrameReporterTest : public testing::Test {
return event_times;
}
+ std::unique_ptr<CompositorFrameReporter> CreatePipelineReporter() {
+ auto reporter = std::make_unique<CompositorFrameReporter>(
+ CompositorFrameReporter::ActiveTrackers(), viz::BeginFrameArgs(),
+ /*latency_ukm_reporter=*/nullptr,
+ /*should_report_metrics=*/true,
+ CompositorFrameReporter::SmoothThread::kSmoothBoth,
+ FrameSequenceMetrics::ThreadType::kUnknown,
+ /*layer_tree_host_id=*/1, &dropped_frame_counter_);
+ reporter->set_tick_clock(&test_tick_clock_);
+ return reporter;
+ }
+
// This should be defined before |pipeline_reporter_| so it is created before
// and destroyed after that.
base::SimpleTestTickClock test_tick_clock_;
@@ -130,30 +133,30 @@ TEST_F(CompositorFrameReporterTest, MainFrameAbortedReportingTest) {
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
Now());
- EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(0, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
- EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(1, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
- EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(2, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
- EXPECT_EQ(3, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(3, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
- EXPECT_EQ(4, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(4, pipeline_reporter_->stage_history_size_for_testing());
pipeline_reporter_ = nullptr;
histogram_tester.ExpectTotalCount(
@@ -175,18 +178,18 @@ TEST_F(CompositorFrameReporterTest, ReplacedByNewReporterReportingTest) {
pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
Now());
- EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(0, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
- EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(1, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(2);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter,
Now());
- EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(2, pipeline_reporter_->stage_history_size_for_testing());
pipeline_reporter_ = nullptr;
histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0);
@@ -199,18 +202,18 @@ TEST_F(CompositorFrameReporterTest, SubmittedFrameReportingTest) {
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kActivation, Now());
- EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(0, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
- EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(1, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(2);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
- EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(2, pipeline_reporter_->stage_history_size_for_testing());
pipeline_reporter_ = nullptr;
histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 1);
@@ -235,18 +238,18 @@ TEST_F(CompositorFrameReporterTest, SubmittedDroppedFrameReportingTest) {
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
- EXPECT_EQ(0, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(0, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
Now());
- EXPECT_EQ(1, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(1, pipeline_reporter_->stage_history_size_for_testing());
AdvanceNowByMs(2);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame,
Now());
- EXPECT_EQ(2, pipeline_reporter_->StageHistorySizeForTesting());
+ EXPECT_EQ(2, pipeline_reporter_->stage_history_size_for_testing());
pipeline_reporter_ = nullptr;
histogram_tester.ExpectTotalCount(
@@ -299,7 +302,7 @@ TEST_F(CompositorFrameReporterTest,
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
- pipeline_reporter_->SetEventsMetrics(std::move(events_metrics));
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
const base::TimeTicks presentation_time = AdvanceNowByMs(3);
pipeline_reporter_->TerminateFrame(
@@ -381,7 +384,7 @@ TEST_F(CompositorFrameReporterTest,
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
- pipeline_reporter_->SetEventsMetrics(std::move(events_metrics));
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
AdvanceNowByMs(3);
viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
@@ -467,7 +470,7 @@ TEST_F(CompositorFrameReporterTest,
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
- pipeline_reporter_->SetEventsMetrics(std::move(events_metrics));
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
AdvanceNowByMs(3);
pipeline_reporter_->TerminateFrame(
@@ -480,5 +483,122 @@ TEST_F(CompositorFrameReporterTest,
IsEmpty());
}
+// Verifies that partial update dependent queues are working as expected when
+// they reach their maximum capacity.
+TEST_F(CompositorFrameReporterTest, PartialUpdateDependentQueues) {
+ // This constant should match the constant with the same name in
+ // compositor_frame_reporter.cc.
+ const size_t kMaxOwnedPartialUpdateDependents = 300u;
+
+ // The first three dependent reporters for the front of the queue.
+ std::unique_ptr<CompositorFrameReporter> deps[] = {
+ CreatePipelineReporter(),
+ CreatePipelineReporter(),
+ CreatePipelineReporter(),
+ };
+
+ // Set `deps[0]` as a dependent of the main reporter and adopt it at the same
+ // time. This should enqueue it in both non-owned and owned dependents queues.
+ deps[0]->SetPartialUpdateDecider(pipeline_reporter_.get());
+ pipeline_reporter_->AdoptReporter(std::move(deps[0]));
+ DCHECK_EQ(1u,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ 1u,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Set `deps[1]` as a dependent of the main reporter, but don't adopt it yet.
+ // This should enqueue it in non-owned dependents queue only.
+ deps[1]->SetPartialUpdateDecider(pipeline_reporter_.get());
+ DCHECK_EQ(2u,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ 1u,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Set `deps[2]` as a dependent of the main reporter and adopt it at the same
+ // time. This should enqueue it in both non-owned and owned dependents queues.
+ deps[2]->SetPartialUpdateDecider(pipeline_reporter_.get());
+ pipeline_reporter_->AdoptReporter(std::move(deps[2]));
+ DCHECK_EQ(3u,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ 2u,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Now adopt `deps[1]` to enqueue it in the owned dependents queue.
+ pipeline_reporter_->AdoptReporter(std::move(deps[1]));
+ DCHECK_EQ(3u,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ 3u,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Fill the queues with more dependent reporters until the capacity is
+ // reached. After this, the queues should look like this (assuming n equals
+ // `kMaxOwnedPartialUpdateDependents`):
+ // Partial Update Dependents: [0, 1, 2, 3, 4, ..., n-1]
+ // Owned Partial Update Dependents: [0, 2, 1, 3, 4, ..., n-1]
+ while (
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing() <
+ kMaxOwnedPartialUpdateDependents) {
+ std::unique_ptr<CompositorFrameReporter> dependent =
+ CreatePipelineReporter();
+ dependent->SetPartialUpdateDecider(pipeline_reporter_.get());
+ pipeline_reporter_->AdoptReporter(std::move(dependent));
+ }
+ DCHECK_EQ(kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Enqueue a new dependent reporter. This should pop `deps[0]` from the front
+ // of the owned dependents queue and destroy it. Since the same one is in
+ // front of the non-owned dependents queue, it will be popped out of that
+ // queue, too. The queues will look like this:
+ // Partial Update Dependents: [1, 2, 3, 4, ..., n]
+ // Owned Partial Update Dependents: [2, 1, 3, 4, ..., n]
+ auto new_dep = CreatePipelineReporter();
+ new_dep->SetPartialUpdateDecider(pipeline_reporter_.get());
+ pipeline_reporter_->AdoptReporter(std::move(new_dep));
+ DCHECK_EQ(kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Enqueue another new dependent reporter. This should pop `deps[2]` from the
+ // front of the owned dependents queue and destroy it. Since another reporter
+ // is in front of the non-owned dependents queue it won't be popped out of
+ // that queue. The queues will look like this:
+ // Partial Update Dependents: [2, 3, 4, ..., n+1]
+ // Owned Partial Update Dependents: [2, nullptr, 3, 4, ..., n+1]
+ new_dep = CreatePipelineReporter();
+ new_dep->SetPartialUpdateDecider(pipeline_reporter_.get());
+ pipeline_reporter_->AdoptReporter(std::move(new_dep));
+ DCHECK_EQ(kMaxOwnedPartialUpdateDependents + 1,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+
+ // Enqueue yet another new dependent reporter. This should pop `deps[1]` from
+ // the front of the owned dependents queue and destroy it. Since the same one
+ // is in front of the non-owned dependents queue followed by `deps[2]` which
+ // was destroyed in the previous step, they will be popped out of that queue,
+ // too. The queues will look like this:
+ // Partial Update Dependents: [3, 4, ..., n+2]
+ // Owned Partial Update Dependents: [3, 4, ..., n+2]
+ new_dep = CreatePipelineReporter();
+ new_dep->SetPartialUpdateDecider(pipeline_reporter_.get());
+ pipeline_reporter_->AdoptReporter(std::move(new_dep));
+ DCHECK_EQ(kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->partial_update_dependents_size_for_testing());
+ DCHECK_EQ(
+ kMaxOwnedPartialUpdateDependents,
+ pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.cc b/chromium/cc/metrics/compositor_frame_reporting_controller.cc
index dec573d13d9..279c9547e70 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller.cc
@@ -94,8 +94,8 @@ void CompositorFrameReportingController::WillBeginImplFrame(
}
auto reporter = std::make_unique<CompositorFrameReporter>(
active_trackers_, args, latency_ukm_reporter_.get(),
- should_report_metrics_, GetSmoothThread(), layer_tree_host_id_,
- dropped_frame_counter_);
+ should_report_metrics_, GetSmoothThread(), scrolling_thread_,
+ layer_tree_host_id_, dropped_frame_counter_);
reporter->set_tick_clock(tick_clock_);
reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
begin_time);
@@ -121,8 +121,8 @@ void CompositorFrameReportingController::WillBeginMainFrame(
// deadline yet). So will start a new reporter at BeginMainFrame.
auto reporter = std::make_unique<CompositorFrameReporter>(
active_trackers_, args, latency_ukm_reporter_.get(),
- should_report_metrics_, GetSmoothThread(), layer_tree_host_id_,
- dropped_frame_counter_);
+ should_report_metrics_, GetSmoothThread(), scrolling_thread_,
+ layer_tree_host_id_, dropped_frame_counter_);
reporter->set_tick_clock(tick_clock_);
reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now());
reporters_[PipelineStage::kBeginMainFrame] = std::move(reporter);
@@ -177,7 +177,8 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
uint32_t frame_token,
const viz::BeginFrameId& current_frame_id,
const viz::BeginFrameId& last_activated_frame_id,
- EventMetricsSet events_metrics) {
+ EventMetricsSet events_metrics,
+ bool has_missing_content) {
bool is_activated_frame_new =
(last_activated_frame_id != last_submitted_frame_id_);
@@ -222,8 +223,8 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
AdvanceReporterStage(PipelineStage::kBeginImplFrame,
PipelineStage::kActivate);
impl_reporter = std::move(reporters_[PipelineStage::kActivate]);
- auto partial_update_decider =
- HasOutstandingUpdatesFromMain(current_frame_id);
+ CompositorFrameReporter* partial_update_decider =
+ GetOutstandingUpdatesFromMain(current_frame_id);
if (partial_update_decider)
impl_reporter->SetPartialUpdateDecider(partial_update_decider);
} else if (CanSubmitMainFrame(current_frame_id)) {
@@ -277,8 +278,9 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
if (main_reporter) {
main_reporter->StartStage(
StageType::kSubmitCompositorFrameToPresentationCompositorFrame, Now());
- main_reporter->SetEventsMetrics(
+ main_reporter->AddEventsMetrics(
std::move(events_metrics.main_event_metrics));
+ main_reporter->set_has_missing_content(has_missing_content);
submitted_compositor_frames_.emplace_back(frame_token,
std::move(main_reporter));
}
@@ -287,8 +289,9 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
impl_reporter->EnableCompositorOnlyReporting();
impl_reporter->StartStage(
StageType::kSubmitCompositorFrameToPresentationCompositorFrame, Now());
- impl_reporter->SetEventsMetrics(
+ impl_reporter->AddEventsMetrics(
std::move(events_metrics.impl_event_metrics));
+ impl_reporter->set_has_missing_content(has_missing_content);
submitted_compositor_frames_.emplace_back(frame_token,
std::move(impl_reporter));
}
@@ -333,8 +336,8 @@ void CompositorFrameReportingController::
} else {
// The stage_reporter in this case was waiting for main, so needs to
// be adopted by the reporter which is waiting on Main thread's work
- auto partial_update_decider =
- HasOutstandingUpdatesFromMain(stage_reporter->frame_id());
+ CompositorFrameReporter* partial_update_decider =
+ GetOutstandingUpdatesFromMain(stage_reporter->frame_id());
if (partial_update_decider) {
stage_reporter->SetPartialUpdateDecider(partial_update_decider);
stage_reporter->OnDidNotProduceFrame(FrameSkippedReason::kWaitingOnMain);
@@ -358,37 +361,96 @@ void CompositorFrameReportingController::OnFinishImplFrame(
void CompositorFrameReportingController::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) {
- while (!submitted_compositor_frames_.empty()) {
- auto submitted_frame = submitted_compositor_frames_.begin();
- if (viz::FrameTokenGT(submitted_frame->frame_token, frame_token))
- break;
+ bool feedback_failed = details.presentation_feedback.failed();
+ for (auto submitted_frame = submitted_compositor_frames_.begin();
+ submitted_frame != submitted_compositor_frames_.end() &&
+ !viz::FrameTokenGT(submitted_frame->frame_token, frame_token);) {
+ bool is_earlier_frame = submitted_frame->frame_token != frame_token;
+
+ // If the presentation feedback is a failure, earlier frames should still be
+ // left in the queue as they still might end up being presented
+ // successfully. Skip to the next frame.
+ if (feedback_failed && is_earlier_frame) {
+ submitted_frame++;
+ continue;
+ }
- auto termination_status = FrameTerminationStatus::kPresentedFrame;
- if (submitted_frame->frame_token != frame_token ||
- details.presentation_feedback.failed()) {
+ auto termination_status = feedback_failed
+ ? FrameTerminationStatus::kDidNotPresentFrame
+ : FrameTerminationStatus::kPresentedFrame;
+
+ // If this is an earlier frame, presentation feedback has been successful
+ // which means this earlier frame should be considered dropped.
+ if (is_earlier_frame)
termination_status = FrameTerminationStatus::kDidNotPresentFrame;
- }
auto& reporter = submitted_frame->reporter;
reporter->SetVizBreakdown(details);
reporter->TerminateFrame(termination_status,
details.presentation_feedback.timestamp);
- // If |reporter| was cloned from a reporter, and the original reporter is
- // still alive, then check whether the cloned reporter has the 'partial
- // update' flag set. It is still possible for the original reporter to
- // terminate with 'no damage', and if that happens, then the cloned
- // reporter's 'partial update' flag will need to be reset. To allow this to
- // happen, keep the cloned reporter alive, and hand over its ownership to
- // the original reporter, so that the cloned reporter stays alive until the
- // original reporter is terminated, and the cloned reporter's 'partial
- // update' flag can be unset if necessary.
- if (reporter->MightHavePartialUpdate()) {
- auto orig_reporter = reporter->partial_update_decider();
- if (orig_reporter)
+ if (termination_status == FrameTerminationStatus::kPresentedFrame) {
+ // If there are outstanding metrics from dropped frames older than this
+ // frame, this frame would be the first frame presented after those
+ // dropped frames. So, this frame is the one presenting updates from those
+ // frames to the user and should report metrics for them. Note that since
+ // reporters for submitted but dropped frames are terminated before any
+ // following frame being presented, all events metrics that should
+ // potentially be included in this presented frame are already in
+ // `events_metrics_from_dropped_frames_`.
+ for (auto it = events_metrics_from_dropped_frames_.begin();
+ it != events_metrics_from_dropped_frames_.end() &&
+ !(reporter->frame_id() < it->first);
+ it = events_metrics_from_dropped_frames_.erase(it)) {
+ reporter->AddEventsMetrics(std::move(it->second));
+ }
+
+ // For presented frames, if `reporter` was cloned from another reporter,
+ // and the original reporter is still alive, then check whether the cloned
+ // reporter has a 'partial update decider'. It is still possible for the
+ // original reporter to terminate with 'no damage', and if that happens,
+ // then the cloned reporter's 'partial update' flag will need to be reset.
+ // To allow this to happen, keep the cloned reporter alive, and hand over
+ // its ownership to the original reporter, so that the cloned reporter
+ // stays alive until the original reporter is terminated, and the cloned
+ // reporter's 'partial update' flag can be unset if necessary. This is not
+ // necessary for frames with failed presentation as we can say for sure
+ // that they are dropped and nothing will change their fate.
+ if (CompositorFrameReporter* orig_reporter =
+ reporter->partial_update_decider()) {
orig_reporter->AdoptReporter(std::move(reporter));
+ }
+ } else {
+ // If the frame didn't end up being presented, keep its metrics around to
+ // be reported with the first following presented frame.
+ auto reporter_events_metrics = reporter->TakeEventsMetrics();
+ if (!reporter_events_metrics.empty()) {
+ auto& frame_events_metrics =
+ events_metrics_from_dropped_frames_[reporter->frame_id()];
+ frame_events_metrics.insert(
+ frame_events_metrics.end(),
+ std::make_move_iterator(reporter_events_metrics.begin()),
+ std::make_move_iterator(reporter_events_metrics.end()));
+ }
+ }
+
+ if (feedback_failed) {
+ // When feedback is for a failed presentation, `submitted_frame` is not
+ // necessarily in the front of the queue. We will reach here only once per
+ // did-present; so, we will have 1 operation of O(n) complexity (n is the
+ // number of previous frames).
+ submitted_frame = submitted_compositor_frames_.erase(submitted_frame);
+ } else {
+ // When feedback is for a successful presentation, `submitted_frame` is in
+ // the front of the queue; so, we will have n operations of O(1)
+ // complexity for a did-present (n is the number of previous frames).
+ // `pop_front()` function is used here to shrink the queue when necessary
+ // to avoid unnecessary memory usage over time.
+ DCHECK_EQ(submitted_frame->frame_token,
+ submitted_compositor_frames_.front().frame_token);
+ submitted_compositor_frames_.pop_front();
+ submitted_frame = submitted_compositor_frames_.begin();
}
- submitted_compositor_frames_.erase(submitted_frame);
}
}
@@ -427,6 +489,11 @@ void CompositorFrameReportingController::RemoveActiveTracker(
dropped_frame_counter_->ReportFrames();
}
+void CompositorFrameReportingController::SetScrollingThread(
+ FrameSequenceMetrics::ThreadType thread) {
+ scrolling_thread_ = thread;
+}
+
void CompositorFrameReportingController::SetThreadAffectsSmoothness(
FrameSequenceMetrics::ThreadType thread_type,
bool affects_smoothness) {
@@ -532,8 +599,8 @@ CompositorFrameReportingController::GetSmoothThreadAtTime(
return smooth_thread_history_.lower_bound(timestamp)->second;
}
-base::WeakPtr<CompositorFrameReporter>
-CompositorFrameReportingController::HasOutstandingUpdatesFromMain(
+CompositorFrameReporter*
+CompositorFrameReportingController::GetOutstandingUpdatesFromMain(
const viz::BeginFrameId& id) const {
// Any unterminated reporter in the 'main frame', or 'commit' stages, then
// that indicates some pending updates from the main thread.
@@ -541,17 +608,17 @@ CompositorFrameReportingController::HasOutstandingUpdatesFromMain(
const auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
if (reporter && reporter->frame_id() < id &&
!reporter->did_abort_main_frame()) {
- return reporter->GetWeakPtr();
+ return reporter.get();
}
}
{
const auto& reporter = reporters_[PipelineStage::kCommit];
if (reporter && reporter->frame_id() < id) {
DCHECK(!reporter->did_abort_main_frame());
- return reporter->GetWeakPtr();
+ return reporter.get();
}
}
- return {};
+ return nullptr;
}
void CompositorFrameReportingController::CreateReportersForDroppedFrames(
@@ -577,10 +644,15 @@ void CompositorFrameReportingController::CreateReportersForDroppedFrames(
old_args.frame_id.sequence_number + i, timestamp,
timestamp + old_args.interval, old_args.interval,
viz::BeginFrameArgs::NORMAL);
+ // ThreadType::kUnknown is used here for scrolling thread, because the
+ // frames reported here could have a scroll interaction active at their
+ // start time, but they were skipped and history of scrolling thread might
+ // change in the diff of start time and report time.
auto reporter = std::make_unique<CompositorFrameReporter>(
active_trackers_, args, latency_ukm_reporter_.get(),
should_report_metrics_, GetSmoothThreadAtTime(timestamp),
- layer_tree_host_id_, dropped_frame_counter_);
+ FrameSequenceMetrics::ThreadType::kUnknown, layer_tree_host_id_,
+ dropped_frame_counter_);
reporter->set_tick_clock(tick_clock_);
reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
timestamp);
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.h b/chromium/cc/metrics/compositor_frame_reporting_controller.h
index 9054c0a325a..e7c6863077b 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller.h
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller.h
@@ -64,7 +64,8 @@ class CC_EXPORT CompositorFrameReportingController {
uint32_t frame_token,
const viz::BeginFrameId& current_frame_id,
const viz::BeginFrameId& last_activated_frame_id,
- EventMetricsSet events_metrics);
+ EventMetricsSet events_metrics,
+ bool has_missing_content);
virtual void DidNotProduceFrame(const viz::BeginFrameId& id,
FrameSkippedReason skip_reason);
virtual void OnFinishImplFrame(const viz::BeginFrameId& id);
@@ -80,6 +81,7 @@ class CC_EXPORT CompositorFrameReportingController {
void AddActiveTracker(FrameSequenceTrackerType type);
void RemoveActiveTracker(FrameSequenceTrackerType type);
+ void SetScrollingThread(FrameSequenceMetrics::ThreadType thread);
void SetThreadAffectsSmoothness(FrameSequenceMetrics::ThreadType thread_type,
bool affects_smoothness);
@@ -126,9 +128,9 @@ class CC_EXPORT CompositorFrameReportingController {
base::TimeTicks timestamp) const;
// Checks whether there are reporters containing updates from the main
- // thread, and returns a weak-ptr to that reporter (if any). Otherwise returns
- // null.
- base::WeakPtr<CompositorFrameReporter> HasOutstandingUpdatesFromMain(
+ // thread, and returns a pointer to that reporter (if any). Otherwise
+ // returns nullptr.
+ CompositorFrameReporter* GetOutstandingUpdatesFromMain(
const viz::BeginFrameId& id) const;
// If the display-compositor skips over some frames (e.g. when the gpu is
@@ -153,18 +155,20 @@ class CC_EXPORT CompositorFrameReportingController {
bool next_activate_has_invalidation_ = false;
CompositorFrameReporter::ActiveTrackers active_trackers_;
+ FrameSequenceMetrics::ThreadType scrolling_thread_ =
+ FrameSequenceMetrics::ThreadType::kUnknown;
bool is_compositor_thread_driving_smoothness_ = false;
bool is_main_thread_driving_smoothness_ = false;
- // Sorted history of smooththread. Element i indicating the smooththread from
- // timestamp of element i-1 until timestamp of element i.
+ // Sorted history of smooththread. Element i indicating the smooththread
+ // from timestamp of element i-1 until timestamp of element i.
std::map<base::TimeTicks, CompositorFrameReporter::SmoothThread>
smooth_thread_history_;
// The latency reporter passed to each CompositorFrameReporter. Owned here
// because it must be common among all reporters.
- // DO NOT reorder this line and the ones below. The latency_ukm_reporter_ must
- // outlive the objects in |submitted_compositor_frames_|.
+ // DO NOT reorder this line and the ones below. The latency_ukm_reporter_
+ // must outlive the objects in |submitted_compositor_frames_|.
std::unique_ptr<LatencyUkmReporter> latency_ukm_reporter_;
std::unique_ptr<CompositorFrameReporter>
@@ -172,8 +176,8 @@ class CC_EXPORT CompositorFrameReportingController {
// Mapping of frame token to pipeline reporter for submitted compositor
// frames.
- // DO NOT reorder this line and the one above. The latency_ukm_reporter_ must
- // outlive the objects in |submitted_compositor_frames_|.
+ // DO NOT reorder this line and the one above. The latency_ukm_reporter_
+ // must outlive the objects in |submitted_compositor_frames_|.
base::circular_deque<SubmittedCompositorFrame> submitted_compositor_frames_;
// The latest frame that was started.
@@ -182,6 +186,12 @@ class CC_EXPORT CompositorFrameReportingController {
const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance();
DroppedFrameCounter* dropped_frame_counter_ = nullptr;
+
+ // When a frame with events metrics fails to be presented, its events metrics
+ // will be added to this map. The first following presented frame will get
+ // these metrics and report them.
+ std::map<viz::BeginFrameId, EventMetrics::List>
+ events_metrics_from_dropped_frames_;
};
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc
index 8f13ac70623..4c0ed45e74c 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -66,7 +66,8 @@ class TestCompositorFrameReportingController
};
for (auto stage : kStages) {
auto& reporter = reporters()[stage];
- if (reporter && reporter->GetPartialUpdateDependentsCount() > 0) {
+ if (reporter &&
+ reporter->partial_update_dependents_size_for_testing() > 0) {
++count;
}
}
@@ -84,7 +85,23 @@ class TestCompositorFrameReportingController
for (auto stage : kStages) {
auto& reporter = reporters()[stage];
if (reporter)
- count += reporter->GetPartialUpdateDependentsCount();
+ count += reporter->partial_update_dependents_size_for_testing();
+ }
+ return count;
+ }
+
+ size_t GetAdoptedReportersCount() {
+ size_t count = 0;
+ const PipelineStage kStages[] = {
+ PipelineStage::kBeginImplFrame,
+ PipelineStage::kBeginMainFrame,
+ PipelineStage::kCommit,
+ PipelineStage::kActivate,
+ };
+ for (auto stage : kStages) {
+ auto& reporter = reporters()[stage];
+ if (reporter)
+ count += reporter->owned_partial_update_dependents_size_for_testing();
}
return count;
}
@@ -96,8 +113,8 @@ class CompositorFrameReportingControllerTest : public testing::Test {
test_tick_clock_.SetNowTicks(base::TimeTicks::Now());
reporting_controller_.set_tick_clock(&test_tick_clock_);
args_ = SimulateBeginFrameArgs(current_id_);
- reporting_controller_.SetDroppedFrameCounter(&dropped_counter);
- dropped_counter.set_total_counter(&total_frame_counter_);
+ reporting_controller_.SetDroppedFrameCounter(&dropped_counter_);
+ dropped_counter_.set_total_counter(&total_frame_counter_);
}
// The following functions simulate the actions that would
@@ -150,25 +167,25 @@ class CompositorFrameReportingControllerTest : public testing::Test {
last_activated_id_ = current_id_;
}
- void SimulateSubmitCompositorFrame(uint32_t frame_token,
- EventMetricsSet events_metrics) {
+ void SimulateSubmitCompositorFrame(EventMetricsSet events_metrics) {
if (!reporting_controller_.reporters()
[CompositorFrameReportingController::PipelineStage::kActivate])
SimulateActivate();
CHECK(reporting_controller_.reporters()
[CompositorFrameReportingController::PipelineStage::kActivate]);
submit_time_ = AdvanceNowByMs(10);
- reporting_controller_.DidSubmitCompositorFrame(frame_token, current_id_,
- last_activated_id_,
- std::move(events_metrics));
+ ++current_token_;
+ reporting_controller_.DidSubmitCompositorFrame(
+ *current_token_, current_id_, last_activated_id_,
+ std::move(events_metrics),
+ /*has_missing_content=*/false);
}
void SimulatePresentCompositorFrame() {
- ++next_token_;
- SimulateSubmitCompositorFrame(*next_token_, {});
+ SimulateSubmitCompositorFrame({});
viz::FrameTimingDetails details = {};
details.presentation_feedback.timestamp = AdvanceNowByMs(10);
- reporting_controller_.DidPresentCompositorFrame(*next_token_, details);
+ reporting_controller_.DidPresentCompositorFrame(*current_token_, details);
}
viz::BeginFrameArgs SimulateBeginFrameArgs(viz::BeginFrameId frame_id) {
@@ -269,8 +286,8 @@ class CompositorFrameReportingControllerTest : public testing::Test {
base::TimeTicks begin_activation_time_;
base::TimeTicks end_activation_time_;
base::TimeTicks submit_time_;
- viz::FrameTokenGenerator next_token_;
- DroppedFrameCounter dropped_counter;
+ viz::FrameTokenGenerator current_token_;
+ DroppedFrameCounter dropped_counter_;
TotalFrameCounter total_frame_counter_;
};
@@ -340,8 +357,8 @@ TEST_F(CompositorFrameReportingControllerTest, ActiveReporterCounts) {
EXPECT_EQ(1, reporting_controller_.ActiveReporters());
last_activated_id_ = current_id_3;
- reporting_controller_.DidSubmitCompositorFrame(0, current_id_3,
- last_activated_id_, {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 0, current_id_3, last_activated_id_, {}, /*has_missing_content=*/false);
EXPECT_EQ(0, reporting_controller_.ActiveReporters());
// Start a frame and take it all the way to the activate stage.
@@ -501,8 +518,8 @@ TEST_F(CompositorFrameReportingControllerTest, DidNotProduceFrame) {
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_2, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_2, current_id_1, {}, /*has_missing_content=*/false);
viz::FrameTimingDetails details = {};
reporting_controller_.DidPresentCompositorFrame(1, details);
@@ -567,8 +584,8 @@ TEST_F(CompositorFrameReportingControllerTest,
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
reporting_controller_.OnFinishImplFrame(current_id_3);
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_3, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_3, current_id_1, {}, /*has_missing_content=*/false);
viz::FrameTimingDetails details;
details.presentation_feedback = {args_3.frame_time + args_3.interval,
args_3.interval, 0};
@@ -599,8 +616,8 @@ TEST_F(CompositorFrameReportingControllerTest, MainFrameAborted) {
reporting_controller_.WillBeginMainFrame(args_);
reporting_controller_.BeginMainFrameAborted(current_id_);
reporting_controller_.OnFinishImplFrame(current_id_);
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_,
- last_activated_id_, {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_, last_activated_id_, {}, /*has_missing_content=*/false);
viz::FrameTimingDetails details = {};
reporting_controller_.DidPresentCompositorFrame(1, details);
@@ -654,8 +671,8 @@ TEST_F(CompositorFrameReportingControllerTest, MainFrameAborted2) {
reporting_controller_.WillBeginMainFrame(args_2);
reporting_controller_.OnFinishImplFrame(current_id_2);
reporting_controller_.BeginMainFrameAborted(current_id_2);
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_2, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_2, current_id_1, {}, /*has_missing_content=*/false);
viz::FrameTimingDetails details = {};
reporting_controller_.DidPresentCompositorFrame(1, details);
histogram_tester.ExpectTotalCount(
@@ -673,8 +690,8 @@ TEST_F(CompositorFrameReportingControllerTest, MainFrameAborted2) {
histogram_tester.ExpectTotalCount(
"CompositorLatency.SubmitCompositorFrameToPresentationCompositorFrame",
2);
- reporting_controller_.DidSubmitCompositorFrame(2, current_id_2, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 2, current_id_2, current_id_1, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(2, details);
histogram_tester.ExpectTotalCount(
"CompositorLatency.DroppedFrame.BeginImplFrameToSendBeginMainFrame", 0);
@@ -693,8 +710,8 @@ TEST_F(CompositorFrameReportingControllerTest, MainFrameAborted2) {
2);
reporting_controller_.WillBeginImplFrame(args_3);
reporting_controller_.OnFinishImplFrame(current_id_3);
- reporting_controller_.DidSubmitCompositorFrame(3, current_id_3, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 3, current_id_3, current_id_1, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(3, details);
histogram_tester.ExpectTotalCount(
"CompositorLatency.DroppedFrame.BeginImplFrameToSendBeginMainFrame", 0);
@@ -732,8 +749,8 @@ TEST_F(CompositorFrameReportingControllerTest, LongMainFrame) {
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_1, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_1, current_id_1, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(1, details);
histogram_tester.ExpectTotalCount(
@@ -755,8 +772,8 @@ TEST_F(CompositorFrameReportingControllerTest, LongMainFrame) {
reporting_controller_.WillBeginImplFrame(args_2);
reporting_controller_.WillBeginMainFrame(args_2);
reporting_controller_.OnFinishImplFrame(current_id_2);
- reporting_controller_.DidSubmitCompositorFrame(2, current_id_2, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 2, current_id_2, current_id_1, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(2, details);
// The reporting for the second frame is delayed until the main-thread
@@ -795,8 +812,8 @@ TEST_F(CompositorFrameReportingControllerTest, LongMainFrame) {
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
- reporting_controller_.DidSubmitCompositorFrame(3, current_id_3, current_id_2,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 3, current_id_3, current_id_2, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(3, details);
// The main-thread responded, so the metrics for |args_2| should now be
@@ -846,8 +863,8 @@ TEST_F(CompositorFrameReportingControllerTest, LongMainFrame2) {
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_1, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_1, current_id_1, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(1, details);
histogram_tester.ExpectTotalCount(
@@ -870,8 +887,8 @@ TEST_F(CompositorFrameReportingControllerTest, LongMainFrame2) {
reporting_controller_.WillCommit();
reporting_controller_.DidCommit();
reporting_controller_.OnFinishImplFrame(current_id_2);
- reporting_controller_.DidSubmitCompositorFrame(2, current_id_2, current_id_1,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 2, current_id_2, current_id_1, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(2, details);
histogram_tester.ExpectTotalCount(
@@ -911,8 +928,8 @@ TEST_F(CompositorFrameReportingControllerTest, LongMainFrame2) {
reporting_controller_.DidActivate();
reporting_controller_.WillBeginImplFrame(args_3);
reporting_controller_.OnFinishImplFrame(current_id_3);
- reporting_controller_.DidSubmitCompositorFrame(3, current_id_3, current_id_2,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 3, current_id_3, current_id_2, {}, /*has_missing_content=*/false);
reporting_controller_.DidPresentCompositorFrame(3, details);
histogram_tester.ExpectTotalCount(
"CompositorLatency.BeginImplFrameToSendBeginMainFrame", 4);
@@ -999,8 +1016,8 @@ TEST_F(CompositorFrameReportingControllerTest, ReportingMissedDeadlineFrame1) {
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_, current_id_,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_, current_id_, {}, /*has_missing_content=*/false);
viz::FrameTimingDetails details = {};
details.presentation_feedback.timestamp =
args_.frame_time + args_.interval * 1.5 -
@@ -1038,8 +1055,8 @@ TEST_F(CompositorFrameReportingControllerTest, ReportingMissedDeadlineFrame2) {
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
reporting_controller_.DidActivate();
- reporting_controller_.DidSubmitCompositorFrame(1, current_id_, current_id_,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1, current_id_, current_id_, {}, /*has_missing_content=*/false);
viz::FrameTimingDetails details = {};
details.presentation_feedback.timestamp =
args_.frame_time + args_.interval * 1.5 +
@@ -1113,14 +1130,13 @@ TEST_F(CompositorFrameReportingControllerTest,
// Submit a compositor frame and notify CompositorFrameReporter of the events
// affecting the frame.
- ++next_token_;
- SimulateSubmitCompositorFrame(*next_token_, {std::move(events_metrics), {}});
+ SimulateSubmitCompositorFrame({std::move(events_metrics), {}});
// Present the submitted compositor frame to the user.
const base::TimeTicks presentation_time = AdvanceNowByMs(10);
viz::FrameTimingDetails details;
details.presentation_feedback.timestamp = presentation_time;
- reporting_controller_.DidPresentCompositorFrame(*next_token_, details);
+ reporting_controller_.DidPresentCompositorFrame(*current_token_, details);
// Verify that EventLatency histograms are recorded.
struct {
@@ -1183,8 +1199,7 @@ TEST_F(CompositorFrameReportingControllerTest,
// Submit a compositor frame and notify CompositorFrameReporter of the events
// affecting the frame.
- ++next_token_;
- SimulateSubmitCompositorFrame(*next_token_, {std::move(events_metrics), {}});
+ SimulateSubmitCompositorFrame({std::move(events_metrics), {}});
// Present the submitted compositor frame to the user.
viz::FrameTimingDetails details;
@@ -1193,7 +1208,7 @@ TEST_F(CompositorFrameReportingControllerTest,
details.swap_timings.swap_start = AdvanceNowByMs(10);
details.swap_timings.swap_end = AdvanceNowByMs(10);
details.presentation_feedback.timestamp = AdvanceNowByMs(10);
- reporting_controller_.DidPresentCompositorFrame(*next_token_, details);
+ reporting_controller_.DidPresentCompositorFrame(*current_token_, details);
// Verify that EventLatency histograms are recorded.
struct {
@@ -1240,10 +1255,10 @@ TEST_F(CompositorFrameReportingControllerTest,
}
}
-// Tests that EventLatency histograms are not reported when the frame is dropped
-// and not presented to the user.
+// Tests that EventLatency histograms for events of a dropped frame are reported
+// in the first subsequent presented frame.
TEST_F(CompositorFrameReportingControllerTest,
- EventLatencyForDidNotPresentFrameNotReported) {
+ EventLatencyForDidNotPresentFrameReportedOnNextPresent) {
base::HistogramTester histogram_tester;
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
@@ -1255,25 +1270,58 @@ TEST_F(CompositorFrameReportingControllerTest,
EventMetrics::List events_metrics(
std::make_move_iterator(std::begin(event_metrics_ptrs)),
std::make_move_iterator(std::end(event_metrics_ptrs)));
+ std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
// Submit a compositor frame and notify CompositorFrameReporter of the events
// affecting the frame.
- ++next_token_;
- SimulateSubmitCompositorFrame(*next_token_, {std::move(events_metrics), {}});
+ SimulateSubmitCompositorFrame({std::move(events_metrics), {}});
// Submit another compositor frame.
- ++next_token_;
IncrementCurrentId();
- SimulateSubmitCompositorFrame(*next_token_, {});
+ SimulateSubmitCompositorFrame({});
- // Present the second compositor frame to the uesr, dropping the first one.
+ // Present the second compositor frame to the user, dropping the first one.
+ const base::TimeTicks presentation_time = AdvanceNowByMs(10);
viz::FrameTimingDetails details;
- details.presentation_feedback.timestamp = AdvanceNowByMs(10);
- reporting_controller_.DidPresentCompositorFrame(*next_token_, details);
+ details.presentation_feedback.timestamp = presentation_time;
+ reporting_controller_.DidPresentCompositorFrame(*current_token_, details);
- // Verify that no EventLatency histogram is recorded.
- EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix("EventLatency."),
- IsEmpty());
+ // Verify that EventLatency histograms for the first frame (dropped) are
+ // recorded using the presentation time of the second frame (presented).
+ struct {
+ const char* name;
+ const base::HistogramBase::Count count;
+ } expected_counts[] = {
+ {"EventLatency.TouchPressed.TotalLatency", 1},
+ {"EventLatency.TouchMoved.TotalLatency", 2},
+ {"EventLatency.TotalLatency", 3},
+ };
+ for (const auto& expected_count : expected_counts) {
+ histogram_tester.ExpectTotalCount(expected_count.name,
+ expected_count.count);
+ }
+
+ struct {
+ const char* name;
+ const base::HistogramBase::Sample latency_ms;
+ } expected_latencies[] = {
+ {"EventLatency.TouchPressed.TotalLatency",
+ (presentation_time - event_times[0]).InMicroseconds()},
+ {"EventLatency.TouchMoved.TotalLatency",
+ (presentation_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.TouchMoved.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[0]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
+ };
+ for (const auto& expected_latency : expected_latencies) {
+ histogram_tester.ExpectBucketCount(expected_latency.name,
+ expected_latency.latency_ms, 1);
+ }
}
TEST_F(CompositorFrameReportingControllerTest,
@@ -1284,7 +1332,8 @@ TEST_F(CompositorFrameReportingControllerTest,
// for the pending main-thread frame).
SimulateBeginMainFrame();
reporting_controller_.OnFinishImplFrame(current_id_);
- reporting_controller_.DidSubmitCompositorFrame(1u, current_id_, {}, {});
+ reporting_controller_.DidSubmitCompositorFrame(1u, current_id_, {}, {},
+ /*has_missing_content=*/false);
viz::FrameTimingDetails details = {};
details.presentation_feedback.timestamp = AdvanceNowByMs(10);
reporting_controller_.DidPresentCompositorFrame(1u, details);
@@ -1302,16 +1351,16 @@ TEST_F(CompositorFrameReportingControllerTest,
// and R2M.
SimulateBeginMainFrame();
reporting_controller_.OnFinishImplFrame(current_id_);
- reporting_controller_.DidSubmitCompositorFrame(1u, current_id_, previous_id,
- {});
+ reporting_controller_.DidSubmitCompositorFrame(
+ 1u, current_id_, previous_id, {}, /*has_missing_content=*/false);
details.presentation_feedback.timestamp = AdvanceNowByMs(10);
reporting_controller_.DidPresentCompositorFrame(1u, details);
// In total, two frames have been completed: R1C, and R1M.
// R2C has been presented, but it is blocked on R2M to know whether R2C
// contains partial update, or complete updates. So it is kept alive.
- EXPECT_EQ(2u, dropped_counter.total_frames());
- EXPECT_EQ(1u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(2u, dropped_counter_.total_frames());
+ EXPECT_EQ(1u, dropped_counter_.total_main_dropped());
EXPECT_EQ(1u, reporting_controller_.GetBlockingReportersCount());
EXPECT_EQ(1u, reporting_controller_.GetBlockedReportersCount());
@@ -1319,38 +1368,98 @@ TEST_F(CompositorFrameReportingControllerTest,
reporting_controller_.SetDroppedFrameCounter(nullptr);
}
+// Verifies that when a dependent frame is submitted to Viz, but not presented
+// (hence dropped), should have its reporter immediately terminated and not
+// adopted by the decider reporter.
+TEST_F(CompositorFrameReportingControllerTest,
+ DependentDroppedFrameTerminatesReporterImmediately) {
+ // Start a frame with main-thread update and let it get stuck in main-thread.
+ SimulateBeginMainFrame();
+ reporting_controller_.OnFinishImplFrame(current_id_);
+
+ // Start another frame that has impl-thread update and submit and present it
+ // successfully. The reporter for this frame should become dependent of the
+ // main reporter and adopted by it.
+ SimulateBeginImplFrame();
+ reporting_controller_.OnFinishImplFrame(current_id_);
+ reporting_controller_.DidSubmitCompositorFrame(1u, current_id_, {}, {},
+ /*has_missing_content=*/false);
+
+ viz::FrameTimingDetails details_1 = {};
+ details_1.presentation_feedback.timestamp = AdvanceNowByMs(10);
+ reporting_controller_.DidPresentCompositorFrame(1u, details_1);
+
+ // There should be 1 blocking reporter, 1 blocked reporter, and 1 adopted
+ // reporter.
+ EXPECT_EQ(1u, reporting_controller_.GetBlockingReportersCount());
+ EXPECT_EQ(1u, reporting_controller_.GetBlockedReportersCount());
+ EXPECT_EQ(1u, reporting_controller_.GetAdoptedReportersCount());
+
+ // At this point no frame has been completed, yet.
+ EXPECT_EQ(0u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
+
+ // Start yet another frame that has impl-thread update and submit it, but with
+ // failed presentation. The reporter for this frame should become dependent of
+ // the main reporter, but should terminated immediately upon presentation
+ // failure, hence not adopted by the main reporter.
+ SimulateBeginImplFrame();
+ reporting_controller_.OnFinishImplFrame(current_id_);
+ reporting_controller_.DidSubmitCompositorFrame(2u, current_id_, {}, {},
+ /*has_missing_content=*/false);
+
+ viz::FrameTimingDetails details_2 = {};
+ details_2.presentation_feedback.timestamp = AdvanceNowByMs(10);
+ details_2.presentation_feedback.flags |= gfx::PresentationFeedback::kFailure;
+ reporting_controller_.DidPresentCompositorFrame(2u, details_2);
+
+ // There should be still 1 blocking reporter, but 2 blocked reporters. There
+ // should also be only 1 adopted reporter as the new reporter should not be
+ // adopted.
+ EXPECT_EQ(1u, reporting_controller_.GetBlockingReportersCount());
+ EXPECT_EQ(2u, reporting_controller_.GetBlockedReportersCount());
+ EXPECT_EQ(1u, reporting_controller_.GetAdoptedReportersCount());
+
+ // At this point 1 frame has been completed and it's a dropped frame.
+ EXPECT_EQ(1u, dropped_counter_.total_frames());
+ EXPECT_EQ(1u, dropped_counter_.total_compositor_dropped());
+
+ reporting_controller_.ResetReporters();
+ reporting_controller_.SetDroppedFrameCounter(nullptr);
+}
+
TEST_F(CompositorFrameReportingControllerTest,
SkippedFramesFromDisplayCompositorAreDropped) {
// Submit and present two compositor frames.
SimulatePresentCompositorFrame();
- EXPECT_EQ(1u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(1u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
SimulatePresentCompositorFrame();
- EXPECT_EQ(2u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(2u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
// Now skip over a few frames, and submit + present another frame.
const uint32_t kSkipFrames = 5;
for (uint32_t i = 0; i < kSkipFrames; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame();
- EXPECT_EQ(3u + kSkipFrames, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(kSkipFrames, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(3u + kSkipFrames, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(kSkipFrames, dropped_counter_.total_compositor_dropped());
// Stop requesting frames, skip over a few frames, and submit + present
// another frame. There should no new dropped frames.
- dropped_counter.Reset();
+ dropped_counter_.Reset();
reporting_controller_.OnStoppedRequestingBeginFrames();
for (uint32_t i = 0; i < kSkipFrames; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame();
- EXPECT_EQ(1u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(1u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
reporting_controller_.ResetReporters();
reporting_controller_.SetDroppedFrameCounter(nullptr);
@@ -1360,14 +1469,14 @@ TEST_F(CompositorFrameReportingControllerTest,
SkippedFramesFromDisplayCompositorAreDroppedUpToLimit) {
// Submit and present two compositor frames.
SimulatePresentCompositorFrame();
- EXPECT_EQ(1u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(1u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
SimulatePresentCompositorFrame();
- EXPECT_EQ(2u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(2u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
// Now skip over a 101 frames (It should be ignored as it more than 100)
// and submit + present another frame.
@@ -1376,9 +1485,9 @@ TEST_F(CompositorFrameReportingControllerTest,
for (uint32_t i = 0; i < kSkipFrames; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame();
- EXPECT_EQ(3u + kSkipFramesActual, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(kSkipFramesActual, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(3u + kSkipFramesActual, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(kSkipFramesActual, dropped_counter_.total_compositor_dropped());
}
TEST_F(CompositorFrameReportingControllerTest,
@@ -1398,7 +1507,7 @@ TEST_F(CompositorFrameReportingControllerTest,
reporting_controller_.WillBeginImplFrame(args_1);
reporting_controller_.WillBeginMainFrame(args_1);
reporting_controller_.OnFinishImplFrame(current_id_1);
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
reporting_controller_.DidNotProduceFrame(args_1.frame_id,
FrameSkippedReason::kWaitingOnMain);
@@ -1416,22 +1525,22 @@ TEST_F(CompositorFrameReportingControllerTest,
EXPECT_EQ(3u, reporting_controller_.GetBlockedReportersCount());
// All frames are waiting for the main frame
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
- EXPECT_EQ(0u, dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_frames());
reporting_controller_.BeginMainFrameAborted(args_1.frame_id);
reporting_controller_.DidNotProduceFrame(args_1.frame_id,
FrameSkippedReason::kNoDamage);
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
// New reporters replace older reporters
reporting_controller_.WillBeginImplFrame(args_4);
reporting_controller_.WillBeginMainFrame(args_4);
- EXPECT_EQ(4u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(4u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
}
TEST_F(CompositorFrameReportingControllerTest,
@@ -1439,28 +1548,28 @@ TEST_F(CompositorFrameReportingControllerTest,
auto thread_type_compositor = FrameSequenceMetrics::ThreadType::kCompositor;
reporting_controller_.SetThreadAffectsSmoothness(thread_type_compositor,
true);
- dropped_counter.OnFcpReceived();
+ dropped_counter_.OnFcpReceived();
// Submit and present two compositor frames.
SimulatePresentCompositorFrame();
- EXPECT_EQ(1u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(1u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
SimulatePresentCompositorFrame();
- EXPECT_EQ(2u, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(2u, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter_.total_compositor_dropped());
// Now skip over a few frames, and submit + present another frame.
const uint32_t kSkipFrames_1 = 5;
for (uint32_t i = 0; i < kSkipFrames_1; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame();
- EXPECT_EQ(3u + kSkipFrames_1, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
- EXPECT_EQ(kSkipFrames_1, dropped_counter.total_compositor_dropped());
- EXPECT_EQ(kSkipFrames_1, dropped_counter.total_smoothness_dropped());
+ EXPECT_EQ(3u + kSkipFrames_1, dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
+ EXPECT_EQ(kSkipFrames_1, dropped_counter_.total_compositor_dropped());
+ EXPECT_EQ(kSkipFrames_1, dropped_counter_.total_smoothness_dropped());
// Now skip over a few frames which are not affecting smoothness.
reporting_controller_.SetThreadAffectsSmoothness(thread_type_compositor,
@@ -1469,11 +1578,12 @@ TEST_F(CompositorFrameReportingControllerTest,
for (uint32_t i = 0; i < kSkipFrames_2; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame(); // Present another frame.
- EXPECT_EQ(4u + kSkipFrames_1 + kSkipFrames_2, dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(4u + kSkipFrames_1 + kSkipFrames_2,
+ dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
EXPECT_EQ(kSkipFrames_1 + kSkipFrames_2,
- dropped_counter.total_compositor_dropped());
- EXPECT_EQ(kSkipFrames_1, dropped_counter.total_smoothness_dropped());
+ dropped_counter_.total_compositor_dropped());
+ EXPECT_EQ(kSkipFrames_1, dropped_counter_.total_smoothness_dropped());
// Now skip over a few frames more frames which are affecting smoothness.
reporting_controller_.SetThreadAffectsSmoothness(thread_type_compositor,
@@ -1483,12 +1593,44 @@ TEST_F(CompositorFrameReportingControllerTest,
IncrementCurrentId();
SimulatePresentCompositorFrame(); // Present another frame.
EXPECT_EQ(5u + kSkipFrames_1 + kSkipFrames_2 + kSkipFrames_3,
- dropped_counter.total_frames());
- EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ dropped_counter_.total_frames());
+ EXPECT_EQ(0u, dropped_counter_.total_main_dropped());
EXPECT_EQ(kSkipFrames_1 + kSkipFrames_2 + kSkipFrames_3,
- dropped_counter.total_compositor_dropped());
+ dropped_counter_.total_compositor_dropped());
EXPECT_EQ(kSkipFrames_1 + kSkipFrames_3,
- dropped_counter.total_smoothness_dropped());
+ dropped_counter_.total_smoothness_dropped());
+}
+
+// Verifies that presentation feedbacks that arrive out of order are handled
+// properly. See crbug.com/1195105 for more details.
+TEST_F(CompositorFrameReportingControllerTest,
+ HandleOutOfOrderPresentationFeedback) {
+ // Submit three compositor frames without sending back their presentation
+ // feedbacks.
+ SimulateSubmitCompositorFrame({});
+
+ SimulateSubmitCompositorFrame({});
+ const uint32_t frame_token_2 = *current_token_;
+
+ SimulateSubmitCompositorFrame({});
+ const uint32_t frame_token_3 = *current_token_;
+
+ // Send a failed presentation feedback for frame 2. This should only drop
+ // frame 2 and leave frame 1 in the queue.
+ viz::FrameTimingDetails details_2;
+ details_2.presentation_feedback = {AdvanceNowByMs(10), base::TimeDelta(),
+ gfx::PresentationFeedback::kFailure};
+ reporting_controller_.DidPresentCompositorFrame(frame_token_2, details_2);
+ DCHECK_EQ(1u, dropped_counter_.total_frames());
+ DCHECK_EQ(1u, dropped_counter_.total_compositor_dropped());
+
+ // Send a successful presentation feedback for frame 3. This should drop frame
+ // 1.
+ viz::FrameTimingDetails details_3;
+ details_3.presentation_feedback.timestamp = AdvanceNowByMs(10);
+ reporting_controller_.DidPresentCompositorFrame(frame_token_3, details_3);
+ DCHECK_EQ(3u, dropped_counter_.total_frames());
+ DCHECK_EQ(2u, dropped_counter_.total_compositor_dropped());
}
} // namespace
diff --git a/chromium/cc/metrics/compositor_timing_history.cc b/chromium/cc/metrics/compositor_timing_history.cc
index 9dd8e1aa0a4..e8af510dba3 100644
--- a/chromium/cc/metrics/compositor_timing_history.cc
+++ b/chromium/cc/metrics/compositor_timing_history.cc
@@ -16,7 +16,6 @@
#include "base/trace_event/trace_event.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/metrics/compositor_frame_reporting_controller.h"
-#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h"
namespace cc {
@@ -424,23 +423,6 @@ CompositorTimingHistory::CreateUMAReporter(UMACategory category) {
return base::WrapUnique<CompositorTimingHistory::UMAReporter>(nullptr);
}
-void CompositorTimingHistory::AsProtozeroInto(
- perfetto::protos::pbzero::CompositorTimingHistory* state) const {
- state->set_begin_main_frame_queue_critical_estimate_delta_us(
- BeginMainFrameQueueDurationCriticalEstimate().InMicroseconds());
- state->set_begin_main_frame_queue_not_critical_estimate_delta_us(
- BeginMainFrameQueueDurationNotCriticalEstimate().InMicroseconds());
- state->set_begin_main_frame_start_to_ready_to_commit_estimate_delta_us(
- BeginMainFrameStartToReadyToCommitDurationEstimate().InMicroseconds());
- state->set_commit_to_ready_to_activate_estimate_delta_us(
- CommitToReadyToActivateDurationEstimate().InMicroseconds());
- state->set_prepare_tiles_estimate_delta_us(
- PrepareTilesDurationEstimate().InMicroseconds());
- state->set_activate_estimate_delta_us(
- ActivateDurationEstimate().InMicroseconds());
- state->set_draw_estimate_delta_us(DrawDurationEstimate().InMicroseconds());
-}
-
base::TimeTicks CompositorTimingHistory::Now() const {
return base::TimeTicks::Now();
}
@@ -511,6 +493,37 @@ base::TimeDelta CompositorTimingHistory::DrawDurationEstimate() const {
return draw_duration_history_.Percentile(kDrawEstimationPercentile);
}
+base::TimeDelta
+CompositorTimingHistory::BeginMainFrameStartToReadyToCommitCriticalEstimate()
+ const {
+ return BeginMainFrameStartToReadyToCommitDurationEstimate() +
+ BeginMainFrameQueueDurationCriticalEstimate();
+}
+
+base::TimeDelta
+CompositorTimingHistory::BeginMainFrameStartToReadyToCommitNotCriticalEstimate()
+ const {
+ return BeginMainFrameStartToReadyToCommitDurationEstimate() +
+ BeginMainFrameQueueDurationNotCriticalEstimate();
+}
+
+base::TimeDelta
+CompositorTimingHistory::BeginMainFrameQueueToActivateCriticalEstimate() const {
+ return BeginMainFrameStartToReadyToCommitDurationEstimate() +
+ CommitDurationEstimate() + CommitToReadyToActivateDurationEstimate() +
+ ActivateDurationEstimate() +
+ BeginMainFrameQueueDurationCriticalEstimate();
+}
+
+base::TimeDelta
+CompositorTimingHistory::BeginMainFrameQueueToActivateNotCriticalEstimate()
+ const {
+ return BeginMainFrameStartToReadyToCommitDurationEstimate() +
+ CommitDurationEstimate() + CommitToReadyToActivateDurationEstimate() +
+ ActivateDurationEstimate() +
+ BeginMainFrameQueueDurationNotCriticalEstimate();
+}
+
void CompositorTimingHistory::WillBeginImplFrame(
const viz::BeginFrameArgs& args,
base::TimeTicks now) {
@@ -776,10 +789,11 @@ void CompositorTimingHistory::DidSubmitCompositorFrame(
uint32_t frame_token,
const viz::BeginFrameId& current_frame_id,
const viz::BeginFrameId& last_activated_frame_id,
- EventMetricsSet events_metrics) {
+ EventMetricsSet events_metrics,
+ bool has_missing_content) {
compositor_frame_reporting_controller_->DidSubmitCompositorFrame(
frame_token, current_frame_id, last_activated_frame_id,
- std::move(events_metrics));
+ std::move(events_metrics), has_missing_content);
}
void CompositorTimingHistory::DidNotProduceFrame(
diff --git a/chromium/cc/metrics/compositor_timing_history.h b/chromium/cc/metrics/compositor_timing_history.h
index 15b1ff0050f..275e6f4c4cc 100644
--- a/chromium/cc/metrics/compositor_timing_history.h
+++ b/chromium/cc/metrics/compositor_timing_history.h
@@ -52,9 +52,6 @@ class CC_EXPORT CompositorTimingHistory {
CompositorTimingHistory& operator=(const CompositorTimingHistory&) = delete;
- void AsProtozeroInto(
- perfetto::protos::pbzero::CompositorTimingHistory* state) const;
-
// The main thread responsiveness depends heavily on whether or not the
// on_critical_path flag is set, so we record response times separately.
virtual base::TimeDelta BeginMainFrameQueueDurationCriticalEstimate() const;
@@ -68,6 +65,11 @@ class CC_EXPORT CompositorTimingHistory {
virtual base::TimeDelta ActivateDurationEstimate() const;
virtual base::TimeDelta DrawDurationEstimate() const;
+ base::TimeDelta BeginMainFrameStartToReadyToCommitCriticalEstimate() const;
+ base::TimeDelta BeginMainFrameStartToReadyToCommitNotCriticalEstimate() const;
+ base::TimeDelta BeginMainFrameQueueToActivateCriticalEstimate() const;
+ base::TimeDelta BeginMainFrameQueueToActivateNotCriticalEstimate() const;
+
// State that affects when events should be expected/recorded/reported.
void SetRecordingEnabled(bool enabled);
@@ -95,7 +97,8 @@ class CC_EXPORT CompositorTimingHistory {
uint32_t frame_token,
const viz::BeginFrameId& current_frame_id,
const viz::BeginFrameId& last_activated_frame_id,
- EventMetricsSet events_metrics);
+ EventMetricsSet events_metrics,
+ bool has_missing_content);
void DidNotProduceFrame(const viz::BeginFrameId& id,
FrameSkippedReason skip_reason);
void DidPresentCompositorFrame(uint32_t frame_token,
diff --git a/chromium/cc/metrics/dropped_frame_counter.cc b/chromium/cc/metrics/dropped_frame_counter.cc
index 357acc6e903..be75c7ceb6a 100644
--- a/chromium/cc/metrics/dropped_frame_counter.cc
+++ b/chromium/cc/metrics/dropped_frame_counter.cc
@@ -228,6 +228,16 @@ void DroppedFrameCounter::ReportFrames() {
static_cast<double>(total_smoothness_dropped_) * 100 / total_frames;
smoothness_data.worst_smoothness = sliding_window_max_percent_dropped_;
smoothness_data.percentile_95 = sliding_window_95pct_percent_dropped;
+
+ if (sliding_window_max_percent_dropped_After_1_sec_.has_value())
+ smoothness_data.worst_smoothness_after1sec =
+ sliding_window_max_percent_dropped_After_1_sec_.value();
+ if (sliding_window_max_percent_dropped_After_2_sec_.has_value())
+ smoothness_data.worst_smoothness_after2sec =
+ sliding_window_max_percent_dropped_After_2_sec_.value();
+ if (sliding_window_max_percent_dropped_After_5_sec_.has_value())
+ smoothness_data.worst_smoothness_after5sec =
+ sliding_window_max_percent_dropped_After_5_sec_.value();
smoothness_data.time_max_delta = time_max_delta_;
ukm_smoothness_data_->Write(smoothness_data);
}
@@ -258,6 +268,9 @@ void DroppedFrameCounter::Reset() {
total_dropped_ = 0;
total_smoothness_dropped_ = 0;
sliding_window_max_percent_dropped_ = 0;
+ sliding_window_max_percent_dropped_After_1_sec_.reset();
+ sliding_window_max_percent_dropped_After_2_sec_.reset();
+ sliding_window_max_percent_dropped_After_5_sec_.reset();
dropped_frame_count_in_window_ = 0;
fcp_received_ = false;
sliding_window_ = {};
@@ -332,6 +345,7 @@ void DroppedFrameCounter::NotifyFrameResult(const viz::BeginFrameArgs& args,
time_max_delta_ = args.frame_time - time_fcp_received_;
sliding_window_max_percent_dropped_ = percent_dropped_frame;
}
+ UpdateMaxPercentDroppedFrame(percent_dropped_frame);
latest_sliding_window_start_ = last_timestamp;
latest_sliding_window_interval_ = remaining_oldest_args.interval;
@@ -341,6 +355,27 @@ void DroppedFrameCounter::NotifyFrameResult(const viz::BeginFrameArgs& args,
++dropped_frame_count_in_window_;
}
+void DroppedFrameCounter::UpdateMaxPercentDroppedFrame(
+ double percent_dropped_frame) {
+ if (!fcp_received_)
+ return;
+
+ const auto fcp_time_delta = base::TimeTicks::Now() - time_fcp_received_;
+
+ if (fcp_time_delta > base::TimeDelta::FromSeconds(1))
+ sliding_window_max_percent_dropped_After_1_sec_ =
+ std::max(sliding_window_max_percent_dropped_After_1_sec_.value_or(0.0),
+ percent_dropped_frame);
+ if (fcp_time_delta > base::TimeDelta::FromSeconds(2))
+ sliding_window_max_percent_dropped_After_2_sec_ =
+ std::max(sliding_window_max_percent_dropped_After_2_sec_.value_or(0.0),
+ percent_dropped_frame);
+ if (fcp_time_delta > base::TimeDelta::FromSeconds(5))
+ sliding_window_max_percent_dropped_After_5_sec_ =
+ std::max(sliding_window_max_percent_dropped_After_5_sec_.value_or(0.0),
+ percent_dropped_frame);
+}
+
void DroppedFrameCounter::OnFcpReceived() {
fcp_received_ = true;
time_fcp_received_ = base::TimeTicks::Now();
diff --git a/chromium/cc/metrics/dropped_frame_counter.h b/chromium/cc/metrics/dropped_frame_counter.h
index 7126c32c46d..aee1839db46 100644
--- a/chromium/cc/metrics/dropped_frame_counter.h
+++ b/chromium/cc/metrics/dropped_frame_counter.h
@@ -6,10 +6,12 @@
#define CC_METRICS_DROPPED_FRAME_COUNTER_H_
#include <stddef.h>
+#include <map>
#include <queue>
#include <utility>
#include "base/containers/ring_buffer.h"
+#include "base/optional.h"
#include "cc/cc_export.h"
#include "cc/metrics/frame_sorter.h"
#include "cc/metrics/ukm_smoothness_data.h"
@@ -102,6 +104,8 @@ class CC_EXPORT DroppedFrameCounter {
void NotifyFrameResult(const viz::BeginFrameArgs& args, bool is_dropped);
base::TimeDelta ComputeCurrentWindowSize() const;
+ void UpdateMaxPercentDroppedFrame(double percent_dropped_frame);
+
const base::TimeDelta kSlidingWindowInterval =
base::TimeDelta::FromSeconds(1);
std::queue<std::pair<const viz::BeginFrameArgs, bool>> sliding_window_;
@@ -119,6 +123,9 @@ class CC_EXPORT DroppedFrameCounter {
size_t total_smoothness_dropped_ = 0;
bool fcp_received_ = false;
double sliding_window_max_percent_dropped_ = 0;
+ base::Optional<double> sliding_window_max_percent_dropped_After_1_sec_;
+ base::Optional<double> sliding_window_max_percent_dropped_After_2_sec_;
+ base::Optional<double> sliding_window_max_percent_dropped_After_5_sec_;
base::TimeTicks time_fcp_received_;
base::TimeDelta time_max_delta_;
UkmSmoothnessDataShared* ukm_smoothness_data_ = nullptr;
diff --git a/chromium/cc/metrics/frame_sequence_tracker.cc b/chromium/cc/metrics/frame_sequence_tracker.cc
index 9576ad3b63d..ce16e4ef9db 100644
--- a/chromium/cc/metrics/frame_sequence_tracker.cc
+++ b/chromium/cc/metrics/frame_sequence_tracker.cc
@@ -142,7 +142,8 @@ void FrameSequenceTracker::ReportBeginImplFrame(
DCHECK(!compositor_frame_submitted_) << TRACKER_DCHECK_MSG;
UpdateTrackedFrameData(&begin_impl_frame_data_, args.frame_id.source_id,
- args.frame_id.sequence_number);
+ args.frame_id.sequence_number,
+ args.frames_throttled_since_last);
impl_throughput().frames_expected +=
begin_impl_frame_data_.previous_sequence_delta;
#if DCHECK_IS_ON()
@@ -188,7 +189,8 @@ void FrameSequenceTracker::ReportBeginMainFrame(
awaiting_main_response_sequence_ = args.frame_id.sequence_number;
UpdateTrackedFrameData(&begin_main_frame_data_, args.frame_id.source_id,
- args.frame_id.sequence_number);
+ args.frame_id.sequence_number,
+ args.frames_throttled_since_last);
if (!first_received_main_sequence_ ||
first_received_main_sequence_ <= last_no_main_damage_sequence_) {
first_received_main_sequence_ = args.frame_id.sequence_number;
@@ -639,12 +641,15 @@ void FrameSequenceTracker::PauseFrameProduction() {
reset_all_state_ = true;
}
-void FrameSequenceTracker::UpdateTrackedFrameData(TrackedFrameData* frame_data,
- uint64_t source_id,
- uint64_t sequence_number) {
+void FrameSequenceTracker::UpdateTrackedFrameData(
+ TrackedFrameData* frame_data,
+ uint64_t source_id,
+ uint64_t sequence_number,
+ uint64_t throttled_frame_count) {
if (frame_data->previous_sequence &&
frame_data->previous_source == source_id) {
- uint32_t current_latency = sequence_number - frame_data->previous_sequence;
+ uint32_t current_latency =
+ sequence_number - frame_data->previous_sequence - throttled_frame_count;
DCHECK_GT(current_latency, 0u) << TRACKER_DCHECK_MSG;
frame_data->previous_sequence_delta = current_latency;
} else {
diff --git a/chromium/cc/metrics/frame_sequence_tracker.h b/chromium/cc/metrics/frame_sequence_tracker.h
index 387a50b71f3..d343c4ff574 100644
--- a/chromium/cc/metrics/frame_sequence_tracker.h
+++ b/chromium/cc/metrics/frame_sequence_tracker.h
@@ -156,7 +156,8 @@ class CC_EXPORT FrameSequenceTracker {
void UpdateTrackedFrameData(TrackedFrameData* frame_data,
uint64_t source_id,
- uint64_t sequence_number);
+ uint64_t sequence_number,
+ uint64_t throttled_frame_count);
bool ShouldIgnoreBeginFrameSource(uint64_t source_id) const;
diff --git a/chromium/cc/metrics/frame_sequence_tracker_collection.cc b/chromium/cc/metrics/frame_sequence_tracker_collection.cc
index 22c7941a8ac..263c4215ef1 100644
--- a/chromium/cc/metrics/frame_sequence_tracker_collection.cc
+++ b/chromium/cc/metrics/frame_sequence_tracker_collection.cc
@@ -65,6 +65,8 @@ FrameSequenceTracker* FrameSequenceTrackerCollection::StartSequenceInternal(
if (IsScrollType(type)) {
DCHECK_NE(scrolling_thread, ThreadType::kUnknown);
metrics->SetScrollingThread(scrolling_thread);
+ compositor_frame_reporting_controller_->SetScrollingThread(
+ scrolling_thread);
}
if (metrics->GetEffectiveThread() == ThreadType::kCompositor) {
@@ -117,6 +119,8 @@ void FrameSequenceTrackerCollection::StopSequence(
auto key = std::make_pair(type, ThreadType::kUnknown);
if (IsScrollType(type)) {
+ compositor_frame_reporting_controller_->SetScrollingThread(
+ ThreadType::kUnknown);
key = std::make_pair(type, ThreadType::kCompositor);
if (!frame_trackers_.contains(key))
key = std::make_pair(type, ThreadType::kMain);
diff --git a/chromium/cc/metrics/jank_injector.cc b/chromium/cc/metrics/jank_injector.cc
index 12c13e41cc5..1ffcbfbe194 100644
--- a/chromium/cc/metrics/jank_injector.cc
+++ b/chromium/cc/metrics/jank_injector.cc
@@ -45,10 +45,12 @@ struct JankInjectionParams {
bool busy_loop = true;
};
+bool g_jank_enabled_for_test = false;
+
bool IsJankInjectionEnabled() {
static bool enabled =
base::FeatureList::IsEnabled(features::kJankInjectionAblationFeature);
- return enabled;
+ return enabled || g_jank_enabled_for_test;
}
using AllowedURLsMap = std::map<std::string, std::vector<std::string>>;
@@ -105,6 +107,16 @@ void RunJank(JankInjectionParams params) {
} // namespace
+ScopedJankInjectionEnabler::ScopedJankInjectionEnabler() {
+ DCHECK(!g_jank_enabled_for_test);
+ g_jank_enabled_for_test = true;
+}
+
+ScopedJankInjectionEnabler::~ScopedJankInjectionEnabler() {
+ DCHECK(g_jank_enabled_for_test);
+ g_jank_enabled_for_test = false;
+}
+
JankInjector::JankInjector() {
if (IsJankInjectionEnabled()) {
config_.target_dropped_frames_percent =
diff --git a/chromium/cc/metrics/jank_injector.h b/chromium/cc/metrics/jank_injector.h
index b27bf2143c9..5b3f650ed1e 100644
--- a/chromium/cc/metrics/jank_injector.h
+++ b/chromium/cc/metrics/jank_injector.h
@@ -15,6 +15,16 @@ class GURL;
namespace cc {
+class CC_EXPORT ScopedJankInjectionEnabler {
+ public:
+ ScopedJankInjectionEnabler();
+ ~ScopedJankInjectionEnabler();
+
+ ScopedJankInjectionEnabler(const ScopedJankInjectionEnabler&) = delete;
+ ScopedJankInjectionEnabler& operator=(const ScopedJankInjectionEnabler&) =
+ delete;
+};
+
class CC_EXPORT JankInjector {
public:
struct CC_EXPORT JankConfig {
diff --git a/chromium/cc/metrics/jank_injector_unittest.cc b/chromium/cc/metrics/jank_injector_unittest.cc
index cbc50ccf272..a6587373c2d 100644
--- a/chromium/cc/metrics/jank_injector_unittest.cc
+++ b/chromium/cc/metrics/jank_injector_unittest.cc
@@ -27,6 +27,7 @@ TEST_F(JankInjectorTest, Basic) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner(
new base::TestSimpleTaskRunner());
+ ScopedJankInjectionEnabler enable_jank;
JankInjector injector;
const auto& config = injector.config();
EXPECT_EQ(config.target_dropped_frames_percent, 10u);
diff --git a/chromium/cc/metrics/ukm_smoothness_data.h b/chromium/cc/metrics/ukm_smoothness_data.h
index eb74020c249..b1c05a42ca8 100644
--- a/chromium/cc/metrics/ukm_smoothness_data.h
+++ b/chromium/cc/metrics/ukm_smoothness_data.h
@@ -15,6 +15,13 @@ namespace cc {
struct UkmSmoothnessData {
double avg_smoothness = 0.0;
double worst_smoothness = 0.0;
+
+ // Values are set to -1 to help with recognizing when these metrics are not
+ // calculated.
+ double worst_smoothness_after1sec = -1.0;
+ double worst_smoothness_after2sec = -1.0;
+ double worst_smoothness_after5sec = -1.0;
+
double above_threshold = 0.0;
double percentile_95 = 0.0;
base::TimeDelta time_max_delta = base::TimeDelta::FromMilliseconds(1);
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
index 467fac7f00f..3615ceee935 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -277,6 +277,11 @@ void AsyncLayerTreeFrameSink::ReclaimResources(
client_->ReclaimResources(resources);
}
+void AsyncLayerTreeFrameSink::OnCompositorFrameTransitionDirectiveProcessed(
+ uint32_t sequence_id) {
+ client_->OnCompositorFrameTransitionDirectiveProcessed(sequence_id);
+}
+
void AsyncLayerTreeFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
DCHECK(compositor_frame_sink_ptr_);
if (needs_begin_frames_ != needs_begin_frames) {
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
index c7efb10500a..2ca8e8b68a3 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
@@ -107,6 +107,8 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
void OnBeginFramePausedChanged(bool paused) override;
void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override;
+ void OnCompositorFrameTransitionDirectiveProcessed(
+ uint32_t sequence_id) override;
// ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override;
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index d5eec1c990b..63986010b93 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
#include <tuple>
#include <vector>
@@ -46,6 +47,10 @@
#include "ui/gfx/skia_util.h"
#include "ui/gl/gl_implementation.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
namespace cc {
namespace {
scoped_refptr<DisplayItemList> MakeNoopDisplayItemList() {
@@ -75,10 +80,10 @@ class OopPixelTest : public testing::Test,
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
const int gles2_max_texture_size =
gles2_context_provider_->ContextCapabilities().max_texture_size;
- gpu_image_cache_.reset(new GpuImageDecodeCache(
+ gpu_image_cache_ = std::make_unique<GpuImageDecodeCache>(
gles2_context_provider_.get(), false, kRGBA_8888_SkColorType,
kWorkingSetSize, gles2_max_texture_size,
- PaintImage::kDefaultGeneratorClientId, nullptr));
+ PaintImage::kDefaultGeneratorClientId, nullptr);
const int raster_max_texture_size =
raster_context_provider_->ContextCapabilities().max_texture_size;
@@ -102,10 +107,10 @@ class OopPixelTest : public testing::Test,
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
const int raster_max_texture_size =
raster_context_provider_->ContextCapabilities().max_texture_size;
- oop_image_cache_.reset(new GpuImageDecodeCache(
+ oop_image_cache_ = std::make_unique<GpuImageDecodeCache>(
raster_context_provider_.get(), true, kRGBA_8888_SkColorType,
kWorkingSetSize, raster_max_texture_size,
- PaintImage::kDefaultGeneratorClientId, nullptr));
+ PaintImage::kDefaultGeneratorClientId, nullptr);
}
class RasterOptions {
@@ -174,16 +179,20 @@ class OopPixelTest : public testing::Test,
if (options.preclear) {
raster_implementation->BeginRasterCHROMIUM(
- options.preclear_color, options.msaa_sample_count,
- options.use_lcd_text, options.color_space, mailbox.name);
+ options.preclear_color, /*needs_clear=*/options.preclear,
+ options.msaa_sample_count, options.use_lcd_text, options.color_space,
+ mailbox.name);
raster_implementation->EndRasterCHROMIUM();
}
// "Out of process" raster! \o/
-
+ // If |options.preclear| is true, the mailbox has already been cleared by
+ // the BeginRasterCHROMIUM call above, and we want to test that it is indeed
+ // cleared, so set |needs_clear| to false here.
raster_implementation->BeginRasterCHROMIUM(
- options.background_color, options.msaa_sample_count,
- options.use_lcd_text, options.color_space, mailbox.name);
+ options.background_color, /*needs_clear=*/!options.preclear,
+ options.msaa_sample_count, options.use_lcd_text, options.color_space,
+ mailbox.name);
size_t max_op_size_limit =
gpu::raster::RasterInterface::kDefaultMaxOpSizeHint;
raster_implementation->RasterCHROMIUM(
@@ -329,7 +338,8 @@ class OopPixelTest : public testing::Test,
options.resource_size.width(), options.resource_size.height(),
options.color_space.ToSkColorSpace());
auto surface = SkSurface::MakeRenderTarget(
- gles2_context_provider_->GrContext(), SkBudgeted::kYes, image_info);
+ gles2_context_provider_->GrContext(), SkBudgeted::kYes, image_info, 0,
+ &surface_props);
SkCanvas* canvas = surface->getCanvas();
if (options.preclear)
canvas->drawColor(options.preclear_color);
@@ -360,11 +370,22 @@ class OopPixelTest : public testing::Test,
void ExpectEquals(SkBitmap actual,
SkBitmap expected,
const char* label = nullptr) {
+ ExactPixelComparator exact(/* discard_alpha */ false);
+ ExpectEquals(actual, expected, exact, label);
+ }
+
+ void ExpectEquals(SkBitmap actual,
+ SkBitmap expected,
+ const PixelComparator& comparator,
+ const char* label = nullptr) {
EXPECT_EQ(actual.dimensions(), expected.dimensions());
+
+ // We don't just use MatchesBitmap so that we can control logging output.
+ if (comparator.Compare(actual, expected))
+ return;
+
auto expected_url = GetPNGDataUrl(expected);
auto actual_url = GetPNGDataUrl(actual);
- if (actual_url == expected_url)
- return;
if (label) {
ADD_FAILURE() << "\nCase: " << label << "\nExpected: " << expected_url
<< "\nActual: " << actual_url;
@@ -1655,48 +1676,47 @@ sk_sp<SkTextBlob> BuildTextBlob(
SkFont font;
font.setTypeface(typeface);
font.setHinting(SkFontHinting::kNormal);
- font.setSize(1u);
+ font.setSize(8.f);
if (use_lcd_text) {
font.setSubpixel(true);
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
}
- SkTextBlobBuilder builder;
- const int glyphCount = 10;
- const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0);
- for (int i = 0; i < glyphCount; i++) {
- runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
- runBuffer.pos[i] = SkIntToScalar(i);
- }
- return builder.make();
+ return SkTextBlob::MakeFromString("Hamburgefons", font);
}
-TEST_F(OopPixelTest, DrawTextBlob) {
- RasterOptions options;
- options.resource_size = gfx::Size(100, 100);
- options.content_size = options.resource_size;
- options.full_raster_rect = gfx::Rect(options.content_size);
- options.playback_rect = options.full_raster_rect;
- options.color_space = gfx::ColorSpace::CreateSRGB();
-
- auto display_item_list = base::MakeRefCounted<DisplayItemList>();
- display_item_list->StartPaint();
- PaintFlags flags;
- flags.setStyle(PaintFlags::kFill_Style);
- flags.setColor(SK_ColorGREEN);
- display_item_list->push<DrawTextBlobOp>(BuildTextBlob(), 0u, 0u, flags);
- display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
- display_item_list->Finalize();
+// A reasonable Y offset given the font parameters of BuildTextBlob() that
+// ensures the text is not just drawn above the top edge of the surface.
+static constexpr SkScalar kTextBlobY = 16.f;
+
+// OopTextBlobPixelTest's test suite runs through the cross product of these
+// strategies.
+enum class TextBlobStrategy {
+ kDirect, // DrawTextBlobOp directly in the display list
+ kDrawRecord, // DrawRecordOp where the paint record includes text
+ kRecordShader, // DrawRectOp where the paint has a RecordShader with text
+ kRecordFilter // DrawRectOp where the paint has a RecordFilter with text
+};
+enum class FilterStrategy {
+ kNone, // No additional PaintFilter interacting with text
+ kPaintFlags, // A blur is added to the PaintFlags of the draw
+ kSaveLayer // An explicit save layer with blur is made before the draw
+};
+enum class MatrixStrategy {
+ kIdentity, // Identity matrix (no extra scale factor for text then)
+ kScaled, // Matrix is an axis-aligned scale factor
+ kComplex, // Matrix is not axis-aligned and scale must be decomposed
+ kPerspective, // Matrix has perspective and an approximate scale is needed
+};
+enum class LCDStrategy { kNo, kYes };
- auto actual = Raster(display_item_list, options);
- auto expected = RasterExpectedBitmap(display_item_list, options);
- ExpectEquals(actual, expected);
-}
+using TextBlobTestConfig = ::testing::
+ tuple<TextBlobStrategy, FilterStrategy, MatrixStrategy, LCDStrategy>;
-class OopRecordShaderPixelTest : public OopPixelTest,
- public ::testing::WithParamInterface<bool> {
+class OopTextBlobPixelTest
+ : public OopPixelTest,
+ public ::testing::WithParamInterface<TextBlobTestConfig> {
public:
- bool UseLcdText() const { return GetParam(); }
void RunTest() {
RasterOptions options;
options.resource_size = gfx::Size(100, 100);
@@ -1706,90 +1726,272 @@ class OopRecordShaderPixelTest : public OopPixelTest,
options.color_space = gfx::ColorSpace::CreateSRGB();
options.use_lcd_text = UseLcdText();
- auto paint_record = sk_make_sp<PaintOpBuffer>();
- PaintFlags flags;
- flags.setStyle(PaintFlags::kFill_Style);
- flags.setColor(SK_ColorGREEN);
- paint_record->push<DrawTextBlobOp>(
- BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags);
- auto paint_record_shader = PaintShader::MakePaintRecord(
- paint_record, SkRect::MakeWH(25, 25), SkTileMode::kRepeat,
- SkTileMode::kRepeat, nullptr,
- PaintShader::ScalingBehavior::kRasterAtScale);
- // Force paint_flags to convert this to kFixedScale, so we can safely
- // compare pixels between direct and oop-r modes (since oop will convert to
- // kFixedScale no matter what.
- paint_record_shader->set_has_animated_images(true);
-
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- display_item_list->push<ScaleOp>(2.f, 2.f);
- PaintFlags shader_flags;
- shader_flags.setShader(paint_record_shader);
- display_item_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), shader_flags);
+
+ // Set matrix before any image filter is applied, which may force the
+ // matrix to be decomposed into a transform compatible with the filter.
+ SetMatrix(display_item_list);
+
+ const bool save_layer =
+ GetFilterStrategy(GetParam()) == FilterStrategy::kSaveLayer;
+ sk_sp<PaintFilter> filter = MakeFilter();
+ if (save_layer) {
+ PaintFlags layer_flags;
+ layer_flags.setImageFilter(std::move(filter));
+ filter = nullptr;
+ display_item_list->push<SaveLayerOp>(nullptr, &layer_flags);
+ }
+
+ PushDrawOp(display_item_list, std::move(filter));
+
+ if (save_layer) {
+ display_item_list->push<RestoreOp>();
+ }
+
display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
display_item_list->Finalize();
auto actual = Raster(display_item_list, options);
auto expected = RasterExpectedBitmap(display_item_list, options);
- ExpectEquals(actual, expected);
+
+ // Drawing text into an image and then transforming that can lead to small
+ // flakiness in devices, although in practice they are very imperceptible,
+ // and distinctly different from using the wrong glyph or text params.
+ float error_pixels_percentage = 0.f;
+ int max_abs_error = 0;
+#if defined(OS_ANDROID)
+ // The nexus5 and nexus5x bots are particularly susceptible to small changes
+ // when bilerping an image (not visible).
+ const int sdk = base::android::BuildInfo::GetInstance()->sdk_int();
+ if (sdk <= base::android::SDK_VERSION_MARSHMALLOW) {
+ error_pixels_percentage = 10.f;
+ max_abs_error = 16;
+ } else {
+ // Newer OSes occasionally have smaller flakes when using the real GPU
+ error_pixels_percentage = 1.5f;
+ max_abs_error = 2;
+ }
+#elif defined(OS_MAC) || defined(OS_WIN)
+ // Mac and Windows need very small tolerances only under complex transforms
+ if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kComplex) {
+ error_pixels_percentage = 0.2f;
+ max_abs_error = 2;
+ }
+#endif
+ // Regardless of OS, perspective triggers path rendering for each glyph,
+ // which produces its own set of pixel differences.
+ if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kPerspective) {
+ error_pixels_percentage = 4.f;
+ max_abs_error = 36;
+ }
+
+ FuzzyPixelComparator comparator(
+ /*discard_alpha=*/false,
+ /*error_pixels_percentage_limit=*/error_pixels_percentage,
+ /*small_error_pixels_percentage_limit=*/0.0f,
+ /*avg_abs_error_limit=*/max_abs_error,
+ /*max_abs_error_limit=*/max_abs_error,
+ /*small_error_threshold=*/0);
+ ExpectEquals(actual, expected, comparator);
}
-};
-TEST_P(OopRecordShaderPixelTest, ShaderWithTextScaled) {
- RunTest();
-}
+ sk_sp<PaintFilter> MakeFilter() {
+ if (GetFilterStrategy(GetParam()) == FilterStrategy::kNone) {
+ return nullptr;
+ } else {
+ // Keep the blur sigmas small to reduce test duration, it's the presence
+ // of the blur filter that triggers the code path changes we care about.
+ return sk_make_sp<BlurPaintFilter>(.1f, .1f, SkTileMode::kDecal, nullptr);
+ }
+ }
-class OopRecordFilterPixelTest : public OopPixelTest,
- public ::testing::WithParamInterface<bool> {
- public:
- bool UseLcdText() const { return GetParam(); }
- void RunTest(const SkM44& mat) {
- RasterOptions options;
- options.resource_size = gfx::Size(100, 100);
- options.content_size = options.resource_size;
- options.full_raster_rect = gfx::Rect(options.content_size);
- options.playback_rect = options.full_raster_rect;
- options.color_space = gfx::ColorSpace::CreateSRGB();
- options.use_lcd_text = UseLcdText();
+ void SetMatrix(scoped_refptr<DisplayItemList> display_list) {
+ MatrixStrategy strategy = GetMatrixStrategy(GetParam());
+
+ SkM44 m; // Default constructed to identity
+ if (strategy != MatrixStrategy::kIdentity) {
+ // Scaled, Complex, and Perspective all have a 2x scale factor
+ m.preScale(2.0f, 2.0f);
+ if (strategy == MatrixStrategy::kComplex) {
+ SkM44 skew = SkM44();
+ skew.setRC(0, 1, 2.f);
+ skew.setRC(1, 0, 2.f);
+ m.preConcat(skew);
+ } else if (strategy == MatrixStrategy::kPerspective) {
+ SkM44 persp = SkM44::Perspective(0.01f, 10.f, SK_ScalarPI / 3.f);
+ persp.preTranslate(0.f, 5.f, -0.1f);
+ persp.preConcat(SkM44::Rotate({0.f, 1.f, 0.f}, 0.008f /* radians */));
+ m.postConcat(persp);
+ }
+ }
+ display_list->push<ConcatOp>(m);
+ }
+
+ void PushDrawOp(scoped_refptr<DisplayItemList> display_list,
+ sk_sp<PaintFilter> filter) {
+ TextBlobStrategy strategy = GetTextBlobStrategy(GetParam());
+
+ auto text_blob = BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText());
+
+ PaintFlags text_flags;
+ text_flags.setStyle(PaintFlags::kFill_Style);
+ text_flags.setColor(SK_ColorGREEN);
+ if (filter && (strategy == TextBlobStrategy::kDirect ||
+ strategy == TextBlobStrategy::kDrawRecord)) {
+ // If there's a filter, the only PaintFlags that are available for these
+ // two text-drawing strategies is 'text_flags'.
+ text_flags.setImageFilter(std::move(filter));
+ filter = nullptr;
+ }
+ if (strategy == TextBlobStrategy::kDirect) {
+ display_list->push<DrawTextBlobOp>(std::move(text_blob), 0u, kTextBlobY,
+ text_flags);
+ return;
+ }
+
+ // All remaining strategies add the DrawTextBlobOp to an inner paint record.
auto paint_record = sk_make_sp<PaintOpBuffer>();
- PaintFlags flags;
- flags.setStyle(PaintFlags::kFill_Style);
- flags.setColor(SK_ColorGREEN);
- paint_record->push<DrawTextBlobOp>(
- BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags);
- auto paint_record_filter =
- sk_make_sp<RecordPaintFilter>(paint_record, SkRect::MakeWH(100, 100));
+ paint_record->push<DrawTextBlobOp>(std::move(text_blob), 0u, kTextBlobY,
+ text_flags);
+ if (strategy == TextBlobStrategy::kDrawRecord) {
+ display_list->push<DrawRecordOp>(std::move(paint_record));
+ return;
+ }
- auto display_item_list = base::MakeRefCounted<DisplayItemList>();
- display_item_list->StartPaint();
- display_item_list->push<SetMatrixOp>(mat);
- PaintFlags shader_flags;
- shader_flags.setImageFilter(paint_record_filter);
- display_item_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), shader_flags);
- display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
- display_item_list->Finalize();
+ PaintFlags record_flags;
+ if (strategy == TextBlobStrategy::kRecordShader) {
+ auto paint_record_shader = PaintShader::MakePaintRecord(
+ paint_record, SkRect::MakeWH(25, 25), SkTileMode::kRepeat,
+ SkTileMode::kRepeat, nullptr,
+ PaintShader::ScalingBehavior::kRasterAtScale);
+ // Force paint_flags to convert this to kFixedScale, so we can safely
+ // compare pixels between direct and oop-r modes (since oop will convert
+ // to kFixedScale no matter what.
+ paint_record_shader->set_has_animated_images(true);
+
+ record_flags.setShader(paint_record_shader);
+ record_flags.setImageFilter(std::move(filter));
+ } else {
+ DCHECK(strategy == TextBlobStrategy::kRecordFilter);
+
+ sk_sp<PaintFilter> paint_record_filter =
+ sk_make_sp<RecordPaintFilter>(paint_record, SkRect::MakeWH(100, 100));
+ // If there's an additional filter, we have to compose it with the
+ // paint record filter.
+ if (filter) {
+ paint_record_filter = sk_make_sp<ComposePaintFilter>(
+ std::move(filter), std::move(paint_record_filter));
+ }
+ record_flags.setImageFilter(std::move(paint_record_filter));
+ }
- auto actual = Raster(display_item_list, options);
- auto expected = RasterExpectedBitmap(display_item_list, options);
- ExpectEquals(actual, expected);
+ // Use bilerp sampling with the PaintRecord to help reduce max RGB error
+ // from pixel-snapping flakiness when using NN sampling.
+ record_flags.setFilterQuality(kLow_SkFilterQuality);
+
+ // The text blob is embedded in a paint record, which is attached to the
+ // paint via a shader or image filter. Just draw a rect with the paint.
+ display_list->push<DrawRectOp>(SkRect::MakeWH(50, 50), record_flags);
+ }
+
+ static TextBlobStrategy GetTextBlobStrategy(
+ const TextBlobTestConfig& config) {
+ return ::testing::get<0>(config);
+ }
+ static FilterStrategy GetFilterStrategy(const TextBlobTestConfig& config) {
+ return ::testing::get<1>(config);
+ }
+ static MatrixStrategy GetMatrixStrategy(const TextBlobTestConfig& config) {
+ return ::testing::get<2>(config);
+ }
+ static LCDStrategy GetLCDStrategy(const TextBlobTestConfig& config) {
+ return ::testing::get<3>(config);
+ }
+
+ bool UseLcdText() const {
+ return GetLCDStrategy(GetParam()) == LCDStrategy::kYes;
+ }
+
+ static std::string PrintTestName(
+ const ::testing::TestParamInfo<TextBlobTestConfig>& info) {
+ std::stringstream ss;
+ switch (GetTextBlobStrategy(info.param)) {
+ case TextBlobStrategy::kDirect:
+ ss << "Direct";
+ break;
+ case TextBlobStrategy::kDrawRecord:
+ ss << "DrawRecord";
+ break;
+ case TextBlobStrategy::kRecordShader:
+ ss << "RecordShader";
+ break;
+ case TextBlobStrategy::kRecordFilter:
+ ss << "RecordFilter";
+ break;
+ }
+ ss << "_";
+ switch (GetFilterStrategy(info.param)) {
+ case FilterStrategy::kNone:
+ ss << "NoFilter";
+ break;
+ case FilterStrategy::kPaintFlags:
+ ss << "FilterOnPaint";
+ break;
+ case FilterStrategy::kSaveLayer:
+ ss << "FilterOnLayer";
+ break;
+ }
+ ss << "_";
+ switch (GetMatrixStrategy(info.param)) {
+ case MatrixStrategy::kIdentity:
+ ss << "IdentityCTM";
+ break;
+ case MatrixStrategy::kScaled:
+ ss << "ScaledCTM";
+ break;
+ case MatrixStrategy::kComplex:
+ ss << "ComplexCTM";
+ break;
+ case MatrixStrategy::kPerspective:
+ ss << "PerspectiveCTM";
+ break;
+ }
+ ss << "_";
+ switch (GetLCDStrategy(info.param)) {
+ case LCDStrategy::kNo:
+ ss << "NoLCD";
+ break;
+ case LCDStrategy::kYes:
+ ss << "LCD";
+ break;
+ }
+
+ return ss.str();
}
};
-TEST_P(OopRecordFilterPixelTest, FilterWithTextScaled) {
- SkM44 mat = SkM44::Scale(2.f, 2.f);
- RunTest(mat);
+TEST_P(OopTextBlobPixelTest, Config) {
+ RunTest();
}
-TEST_P(OopRecordFilterPixelTest, FilterWithTextAndComplexCTM) {
- SkM44 mat = SkM44::Scale(2.f, 2.f);
- SkM44 skew = SkM44();
- skew.setRC(0, 1, 2.f);
- skew.setRC(1, 0, 2.f);
- mat.preConcat(skew);
- RunTest(mat);
-}
+INSTANTIATE_TEST_SUITE_P(
+ P,
+ OopTextBlobPixelTest,
+ ::testing::Combine(::testing::Values(TextBlobStrategy::kDirect,
+ TextBlobStrategy::kDrawRecord,
+ TextBlobStrategy::kRecordShader,
+ TextBlobStrategy::kRecordFilter),
+ ::testing::Values(FilterStrategy::kNone,
+ FilterStrategy::kPaintFlags,
+ FilterStrategy::kSaveLayer),
+ ::testing::Values(MatrixStrategy::kIdentity,
+ MatrixStrategy::kScaled,
+ MatrixStrategy::kComplex,
+ MatrixStrategy::kPerspective),
+ ::testing::Values(LCDStrategy::kNo, LCDStrategy::kYes)),
+ OopTextBlobPixelTest::PrintTestName);
void ClearFontCache(CompletionEvent* event) {
SkGraphics::PurgeFontCache();
@@ -1812,8 +2014,8 @@ TEST_F(OopPixelTest, DrawTextMultipleRasterCHROMIUM) {
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SK_ColorGREEN);
- display_item_list->push<DrawTextBlobOp>(BuildTextBlob(sk_typeface_1), 0u, 0u,
- flags);
+ display_item_list->push<DrawTextBlobOp>(BuildTextBlob(sk_typeface_1), 0u,
+ kTextBlobY, flags);
display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
display_item_list->Finalize();
@@ -1821,7 +2023,7 @@ TEST_F(OopPixelTest, DrawTextMultipleRasterCHROMIUM) {
auto display_item_list_2 = base::MakeRefCounted<DisplayItemList>();
display_item_list_2->StartPaint();
display_item_list_2->push<DrawTextBlobOp>(BuildTextBlob(sk_typeface_2), 0u,
- 0u, flags);
+ kTextBlobY, flags);
display_item_list_2->EndPaintOfUnpaired(options.full_raster_rect);
display_item_list_2->Finalize();
@@ -1853,7 +2055,8 @@ TEST_F(OopPixelTest, DrawTextBlobPersistentShaderCache) {
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SK_ColorGREEN);
- display_item_list->push<DrawTextBlobOp>(BuildTextBlob(), 0u, 0u, flags);
+ display_item_list->push<DrawTextBlobOp>(BuildTextBlob(), 0u, kTextBlobY,
+ flags);
display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
display_item_list->Finalize();
@@ -2188,8 +2391,6 @@ TEST_F(OopPixelTest, RecordShaderExceedsMaxTextureSize) {
INSTANTIATE_TEST_SUITE_P(P, OopImagePixelTest, ::testing::Bool());
INSTANTIATE_TEST_SUITE_P(P, OopClearPixelTest, ::testing::Bool());
-INSTANTIATE_TEST_SUITE_P(P, OopRecordShaderPixelTest, ::testing::Bool());
-INSTANTIATE_TEST_SUITE_P(P, OopRecordFilterPixelTest, ::testing::Bool());
INSTANTIATE_TEST_SUITE_P(P, OopPathPixelTest, ::testing::Bool());
} // namespace
diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc
index 9e32ec4b729..3ad2d2f46dd 100644
--- a/chromium/cc/paint/paint_filter.cc
+++ b/chromium/cc/paint/paint_filter.cc
@@ -999,12 +999,10 @@ PaintFlagsPaintFilter::PaintFlagsPaintFilter(PaintFlags flags,
shader = SkShaders::Color(paint.getColor());
}
- // TODO(michaelludwig): Remove SkFilterQuality arg once all image shaders are
- // created with explicit filter settings
using Dither = SkImageFilters::Dither;
cached_sk_filter_ = SkImageFilters::Shader(
std::move(shader), paint.isDither() ? Dither::kYes : Dither::kNo,
- paint.getFilterQuality(), crop_rect);
+ crop_rect);
}
PaintFlagsPaintFilter::~PaintFlagsPaintFilter() = default;
@@ -1034,7 +1032,10 @@ MatrixPaintFilter::MatrixPaintFilter(const SkMatrix& matrix,
filter_quality_(filter_quality),
input_(std::move(input)) {
cached_sk_filter_ = SkImageFilters::MatrixTransform(
- matrix_, filter_quality_, GetSkFilter(input_.get()));
+ matrix_,
+ SkSamplingOptions(filter_quality_,
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ GetSkFilter(input_.get()));
}
MatrixPaintFilter::~MatrixPaintFilter() = default;
diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc
index 7e138218e96..a55e680b0a7 100644
--- a/chromium/cc/paint/paint_flags.cc
+++ b/chromium/cc/paint/paint_flags.cc
@@ -11,7 +11,7 @@
namespace {
static bool affects_alpha(const SkColorFilter* cf) {
- return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
+ return cf && !cf->isAlphaUnchanged();
}
} // namespace
@@ -126,7 +126,7 @@ SkPaint PaintFlags::ToSkPaint() const {
SkPaint paint;
paint.setPathEffect(path_effect_);
if (shader_)
- paint.setShader(shader_->GetSkShader());
+ paint.setShader(shader_->GetSkShader(getFilterQuality()));
paint.setMaskFilter(mask_filter_);
paint.setColorFilter(color_filter_);
if (image_filter_)
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index ab1a18c7f2d..01a6906a8dd 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -33,7 +33,17 @@ class PaintWorkletInput;
class TextureBacking;
using PaintRecord = PaintOpBuffer;
-enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kAVIF, kInvalid };
+enum class ImageType {
+ kPNG,
+ kJPEG,
+ kWEBP,
+ kGIF,
+ kICO,
+ kBMP,
+ kAVIF,
+ kJXL,
+ kInvalid
+};
enum class YUVSubsampling { k410, k411, k420, k422, k440, k444, kUnknown };
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index c9f9ac8bb80..bed909886d6 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -2390,6 +2390,8 @@ bool PaintOp::QuickRejectDraw(const PaintOp* op, const SkCanvas* canvas) {
SkRect rect;
if (!PaintOp::GetBounds(op, &rect))
return false;
+ if (!rect.isFinite())
+ return true;
if (op->IsPaintOpWithFlags()) {
SkPaint paint = static_cast<const PaintOpWithFlags*>(op)->flags.ToSkPaint();
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index 39288b97b54..a93104dae1f 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -2613,6 +2613,10 @@ TEST(PaintOpBufferTest, ValidateRects) {
static_cast<char*>(
base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ // Used for QuickRejectDraw
+ SkCanvas device(256, 256);
+ SkCanvas* canvas = &device;
+
SkRect bad_rect = SkRect::MakeEmpty();
bad_rect.fBottom = std::numeric_limits<float>::quiet_NaN();
EXPECT_FALSE(bad_rect.isFinite());
@@ -2647,6 +2651,14 @@ TEST(PaintOpBufferTest, ValidateRects) {
serialized.get(), bytes_written, deserialized.get(), buffer_size,
&bytes_read, options_provider.deserialize_options());
EXPECT_FALSE(written) << "op: " << op_idx;
+
+ // Additionally, every draw op should be rejected by QuickRejectDraw if
+ // the paint op buffer were played back directly without going through
+ // deserialization (e.g. canvas2D, crbug.com/1186392)
+ if (op->IsDrawOp()) {
+ EXPECT_TRUE(PaintOp::QuickRejectDraw(op, canvas));
+ }
+
++op_idx;
}
}
@@ -3392,7 +3404,6 @@ TEST(PaintOpBufferTest, PaintRecordShaderSerialization) {
EXPECT_FLOAT_RECT_EQ(rect_op->rect, SkRect::MakeXYWH(1, 2, 3, 4));
EXPECT_TRUE(rect_op->flags == flags);
EXPECT_TRUE(*rect_op->flags.getShader() == *flags.getShader());
- EXPECT_TRUE(!!rect_op->flags.getShader()->GetSkShader());
}
#if !defined(OS_ANDROID)
@@ -3696,7 +3707,7 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
// Hold onto records so PaintShader pointer comparisons are valid.
sk_sp<PaintRecord> records[5];
- const SkShader* last_shader = nullptr;
+ SkPicture* last_shader = nullptr;
std::vector<uint8_t> scratch_buffer;
PaintOp::DeserializeOptions deserialize_options(
transfer_cache, options_provider.service_paint_cache(),
@@ -3731,8 +3742,8 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
// In every case, the shader in the op should get cached for future
// use.
- auto* op_skshader = op->flags.getShader()->GetSkShader().get();
- EXPECT_EQ(op_skshader, entry->shader()->GetSkShader().get());
+ auto* op_skshader = op->flags.getShader()->sk_cached_picture_.get();
+ EXPECT_EQ(op_skshader, entry->shader()->sk_cached_picture_.get());
switch (i) {
case 0:
// Nothing to check.
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index eb795ba528e..68429994cd9 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -590,7 +590,7 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
// All shader types but records are done.
if (shader_type != PaintShader::Type::kPaintRecord) {
- (*shader)->CreateSkShader();
+ (*shader)->ResolveSkObjects();
return;
}
@@ -607,10 +607,11 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
// side transfer cache to only having one entry per shader but this will hit
// the common case of enabling Skia reuse.
if (entry && entry->shader()->tile_ == ref.tile_) {
- DCHECK(!ref.cached_shader_);
- ref.cached_shader_ = entry->shader()->GetSkShader();
+ DCHECK(!ref.sk_cached_picture_);
+ ref.sk_cached_picture_ = entry->shader()->sk_cached_picture_;
} else {
- ref.CreateSkShader();
+ ref.ResolveSkObjects();
+ DCHECK(ref.sk_cached_picture_);
options_.transfer_cache->CreateLocalEntry(
shader_id, std::make_unique<ServiceShaderTransferCacheEntry>(
*shader, shader_size));
diff --git a/chromium/cc/paint/paint_shader.cc b/chromium/cc/paint/paint_shader.cc
index 02cdea0b8b9..f221163b646 100644
--- a/chromium/cc/paint/paint_shader.cc
+++ b/chromium/cc/paint/paint_shader.cc
@@ -69,7 +69,7 @@ const PaintShader::RecordShaderId PaintShader::kInvalidRecordShaderId = -1;
sk_sp<PaintShader> PaintShader::MakeEmpty() {
sk_sp<PaintShader> shader(new PaintShader(Type::kEmpty));
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -79,7 +79,7 @@ sk_sp<PaintShader> PaintShader::MakeColor(SkColor color) {
// Just one color. Store it in the fallback color. Easy.
shader->fallback_color_ = color;
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -100,7 +100,7 @@ sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -121,7 +121,7 @@ sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -147,7 +147,7 @@ sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -171,7 +171,7 @@ sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -189,7 +189,7 @@ sk_sp<PaintShader> PaintShader::MakeImage(const PaintImage& image,
shader->tile_ = *tile_rect;
}
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -208,7 +208,7 @@ sk_sp<PaintShader> PaintShader::MakePaintRecord(
shader->scaling_behavior_ = scaling_behavior;
shader->SetMatrixAndTiling(local_matrix, tx, ty);
- shader->CreateSkShader();
+ shader->ResolveSkObjects();
return shader;
}
@@ -413,24 +413,19 @@ sk_sp<PaintShader> PaintShader::CreateDecodedImage(
return PaintShader::MakeImage(decoded_paint_image, tx_, ty_, &final_matrix);
}
-sk_sp<SkShader> PaintShader::GetSkShader() const {
- return cached_shader_;
-}
-
-void PaintShader::CreateSkShader(const gfx::SizeF* raster_scale,
- ImageProvider* image_provider) {
- DCHECK(!cached_shader_);
+sk_sp<SkShader> PaintShader::GetSkShader(SkFilterQuality quality) const {
+ SkSamplingOptions sampling(quality,
+ SkSamplingOptions::kMedium_asMipmapLinear);
switch (shader_type_) {
case Type::kEmpty:
- cached_shader_ = SkShaders::Empty();
- break;
+ return SkShaders::Empty();
case Type::kColor:
// This will be handled by the fallback check below.
break;
case Type::kLinearGradient: {
SkPoint points[2] = {start_point_, end_point_};
- cached_shader_ = SkGradientShader::MakeLinear(
+ return SkGradientShader::MakeLinear(
points, colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
@@ -438,66 +433,84 @@ void PaintShader::CreateSkShader(const gfx::SizeF* raster_scale,
break;
}
case Type::kRadialGradient:
- cached_shader_ = SkGradientShader::MakeRadial(
+ return SkGradientShader::MakeRadial(
center_, start_radius_, colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
base::OptionalOrNullptr(local_matrix_));
break;
case Type::kTwoPointConicalGradient:
- cached_shader_ = SkGradientShader::MakeTwoPointConical(
+ return SkGradientShader::MakeTwoPointConical(
start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
base::OptionalOrNullptr(local_matrix_));
break;
case Type::kSweepGradient:
- cached_shader_ = SkGradientShader::MakeSweep(
+ return SkGradientShader::MakeSweep(
center_.x(), center_.y(), colors_.data(),
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
flags_, base::OptionalOrNullptr(local_matrix_));
break;
case Type::kImage:
- if (image_ && !image_.IsPaintWorklet()) {
- cached_shader_ = image_.GetSkImage()->makeShader(
- tx_, ty_, base::OptionalOrNullptr(local_matrix_));
+ if (sk_cached_image_) {
+ return sk_cached_image_->makeShader(
+ tx_, ty_, sampling, base::OptionalOrNullptr(local_matrix_));
}
break;
- case Type::kPaintRecord: {
- // Create a recording at the desired scale if this record has images which
- // have been decoded before raster.
- auto picture = ToSkPicture(record_, tile_, raster_scale, image_provider);
-
- switch (scaling_behavior_) {
- // For raster scale, we create a picture shader directly.
- case ScalingBehavior::kRasterAtScale:
- cached_shader_ = picture->makeShader(
- tx_, ty_, base::OptionalOrNullptr(local_matrix_), nullptr);
- break;
- // For fixed scale, we create an image shader with an image backed by
- // the picture.
- case ScalingBehavior::kFixedScale: {
- auto image = SkImage::MakeFromPicture(
- std::move(picture), SkISize::Make(tile_.width(), tile_.height()),
- nullptr, nullptr, SkImage::BitDepth::kU8,
- SkColorSpace::MakeSRGB());
- cached_shader_ = image->makeShader(
- tx_, ty_, base::OptionalOrNullptr(local_matrix_));
- break;
+ case Type::kPaintRecord:
+ if (sk_cached_picture_) {
+ switch (scaling_behavior_) {
+ // For raster scale, we create a picture shader directly.
+ case ScalingBehavior::kRasterAtScale:
+ return sk_cached_picture_->makeShader(
+ tx_, ty_, sampling.filter,
+ base::OptionalOrNullptr(local_matrix_), nullptr);
+ break;
+ // For fixed scale, we create an image shader with an image backed by
+ // the picture.
+ case ScalingBehavior::kFixedScale: {
+ auto image = SkImage::MakeFromPicture(
+ sk_cached_picture_,
+ SkISize::Make(tile_.width(), tile_.height()), nullptr, nullptr,
+ SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
+ return image->makeShader(tx_, ty_, sampling,
+ base::OptionalOrNullptr(local_matrix_));
+ break;
+ }
}
+ break;
}
break;
- }
case Type::kShaderCount:
NOTREACHED();
break;
}
- // If we didn't create a shader for whatever reason, create a fallback color
- // one.
- if (!cached_shader_)
- cached_shader_ = SkShaders::Color(fallback_color_);
+ // If we didn't create a shader for whatever reason, create a fallback
+ // color one.
+ return SkShaders::Color(fallback_color_);
+}
+
+void PaintShader::ResolveSkObjects(const gfx::SizeF* raster_scale,
+ ImageProvider* image_provider) {
+ switch (shader_type_) {
+ case Type::kImage:
+ if (image_ && !image_.IsPaintWorklet()) {
+ sk_cached_image_ = image_.GetSkImage();
+ }
+ break;
+ case Type::kPaintRecord: {
+ // Create a recording at the desired scale if this record has images
+ // which have been decoded before raster.
+ sk_cached_picture_ =
+ ToSkPicture(record_, tile_, raster_scale, image_provider);
+ break;
+ }
+ default:
+ break;
+ }
}
void PaintShader::SetColorsAndPositions(const SkColor* colors,
@@ -528,15 +541,44 @@ void PaintShader::SetFlagsAndFallback(uint32_t flags, SkColor fallback_color) {
}
bool PaintShader::IsOpaque() const {
- // TODO(enne): don't create a shader to answer this.
- return GetSkShader()->isOpaque();
+ switch (shader_type_) {
+ case Type::kEmpty:
+ return false;
+ case Type::kColor:
+ // This will be handled by the fallback check below.
+ break;
+ case Type::kLinearGradient: // fall-through
+ case Type::kRadialGradient: // fall-through
+ case Type::kSweepGradient:
+ if (tx_ == SkTileMode::kDecal)
+ return false;
+ for (const auto& c : colors_)
+ if (SkColorGetA(c) != 0xFF)
+ return false;
+ return true;
+ case Type::kTwoPointConicalGradient:
+ // Because two-point-conical can sometimes ignore its tiling and not draw
+ // everywhere, we conservatively return false here. If we measure
+ // performance reasons to be more aggressive here, we can ask Skia to
+ // expose private functionality to compute this with having to actually
+ // instantiate a sk_shader object.
+ return false;
+ case Type::kImage:
+ if (tx_ == SkTileMode::kDecal || ty_ == SkTileMode::kDecal)
+ return false;
+ if (sk_cached_image_)
+ return sk_cached_image_->isOpaque();
+ return false;
+ case Type::kPaintRecord:
+ return false;
+ case Type::kShaderCount:
+ NOTREACHED();
+ break;
+ }
+ return SkColorGetA(fallback_color_) == 0xFF;
}
bool PaintShader::IsValid() const {
- // If we managed to create a shader already, then we should be valid.
- if (cached_shader_)
- return true;
-
switch (shader_type_) {
case Type::kEmpty:
case Type::kColor:
diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h
index 7b6940cea87..a2ae2576a93 100644
--- a/chromium/cc/paint/paint_shader.h
+++ b/chromium/cc/paint/paint_shader.h
@@ -182,9 +182,13 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
explicit PaintShader(Type type);
- sk_sp<SkShader> GetSkShader() const;
- void CreateSkShader(const gfx::SizeF* raster_scale = nullptr,
- ImageProvider* image_provider = nullptr);
+ sk_sp<SkShader> GetSkShader(SkFilterQuality quality) const;
+
+ // If the type needs a resolve skia object (e.g. SkImage or SkPicture), this
+ // will create and cache it internally. Most types do not need this, but it
+ // is safe to call on any type.
+ void ResolveSkObjects(const gfx::SizeF* raster_scale = nullptr,
+ ImageProvider* image_provider = nullptr);
// Creates a PaintShader to be rasterized at the given ctm. |raster_scale| is
// set to the scale at which the record should be rasterized when the shader
@@ -251,10 +255,9 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
std::vector<SkColor> colors_;
std::vector<SkScalar> positions_;
- // The |cached_shader_| can be derived/creates from other inputs present in
- // the PaintShader but we always construct it at creation time to ensure that
- // accesses to it are thread-safe.
- sk_sp<SkShader> cached_shader_;
+ // Cached intermediates, for cc::Paint objects that may not be thread-safe
+ sk_sp<SkPicture> sk_cached_picture_;
+ sk_sp<SkImage> sk_cached_image_;
ImageAnalysisState image_analysis_state_ = ImageAnalysisState::kNoAnalysis;
};
diff --git a/chromium/cc/paint/scoped_raster_flags.cc b/chromium/cc/paint/scoped_raster_flags.cc
index 1e5b87e6ad3..8bd3ce0640c 100644
--- a/chromium/cc/paint/scoped_raster_flags.cc
+++ b/chromium/cc/paint/scoped_raster_flags.cc
@@ -101,8 +101,8 @@ void ScopedRasterFlags::DecodeRecordShader(const SkMatrix& ctm,
gfx::SizeF raster_scale(1.f, 1.f);
auto decoded_shader = flags()->getShader()->CreateScaledPaintRecord(
ctm, max_texture_size, &raster_scale);
- decoded_shader->CreateSkShader(&raster_scale,
- &*decode_stashing_image_provider_);
+ decoded_shader->ResolveSkObjects(&raster_scale,
+ &*decode_stashing_image_provider_);
MutableFlags()->setShader(std::move(decoded_shader));
}
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index 0f76c1a85c2..3726fd4ae6f 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -61,6 +61,7 @@ static void RasterizeSourceOOP(
const RasterSource::PlaybackSettings& playback_settings,
viz::RasterContextProvider* context_provider) {
gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
+ bool mailbox_needs_clear = false;
if (mailbox->IsZero()) {
DCHECK(!sync_token.HasData());
auto* sii = context_provider->SharedImageInterface();
@@ -72,14 +73,16 @@ static void RasterizeSourceOOP(
*mailbox = sii->CreateSharedImage(
resource_format, resource_size, color_space, kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, flags, gpu::kNullSurfaceHandle);
+ mailbox_needs_clear = true;
ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
} else {
ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
}
ri->BeginRasterCHROMIUM(
- raster_source->background_color(), playback_settings.msaa_sample_count,
- playback_settings.use_lcd_text, color_space, mailbox->name);
+ raster_source->background_color(), mailbox_needs_clear,
+ playback_settings.msaa_sample_count, playback_settings.use_lcd_text,
+ color_space, mailbox->name);
float recording_to_raster_scale =
transform.scale() / raster_source->recording_scale_factor();
gfx::Size content_size = raster_source->GetContentSize(transform.scale());
diff --git a/chromium/cc/raster/raster_buffer_provider_unittest.cc b/chromium/cc/raster/raster_buffer_provider_unittest.cc
index a19a04e98a9..4a281c36c24 100644
--- a/chromium/cc/raster/raster_buffer_provider_unittest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_unittest.cc
@@ -174,6 +174,7 @@ class RasterImplementationForOOPR
}
}
void BeginRasterCHROMIUM(GLuint sk_color,
+ GLboolean needs_clear,
GLuint msaa_sample_count,
GLboolean can_use_lcd_text,
const gfx::ColorSpace& color_space,
diff --git a/chromium/cc/raster/single_thread_task_graph_runner.cc b/chromium/cc/raster/single_thread_task_graph_runner.cc
index 0735d4e91ee..c772814faa8 100644
--- a/chromium/cc/raster/single_thread_task_graph_runner.cc
+++ b/chromium/cc/raster/single_thread_task_graph_runner.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include <utility>
@@ -26,8 +27,8 @@ SingleThreadTaskGraphRunner::~SingleThreadTaskGraphRunner() = default;
void SingleThreadTaskGraphRunner::Start(
const std::string& thread_name,
const base::SimpleThread::Options& thread_options) {
- thread_.reset(
- new base::DelegateSimpleThread(this, thread_name, thread_options));
+ thread_ = std::make_unique<base::DelegateSimpleThread>(this, thread_name,
+ thread_options);
thread_->StartAsync();
}
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index bacb2272f72..f5f68d76a23 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -36,14 +36,18 @@ Scheduler::Scheduler(
const SchedulerSettings& settings,
int layer_tree_host_id,
base::SingleThreadTaskRunner* task_runner,
- std::unique_ptr<CompositorTimingHistory> compositor_timing_history)
+ std::unique_ptr<CompositorTimingHistory> compositor_timing_history,
+ gfx::RenderingPipeline* main_thread_pipeline,
+ gfx::RenderingPipeline* compositor_thread_pipeline)
: settings_(settings),
client_(client),
layer_tree_host_id_(layer_tree_host_id),
task_runner_(task_runner),
compositor_timing_history_(std::move(compositor_timing_history)),
begin_impl_frame_tracker_(FROM_HERE),
- state_machine_(settings) {
+ state_machine_(settings),
+ main_thread_pipeline_(main_thread_pipeline),
+ compositor_thread_pipeline_(compositor_thread_pipeline) {
TRACE_EVENT1("cc", "Scheduler::Scheduler", "settings", settings_.AsValue());
DCHECK(client_);
DCHECK(!state_machine_.BeginFrameNeeded());
@@ -148,10 +152,12 @@ void Scheduler::SetNeedsPrepareTiles() {
}
void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token,
- EventMetricsSet events_metrics) {
+ EventMetricsSet events_metrics,
+ bool has_missing_content) {
compositor_timing_history_->DidSubmitCompositorFrame(
frame_token, begin_main_frame_args_.frame_id,
- last_activate_origin_frame_args_.frame_id, std::move(events_metrics));
+ last_activate_origin_frame_args_.frame_id, std::move(events_metrics),
+ has_missing_content);
state_machine_.DidSubmitCompositorFrame();
// There is no need to call ProcessScheduledActions here because
@@ -185,6 +191,8 @@ void Scheduler::NotifyReadyToCommit(
}
void Scheduler::DidCommit() {
+ if (main_thread_pipeline_)
+ main_thread_pipeline_->NotifyFrameFinished();
compositor_timing_history_->DidCommit();
}
@@ -194,6 +202,8 @@ void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) {
compositor_timing_history_->BeginMainFrameAborted(
last_dispatched_begin_main_frame_args_.frame_id, reason);
state_machine_.BeginMainFrameAborted(reason);
+ if (main_thread_pipeline_)
+ main_thread_pipeline_->NotifyFrameFinished();
ProcessScheduledActions();
}
@@ -283,6 +293,8 @@ void Scheduler::StartOrStopBeginFrames() {
devtools_instrumentation::NeedsBeginFrameChanged(layer_tree_host_id_,
false);
client_->WillNotReceiveBeginFrame();
+ main_thread_pipeline_active_.reset();
+ compositor_thread_pipeline_active_.reset();
}
}
@@ -477,20 +489,9 @@ void Scheduler::BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args) {
adjusted_args.interval -
compositor_timing_history_->DrawDurationEstimate() - kDeadlineFudgeFactor;
- // An estimate of time from starting the main frame on the main thread to when
- // the resulting pending tree is activated. Note that this excludes the
- // durations where progress is blocked due to back pressure in the pipeline
- // (ready to commit to commit, ready to activate to activate, etc.)
- base::TimeDelta bmf_start_to_activate =
- compositor_timing_history_
- ->BeginMainFrameStartToReadyToCommitDurationEstimate() +
- compositor_timing_history_->CommitDurationEstimate() +
- compositor_timing_history_->CommitToReadyToActivateDurationEstimate() +
- compositor_timing_history_->ActivateDurationEstimate();
-
base::TimeDelta bmf_to_activate_estimate_critical =
- bmf_start_to_activate +
- compositor_timing_history_->BeginMainFrameQueueDurationCriticalEstimate();
+ compositor_timing_history_
+ ->BeginMainFrameQueueToActivateCriticalEstimate();
state_machine_.SetCriticalBeginMainFrameToActivateIsFast(
bmf_to_activate_estimate_critical < bmf_to_activate_threshold);
@@ -510,17 +511,15 @@ void Scheduler::BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args) {
time_since_main_frame_sent =
now - compositor_timing_history_->begin_main_frame_sent_time();
}
- base::TimeDelta bmf_sent_to_ready_to_commit_estimate =
- compositor_timing_history_
- ->BeginMainFrameStartToReadyToCommitDurationEstimate();
+ base::TimeDelta bmf_sent_to_ready_to_commit_estimate;
if (begin_main_frame_args_.on_critical_path) {
- bmf_sent_to_ready_to_commit_estimate +=
+ bmf_sent_to_ready_to_commit_estimate =
compositor_timing_history_
- ->BeginMainFrameQueueDurationCriticalEstimate();
+ ->BeginMainFrameStartToReadyToCommitCriticalEstimate();
} else {
- bmf_sent_to_ready_to_commit_estimate +=
+ bmf_sent_to_ready_to_commit_estimate =
compositor_timing_history_
- ->BeginMainFrameQueueDurationNotCriticalEstimate();
+ ->BeginMainFrameStartToReadyToCommitNotCriticalEstimate();
}
bool main_thread_response_expected_before_deadline;
@@ -540,9 +539,8 @@ void Scheduler::BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args) {
base::TimeDelta bmf_to_activate_estimate = bmf_to_activate_estimate_critical;
if (!begin_main_frame_args_.on_critical_path) {
bmf_to_activate_estimate =
- bmf_start_to_activate +
compositor_timing_history_
- ->BeginMainFrameQueueDurationNotCriticalEstimate();
+ ->BeginMainFrameQueueToActivateNotCriticalEstimate();
}
bool can_activate_before_deadline =
CanBeginMainFrameAndActivateBeforeDeadline(adjusted_args,
@@ -563,6 +561,29 @@ void Scheduler::BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args) {
skipped_last_frame_to_reduce_latency_ = false;
+ // A pipeline is activated if it's subscribed to BeginFrame callbacks. For the
+ // compositor this implies BeginImplFrames while for the main thread it would
+ // be BeginMainFrames.
+ // TODO(crbug.com/1157620) : For now this also includes cases where the
+ // rendering loop doesn't lead to any visual updates, for example a rAF
+ // callback updating content offscreen. These can be treated differently from
+ // a scheduling perspective (Idle vs Animating).
+ if (compositor_thread_pipeline_) {
+ if (!compositor_thread_pipeline_active_)
+ compositor_thread_pipeline_active_.emplace(compositor_thread_pipeline_);
+ compositor_thread_pipeline_->SetTargetDuration(adjusted_args.interval);
+ }
+
+ if (main_thread_pipeline_) {
+ // TODO(crbug.com/1157620) : We need a heuristic to mark the main pipeline
+ // inactive if it stops subscribing to main frames. For instance after a
+ // composited animation is committed.
+ if (state_machine_.did_commit_during_frame() &&
+ !main_thread_pipeline_active_)
+ main_thread_pipeline_active_.emplace(main_thread_pipeline_);
+ main_thread_pipeline_->SetTargetDuration(adjusted_args.interval);
+ }
+
BeginImplFrame(adjusted_args, now);
}
@@ -618,6 +639,9 @@ void Scheduler::FinishImplFrame() {
if (begin_frame_source_)
begin_frame_source_->DidFinishFrame(this);
+
+ if (compositor_thread_pipeline_)
+ compositor_thread_pipeline_->NotifyFrameFinished();
}
void Scheduler::SendDidNotProduceFrame(const viz::BeginFrameArgs& args,
@@ -942,9 +966,6 @@ void Scheduler::AsProtozeroInto(
if (begin_frame_source_) {
begin_frame_source_->AsProtozeroInto(state->set_begin_frame_source_state());
}
-
- compositor_timing_history_->AsProtozeroInto(
- state->set_compositor_timing_history());
}
void Scheduler::UpdateCompositorTimingHistoryRecordingEnabled() {
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index eb0ba20ac57..3784cda0bb1 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -22,6 +22,7 @@
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+#include "ui/gfx/rendering_pipeline.h"
namespace perfetto {
namespace protos {
@@ -97,7 +98,9 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
base::SingleThreadTaskRunner* task_runner,
- std::unique_ptr<CompositorTimingHistory> compositor_timing_history);
+ std::unique_ptr<CompositorTimingHistory> compositor_timing_history,
+ gfx::RenderingPipeline* main_thread_pipeline,
+ gfx::RenderingPipeline* compositor_thread_pipeline);
Scheduler(const Scheduler&) = delete;
~Scheduler() override;
@@ -175,7 +178,8 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
// Drawing should result in submitting a CompositorFrame to the
// LayerTreeFrameSink and then calling this.
void DidSubmitCompositorFrame(uint32_t frame_token,
- EventMetricsSet events_metrics);
+ EventMetricsSet events_metrics,
+ bool has_missing_content);
// The LayerTreeFrameSink acks when it is ready for a new frame which
// should result in this getting called to unblock the next draw.
void DidReceiveCompositorFrameAck();
@@ -328,6 +332,14 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
// arrive so that |client_| can be informed about changes.
base::TimeDelta last_frame_interval_;
+ gfx::RenderingPipeline* const main_thread_pipeline_;
+ base::Optional<gfx::RenderingPipeline::ScopedPipelineActive>
+ main_thread_pipeline_active_;
+
+ gfx::RenderingPipeline* const compositor_thread_pipeline_;
+ base::Optional<gfx::RenderingPipeline::ScopedPipelineActive>
+ compositor_thread_pipeline_active_;
+
private:
// Posts the deadline task if needed by checking
// SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode(). This only
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index 69a98b0c94d..400d650855b 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -350,6 +350,7 @@ class CC_EXPORT SchedulerStateMachine {
bool should_defer_invalidation_for_fast_main_frame() const {
return should_defer_invalidation_for_fast_main_frame_;
}
+ bool did_commit_during_frame() const { return did_commit_during_frame_; }
protected:
bool BeginFrameRequiredForAction() const;
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index c7647b28a06..98b0c5a66b7 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -172,7 +173,8 @@ class FakeSchedulerClient : public SchedulerClient,
if (swap_will_happen_if_draw_happens_) {
last_begin_frame_ack_ = scheduler_->CurrentBeginFrameAckForActiveTree();
- scheduler_->DidSubmitCompositorFrame(0, EventMetricsSet());
+ scheduler_->DidSubmitCompositorFrame(0, EventMetricsSet(),
+ /*has_missing_content=*/false);
if (automatic_ack_)
scheduler_->DidReceiveCompositorFrameAck();
@@ -367,11 +369,12 @@ class SchedulerTest : public testing::Test {
protected:
TestScheduler* CreateScheduler(BeginFrameSourceType bfs_type) {
viz::BeginFrameSource* frame_source = nullptr;
- unthrottled_frame_source_.reset(new viz::BackToBackBeginFrameSource(
- std::make_unique<viz::FakeDelayBasedTimeSource>(
- task_runner_->GetMockTickClock(), task_runner_.get())));
- fake_external_begin_frame_source_.reset(
- new viz::FakeExternalBeginFrameSource(1.0, false));
+ unthrottled_frame_source_ =
+ std::make_unique<viz::BackToBackBeginFrameSource>(
+ std::make_unique<viz::FakeDelayBasedTimeSource>(
+ task_runner_->GetMockTickClock(), task_runner_.get()));
+ fake_external_begin_frame_source_ =
+ std::make_unique<viz::FakeExternalBeginFrameSource>(1.0, false);
fake_external_begin_frame_source_->SetClient(client_.get());
synthetic_frame_source_ = std::make_unique<viz::DelayBasedBeginFrameSource>(
std::make_unique<viz::FakeDelayBasedTimeSource>(
@@ -395,9 +398,9 @@ class SchedulerTest : public testing::Test {
scheduler_settings_.using_synchronous_renderer_compositor);
fake_compositor_timing_history_ = fake_compositor_timing_history.get();
- scheduler_.reset(new TestScheduler(
+ scheduler_ = std::make_unique<TestScheduler>(
task_runner_->GetMockTickClock(), client_.get(), scheduler_settings_, 0,
- task_runner_.get(), std::move(fake_compositor_timing_history)));
+ task_runner_.get(), std::move(fake_compositor_timing_history));
client_->set_scheduler(scheduler_.get());
scheduler_->SetBeginFrameSource(frame_source);
diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc
index 120e0c6431f..5d1f57d1b9c 100644
--- a/chromium/cc/tiles/image_controller_unittest.cc
+++ b/chromium/cc/tiles/image_controller_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/tiles/image_controller.h"
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -261,8 +262,8 @@ class ImageControllerTest : public testing::Test {
void SetUp() override {
worker_task_runner_ = base::MakeRefCounted<WorkerTaskRunner>();
- controller_.reset(
- new ImageController(task_runner_.get(), worker_task_runner_));
+ controller_ = std::make_unique<ImageController>(task_runner_.get(),
+ worker_task_runner_);
cache_ = TestableCache();
controller_->SetImageDecodeCache(&cache_);
}
diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h
index bd77daad149..6ab0a4539da 100644
--- a/chromium/cc/tiles/image_decode_cache.h
+++ b/chromium/cc/tiles/image_decode_cache.h
@@ -78,6 +78,8 @@ class CC_EXPORT ImageDecodeCache {
using ScopedImageType =
devtools_instrumentation::ScopedImageDecodeTask::ImageType;
switch (image_type) {
+ case ImageType::kJXL:
+ return ScopedImageType::kJxl;
case ImageType::kAVIF:
return ScopedImageType::kAvif;
case ImageType::kBMP:
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc
index f958c316e26..17d7437952d 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set.cc
@@ -281,9 +281,9 @@ PictureLayerTiling* PictureLayerTilingSet::AddTiling(
raster_source_ = raster_source;
#if DCHECK_IS_ON()
- for (size_t i = 0; i < tilings_.size(); ++i) {
- DCHECK_NE(tilings_[i]->contents_scale_key(), raster_transform.scale());
- DCHECK_EQ(tilings_[i]->raster_source(), raster_source.get());
+ for (const auto& tiling : tilings_) {
+ DCHECK_NE(tiling->contents_scale_key(), raster_transform.scale());
+ DCHECK_EQ(tiling->raster_source(), raster_source.get());
}
#endif // DCHECK_IS_ON()
@@ -307,9 +307,9 @@ int PictureLayerTilingSet::NumHighResTilings() const {
PictureLayerTiling* PictureLayerTilingSet::FindTilingWithScaleKey(
float scale_key) const {
- for (size_t i = 0; i < tilings_.size(); ++i) {
- if (tilings_[i]->contents_scale_key() == scale_key)
- return tilings_[i].get();
+ for (const auto& tiling : tilings_) {
+ if (tiling->contents_scale_key() == scale_key)
+ return tiling.get();
}
return nullptr;
}
@@ -365,8 +365,8 @@ void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
}
void PictureLayerTilingSet::RemoveAllTiles() {
- for (size_t i = 0; i < tilings_.size(); ++i)
- tilings_[i]->Reset();
+ for (const auto& tiling : tilings_)
+ tiling->Reset();
}
float PictureLayerTilingSet::GetSnappedContentsScaleKey(
@@ -725,17 +725,17 @@ PictureLayerTilingSet::CoverageIterator::operator bool() const {
void PictureLayerTilingSet::AsValueInto(
base::trace_event::TracedValue* state) const {
- for (size_t i = 0; i < tilings_.size(); ++i) {
+ for (const auto& tiling : tilings_) {
state->BeginDictionary();
- tilings_[i]->AsValueInto(state);
+ tiling->AsValueInto(state);
state->EndDictionary();
}
}
size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
size_t amount = 0;
- for (size_t i = 0; i < tilings_.size(); ++i)
- amount += tilings_[i]->GPUMemoryUsageInBytes();
+ for (const auto& tiling : tilings_)
+ amount += tiling->GPUMemoryUsageInBytes();
return amount;
}
@@ -746,7 +746,7 @@ PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange(
// compute them only when the tiling set has changed instead.
size_t tilings_size = tilings_.size();
TilingRange high_res_range(0, 0);
- TilingRange low_res_range(tilings_.size(), tilings_.size());
+ TilingRange low_res_range(tilings_size, tilings_size);
for (size_t i = 0; i < tilings_size; ++i) {
const PictureLayerTiling* tiling = tilings_[i].get();
if (tiling->resolution() == HIGH_RESOLUTION)
diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc
index a86bf950bec..2ef6c808508 100644
--- a/chromium/cc/trees/damage_tracker.cc
+++ b/chromium/cc/trees/damage_tracker.cc
@@ -7,7 +7,6 @@
#include <stddef.h>
#include <algorithm>
-#include <utility>
#include "base/memory/ptr_util.h"
#include "cc/base/math_util.h"
@@ -357,14 +356,13 @@ void DamageTracker::AccumulateDamageFromLayer(LayerImpl* layer) {
LayerRectMapData& data = RectDataForLayer(layer->id(), &layer_is_new);
gfx::Rect old_rect_in_target_space = data.rect_;
- gfx::Rect visible_rect_in_target_space =
- layer->visible_drawable_content_rect();
- data.Update(visible_rect_in_target_space, mailboxId_);
+ gfx::Rect rect_in_target_space = layer->GetEnclosingRectInTargetSpace();
+ data.Update(rect_in_target_space, mailboxId_);
if (layer_is_new || layer->LayerPropertyChanged()) {
// If a layer is new or has changed, then its entire layer rect affects the
// target surface.
- damage_for_this_update_.Union(visible_rect_in_target_space);
+ damage_for_this_update_.Union(rect_in_target_space);
// The layer's old region is now exposed on the target surface, too.
// Note old_rect_in_target_space is already in target space.
diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc
index 00fa95b025d..3b0139f0a5e 100644
--- a/chromium/cc/trees/damage_tracker_unittest.cc
+++ b/chromium/cc/trees/damage_tracker_unittest.cc
@@ -5,8 +5,6 @@
#include "cc/trees/damage_tracker.h"
#include <stddef.h>
-#include <limits>
-#include <utility>
#include "base/memory/ptr_util.h"
#include "cc/base/math_util.h"
@@ -73,13 +71,6 @@ void ClearDamageForAllSurfaces(LayerImpl* root) {
}
}
-void SetCopyRequest(LayerImpl* root) {
- auto* root_node = root->layer_tree_impl()->property_trees()->effect_tree.Node(
- root->effect_tree_index());
- root_node->has_copy_request = true;
- root->layer_tree_impl()->property_trees()->effect_tree.set_needs_update(true);
-}
-
class DamageTrackerTest : public LayerTreeImplTestBase, public testing::Test {
public:
LayerImpl* CreateTestTreeWithOneSurface(int number_of_children) {
@@ -279,6 +270,7 @@ class DamageTrackerTest : public LayerTreeImplTestBase, public testing::Test {
// 2. updating all damage trackers in the correct order
// 3. resetting all update_rects and property_changed flags for all layers
// and surfaces.
+
root->layer_tree_impl()->SetDeviceScaleFactor(device_scale_factor);
root->layer_tree_impl()->set_needs_update_draw_properties();
UpdateDrawProperties(root->layer_tree_impl());
@@ -1758,8 +1750,6 @@ TEST_F(DamageTrackerTest, HugeDamageRect) {
for (int i = 0; i < kRange; ++i) {
LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
LayerImpl* child = child_layers_[0];
- // Set copy request to damage the entire layer.
- SetCopyRequest(root);
gfx::Transform transform;
transform.Translate(-kBigNumber, -kBigNumber);
@@ -1797,9 +1787,6 @@ TEST_F(DamageTrackerTest, DamageRectTooBig) {
LayerImpl* child1 = child_layers_[0];
LayerImpl* child2 = child_layers_[1];
- // Set copy request to damage the entire layer.
- SetCopyRequest(root);
-
// Really far left.
child1->SetOffsetToTransformParent(
gfx::Vector2dF(std::numeric_limits<int>::min() + 100, 0));
@@ -1809,7 +1796,9 @@ TEST_F(DamageTrackerTest, DamageRectTooBig) {
child2->SetOffsetToTransformParent(
gfx::Vector2dF(std::numeric_limits<int>::max() - 100, 0));
child2->SetBounds(gfx::Size(1, 1));
- EmulateDrawingOneFrame(root, 1.f);
+
+ float device_scale_factor = 1.f;
+ EmulateDrawingOneFrame(root, device_scale_factor);
// The expected damage would be too large to store in a gfx::Rect, so we
// should damage everything (ie, we don't have a valid rect).
@@ -1828,9 +1817,6 @@ TEST_F(DamageTrackerTest, DamageRectTooBigWithFilter) {
LayerImpl* child1 = child_layers_[0];
LayerImpl* child2 = child_layers_[1];
- // Set copy request to damage the entire layer.
- SetCopyRequest(root);
-
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(5.f));
root->SetDrawsContent(true);
@@ -1864,9 +1850,6 @@ TEST_F(DamageTrackerTest, DamageRectTooBigWithFilter) {
TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfacesDrawingFullyVisible();
- // Set copy request to damage the entire layer.
- SetCopyRequest(root);
-
// Really far left.
grand_child1_->SetOffsetToTransformParent(
gfx::Vector2dF(std::numeric_limits<int>::min() + 500, 0));
@@ -1948,9 +1931,6 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurfaceWithFilter) {
LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
- // Set copy request to damage the entire layer.
- SetCopyRequest(root);
-
// Set up a moving pixels filter on the child.
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(5.f));
@@ -2206,164 +2186,5 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
EXPECT_TRUE(GetRenderSurface(grand_child4_)->intersects_damage_under());
}
-TEST_F(DamageTrackerTest, DamageRectOnlyVisibleContentsMoveToOutside) {
- LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(2);
- ClearDamageForAllSurfaces(root);
-
- LayerImpl* child1 = child_layers_[0];
- LayerImpl* child2 = child_layers_[1];
- gfx::Rect origin_damage = child1->visible_drawable_content_rect();
- origin_damage.Union(child2->visible_drawable_content_rect());
-
- // Really far left.
- child1->SetOffsetToTransformParent(
- gfx::Vector2dF(std::numeric_limits<int>::min() + 100, 0));
- child1->SetBounds(gfx::Size(1, 1));
-
- // Really far right.
- child2->SetOffsetToTransformParent(
- gfx::Vector2dF(std::numeric_limits<int>::max() - 100, 0));
- child2->SetBounds(gfx::Size(1, 1));
- EmulateDrawingOneFrame(root, 1.f);
-
- // Above damages should be excludebe because they're outside of
- // the root surface.
- gfx::Rect damage_rect;
- EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(origin_damage, damage_rect);
- EXPECT_TRUE(GetRenderSurface(root)->content_rect().Contains(damage_rect));
- EXPECT_TRUE(GetRenderSurface(root)
- ->damage_tracker()
- ->has_damage_from_contributing_content());
-}
-
-TEST_F(DamageTrackerTest, DamageRectOnlyVisibleContentsLargeTwoContents) {
- LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(2);
- ClearDamageForAllSurfaces(root);
-
- LayerImpl* child1 = child_layers_[0];
- LayerImpl* child2 = child_layers_[1];
-
- gfx::Rect expected_damage = child1->visible_drawable_content_rect();
- expected_damage.Union(child2->visible_drawable_content_rect());
- expected_damage.set_x(0);
- expected_damage.set_width(GetRenderSurface(root)->content_rect().width());
-
- // Really far left.
- child1->SetOffsetToTransformParent(
- gfx::Vector2dF(std::numeric_limits<int>::min() + 100, 100));
- child1->SetBounds(
- gfx::Size(std::numeric_limits<int>::max(), child1->bounds().height()));
-
- // Really far right.
- child2->SetOffsetToTransformParent(gfx::Vector2dF(100, 100));
- child2->SetBounds(
- gfx::Size(std::numeric_limits<int>::max(), child2->bounds().height()));
- EmulateDrawingOneFrame(root, 1.f);
-
- // Above damages should be excludebe because they're outside of
- // the root surface.
- gfx::Rect damage_rect;
- EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(expected_damage, damage_rect);
- EXPECT_TRUE(GetRenderSurface(root)->content_rect().Contains(damage_rect));
- EXPECT_TRUE(GetRenderSurface(root)
- ->damage_tracker()
- ->has_damage_from_contributing_content());
-}
-
-TEST_F(DamageTrackerTest,
- DamageRectOnlyVisibleContentsHugeContentPartiallyVisible) {
- LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(1);
- int content_width = GetRenderSurface(root)->content_rect().width();
-
- ClearDamageForAllSurfaces(root);
-
- LayerImpl* child1 = child_layers_[0];
- int y = child1->offset_to_transform_parent().y();
- int offset = 100;
- int expected_width = offset + child1->bounds().width();
- // Huge content that exceeds on both side.
- child1->SetOffsetToTransformParent(
- gfx::Vector2dF(std::numeric_limits<int>::min() + offset, y));
- child1->SetBounds(
- gfx::Size(std::numeric_limits<int>::max(), child1->bounds().height()));
-
- EmulateDrawingOneFrame(root);
-
- gfx::Rect expected_damage_rect1(0, y, expected_width,
- child1->bounds().height());
-
- // Above damages should be excludebe because they're outside of
- // the root surface.
- gfx::Rect damage_rect;
- EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(expected_damage_rect1, damage_rect);
- EXPECT_TRUE(GetRenderSurface(root)
- ->damage_tracker()
- ->has_damage_from_contributing_content());
-
- ClearDamageForAllSurfaces(root);
-
- // Now move the huge layer to the right, keeping offset visible.
- child1->SetOffsetToTransformParent(gfx::Vector2dF(content_width - offset, y));
- child1->NoteLayerPropertyChanged();
-
- EmulateDrawingOneFrame(root);
-
- // The damaged rect should be "letter boxed" region.
- gfx::Rect expected_damage_rect2(0, y, content_width,
- child1->bounds().height());
- EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(expected_damage_rect2, damage_rect);
- EXPECT_TRUE(GetRenderSurface(root)
- ->damage_tracker()
- ->has_damage_from_contributing_content());
-}
-
-TEST_F(DamageTrackerTest, VerifyDamageExpansionWithBackdropBlurFilters) {
- LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
-
- // Allow us to set damage on child1_.
- child1_->SetDrawsContent(true);
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(2.f));
-
- // Setting the filter will damage the whole surface.
- ClearDamageForAllSurfaces(root);
- SetBackdropFilter(child1_, filters);
- child1_->NoteLayerPropertyChanged();
- EmulateDrawingOneFrame(root);
-
- ClearDamageForAllSurfaces(root);
- root->UnionUpdateRect(gfx::Rect(297, 297, 2, 2));
- EmulateDrawingOneFrame(root);
-
- // child1_'s render surface has a size of 206x208 due to the contributions
- // from grand_child1_ and grand_child2_. The blur filter on child1_ intersects
- // the damage from root and expands it to (100,100 206x208).
- gfx::Rect expected_damage_rect = gfx::Rect(100, 100, 206, 208);
- gfx::Rect root_damage_rect;
- EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
- &root_damage_rect));
- EXPECT_EQ(expected_damage_rect, root_damage_rect);
-
- ClearDamageForAllSurfaces(root);
- gfx::Rect damage_rect(97, 97, 2, 2);
- root->UnionUpdateRect(damage_rect);
- EmulateDrawingOneFrame(root);
-
- // The blur filter on child1_ doesn't intersect the damage from root so the
- // damage remains unchanged.
- EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
- &root_damage_rect));
- EXPECT_EQ(damage_rect, root_damage_rect);
-}
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/debug_rect_history.cc b/chromium/cc/trees/debug_rect_history.cc
index f2455eb24d3..6d460fad605 100644
--- a/chromium/cc/trees/debug_rect_history.cc
+++ b/chromium/cc/trees/debug_rect_history.cc
@@ -76,6 +76,7 @@ void DebugRectHistory::SaveLayoutShiftRects(HeadsUpDisplayLayerImpl* hud) {
LAYOUT_SHIFT_RECT_TYPE,
MathUtil::MapEnclosingClippedRect(hud->ScreenSpaceTransform(), rect)));
}
+ hud->ClearLayoutShiftRects();
}
void DebugRectHistory::SavePaintRects(LayerTreeImpl* tree_impl) {
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index aa4433edce3..b6c84a81c1d 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -412,15 +412,23 @@ bool IsTransformToRootOf3DRenderingContextBackFaceVisible(
const TransformNode& transform_node =
*transform_tree.Node(transform_tree_index);
- if (transform_node.delegates_to_parent_for_backface)
+ const TransformNode* root_node = &transform_node;
+ if (transform_node.delegates_to_parent_for_backface) {
transform_tree_index = transform_node.parent_id;
+ root_node = transform_tree.Node(transform_tree_index);
+ }
int root_id = transform_tree_index;
int sorting_context_id = transform_node.sorting_context_id;
- while (root_id > 0 && transform_tree.Node(root_id - 1)->sorting_context_id ==
- sorting_context_id)
- root_id--;
+ while (root_id > TransformTree::kRootNodeId) {
+ int parent_id = root_node->parent_id;
+ const TransformNode* parent_node = transform_tree.Node(parent_id);
+ if (parent_node->sorting_context_id != sorting_context_id)
+ break;
+ root_id = parent_id;
+ root_node = parent_node;
+ }
// TODO(chrishtr): cache this on the transform trees if needed, similar to
// |to_target| and |to_screen|.
@@ -428,8 +436,7 @@ bool IsTransformToRootOf3DRenderingContextBackFaceVisible(
if (transform_tree_index != root_id)
property_trees->transform_tree.CombineTransformsBetween(
transform_tree_index, root_id, &to_3d_root);
- to_3d_root.PreconcatTransform(
- property_trees->transform_tree.Node(root_id)->to_parent);
+ to_3d_root.PreconcatTransform(root_node->to_parent);
return to_3d_root.IsBackFaceVisible();
}
@@ -1187,7 +1194,6 @@ void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list,
if (!only_draws_visible_content) {
drawable_bounds = gfx::Rect(layer->bounds());
}
-
gfx::Rect visible_bounds_in_target_space =
MathUtil::MapEnclosingClippedRect(
layer->draw_properties().target_space_transform, drawable_bounds);
diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc
index 20b4257603f..bf2aa003a08 100644
--- a/chromium/cc/trees/effect_node.cc
+++ b/chromium/cc/trees/effect_node.cc
@@ -146,6 +146,8 @@ const char* RenderSurfaceReasonToString(RenderSurfaceReason reason) {
return "mirrored";
case RenderSurfaceReason::kSubtreeIsBeingCaptured:
return "subtree being captured";
+ case RenderSurfaceReason::kDocumentTransitionParticipant:
+ return "document transition participant";
case RenderSurfaceReason::kTest:
return "test";
default:
diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h
index 65edbca03b1..b0d13f4fcde 100644
--- a/chromium/cc/trees/effect_node.h
+++ b/chromium/cc/trees/effect_node.h
@@ -6,6 +6,7 @@
#define CC_TREES_EFFECT_NODE_H_
#include "cc/cc_export.h"
+#include "cc/document_transition/document_transition_shared_element_id.h"
#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
@@ -46,6 +47,7 @@ enum class RenderSurfaceReason : uint8_t {
kCopyRequest,
kMirrored,
kSubtreeIsBeingCaptured,
+ kDocumentTransitionParticipant,
// This must be the last value because it's used in tracing code to know the
// number of reasons.
kTest,
@@ -160,6 +162,9 @@ struct CC_EXPORT EffectNode {
int closest_ancestor_with_copy_request_id;
int closest_ancestor_being_captured_id;
+ // Represents a shared element id for the document transition API.
+ DocumentTransitionSharedElementId document_transition_shared_element_id;
+
bool HasRenderSurface() const {
return render_surface_reason != RenderSurfaceReason::kNone;
}
diff --git a/chromium/cc/trees/frame_rate_estimator.cc b/chromium/cc/trees/frame_rate_estimator.cc
index 577b6a1d710..0ba9354e594 100644
--- a/chromium/cc/trees/frame_rate_estimator.cc
+++ b/chromium/cc/trees/frame_rate_estimator.cc
@@ -49,7 +49,7 @@ void FrameRateEstimator::WillDraw(base::TimeTicks now) {
// The delta below is to account for minor offsets in frame times.
constexpr auto kFudgeDelta = base::TimeDelta::FromMilliseconds(1);
constexpr auto kMinDelta =
- (viz::BeginFrameArgs::DefaultInterval() * 2) + kFudgeDelta;
+ (viz::BeginFrameArgs::DefaultInterval() * 2) - kFudgeDelta;
if (draw_delta < kMinDelta)
num_of_consecutive_frames_with_min_delta_++;
else
diff --git a/chromium/cc/trees/frame_rate_estimator.h b/chromium/cc/trees/frame_rate_estimator.h
index 7ea16833ca5..378a21784e6 100644
--- a/chromium/cc/trees/frame_rate_estimator.h
+++ b/chromium/cc/trees/frame_rate_estimator.h
@@ -20,6 +20,7 @@ class CC_EXPORT FrameRateEstimator {
void WillDraw(base::TimeTicks now);
void NotifyInputEvent();
base::TimeDelta GetPreferredInterval() const;
+ bool input_priority_mode() const { return input_priority_mode_; }
private:
void OnExitInputPriorityMode();
diff --git a/chromium/cc/trees/frame_rate_estimator_unittest.cc b/chromium/cc/trees/frame_rate_estimator_unittest.cc
index d99fabf842b..03df3952a9b 100644
--- a/chromium/cc/trees/frame_rate_estimator_unittest.cc
+++ b/chromium/cc/trees/frame_rate_estimator_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/trees/frame_rate_estimator.h"
+#include "base/stl_util.h"
#include "base/test/test_simple_task_runner.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -69,5 +70,28 @@ TEST_F(FrameRateEstimatorTest, InputPriorityMode) {
EXPECT_NE(estimator_->GetPreferredInterval(),
viz::BeginFrameArgs::MinInterval());
}
+
+TEST_F(FrameRateEstimatorTest, RafAtHalfFps) {
+ estimator_->SetFrameEstimationEnabled(true);
+ // Recorded rAF intervals at 30 fps.
+ const base::TimeDelta kIntervals[] = {
+ base::TimeDelta::FromMicroseconds(33425),
+ base::TimeDelta::FromMicroseconds(33298),
+ base::TimeDelta::FromMicroseconds(33396),
+ base::TimeDelta::FromMicroseconds(33339),
+ base::TimeDelta::FromMicroseconds(33431),
+ base::TimeDelta::FromMicroseconds(33320),
+ base::TimeDelta::FromMicroseconds(33364),
+ base::TimeDelta::FromMicroseconds(33360)};
+ const base::TimeDelta kIntervalForHalfFps =
+ viz::BeginFrameArgs::DefaultInterval() * 2;
+ base::TimeTicks time;
+ for (size_t i = 0; i <= base::size(kIntervals); ++i) {
+ estimator_->WillDraw(time);
+ EXPECT_EQ(kIntervalForHalfFps, estimator_->GetPreferredInterval());
+ if (i < base::size(kIntervals))
+ time += kIntervals[i];
+ }
+}
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_frame_sink_client.h b/chromium/cc/trees/layer_tree_frame_sink_client.h
index e56d9c563cd..a093f88e43e 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_client.h
+++ b/chromium/cc/trees/layer_tree_frame_sink_client.h
@@ -5,6 +5,8 @@
#ifndef CC_TREES_LAYER_TREE_FRAME_SINK_CLIENT_H_
#define CC_TREES_LAYER_TREE_FRAME_SINK_CLIENT_H_
+#include <vector>
+
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
@@ -87,6 +89,11 @@ class CC_EXPORT LayerTreeFrameSinkClient {
const gfx::Rect& viewport_rect,
const gfx::Transform& transform) = 0;
+ // Notification that the compositor frame transition directive has been
+ // processed.
+ virtual void OnCompositorFrameTransitionDirectiveProcessed(
+ uint32_t sequence_id) {}
+
protected:
virtual ~LayerTreeFrameSinkClient() {}
};
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 3b598eb3144..2a5cb55897f 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -17,6 +17,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -143,6 +144,8 @@ LayerTreeHost::LayerTreeHost(InitParams params, CompositorMode mode)
debug_state_(settings_.initial_debug_state),
id_(s_layer_tree_host_sequence_number.GetNext() + 1),
task_graph_runner_(params.task_graph_runner),
+ main_thread_pipeline_(params.main_thread_pipeline),
+ compositor_thread_pipeline_(params.compositor_thread_pipeline),
event_listener_properties_(),
mutator_host_(params.mutator_host),
dark_mode_filter_(params.dark_mode_filter) {
@@ -371,7 +374,7 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
// properties, which updates the clobber_active_value flag.
// TODO(pdr): Enforce this comment with DCHECKS and a lifecycle state.
sync_tree->property_trees()->scroll_tree.PushScrollUpdatesFromMainThread(
- property_trees(), sync_tree);
+ property_trees(), sync_tree, settings_.commit_fractional_scroll_deltas);
// This must happen after synchronizing property trees and after push
// properties, which updates property tree indices, but before animation
@@ -490,10 +493,19 @@ void LayerTreeHost::CommitComplete() {
client_->DidCompletePageScaleAnimation();
did_complete_scale_animation_ = false;
}
+}
- for (auto& closure : committed_document_transition_callbacks_)
- std::move(closure).Run();
- committed_document_transition_callbacks_.clear();
+void LayerTreeHost::NotifyTransitionRequestsFinished(
+ const std::vector<uint32_t>& sequence_ids) {
+ // TODO(vmpstr): This might also be a good spot to expire long standing
+ // requests if they were not finished.
+ for (auto& sequence_id : sequence_ids) {
+ auto it = document_transition_callbacks_.find(sequence_id);
+ if (it == document_transition_callbacks_.end())
+ continue;
+ std::move(it->second).Run();
+ document_transition_callbacks_.erase(it);
+ }
}
void LayerTreeHost::SetLayerTreeFrameSink(
@@ -652,6 +664,9 @@ void LayerTreeHost::SetNextCommitWaitsForActivation() {
void LayerTreeHost::SetNeedsCommitWithForcedRedraw() {
next_commit_forces_redraw_ = true;
+ // This method is used by tests to ensure a commit before grabbing a screen
+ // shot or processing input, so do not defer the commit.
+ StopDeferringCommits(PaintHoldingCommitTrigger::kFeatureDisabled);
proxy_->SetNeedsCommit();
}
@@ -1333,8 +1348,8 @@ void LayerTreeHost::StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool use_anchor,
float scale,
base::TimeDelta duration) {
- pending_page_scale_animation_.reset(new PendingPageScaleAnimation(
- target_offset, use_anchor, scale, duration));
+ pending_page_scale_animation_ = std::make_unique<PendingPageScaleAnimation>(
+ target_offset, use_anchor, scale, duration);
SetNeedsCommit();
}
@@ -1358,6 +1373,14 @@ void LayerTreeHost::SetDisplayColorSpaces(
layer->SetNeedsDisplay();
}
+void LayerTreeHost::UpdateViewportIsMobileOptimized(
+ bool is_viewport_mobile_optimized) {
+ if (is_viewport_mobile_optimized_ == is_viewport_mobile_optimized)
+ return;
+ is_viewport_mobile_optimized_ = is_viewport_mobile_optimized;
+ SetNeedsCommit();
+}
+
void LayerTreeHost::SetExternalPageScaleFactor(
float page_scale_factor,
bool is_external_pinch_gesture_active) {
@@ -1627,10 +1650,13 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
// Transfer page transition directives.
for (auto& request : document_transition_requests_) {
- // Store the commit callback on LayerTreeHost, so that we can invoke them in
- // CommitComplete.
- committed_document_transition_callbacks_.push_back(
- request->TakeCommitCallback());
+ // Store the commit callback on LayerTreeHost, so that we can invoke them
+ // when the request is finished.
+ DCHECK(!base::Contains(document_transition_callbacks_,
+ request->sequence_id()));
+ document_transition_callbacks_[request->sequence_id()] =
+ request->TakeFinishedCallback();
+
tree_impl->AddDocumentTransitionRequest(std::move(request));
}
document_transition_requests_.clear();
@@ -1655,6 +1681,7 @@ void LayerTreeHost::PushLayerTreeHostPropertiesTo(
host_impl->SetDebugState(debug_state_);
host_impl->SetVisualDeviceViewportSize(visual_device_viewport_size_);
+ host_impl->set_viewport_mobile_optimized(is_viewport_mobile_optimized_);
}
Layer* LayerTreeHost::LayerByElementId(ElementId element_id) const {
@@ -1871,6 +1898,9 @@ void LayerTreeHost::SetSourceURL(ukm::SourceId source_id, const GURL& url) {
// produced by this host so far.
clear_caches_on_next_commit_ = true;
proxy_->SetSourceURL(source_id, url);
+ // If this is not used as a common web page, don't show HUD.
+ if (!url.SchemeIsHTTPOrHTTPS())
+ debug_state_.TurnOffHudInfoDisplay();
}
base::ReadOnlySharedMemoryRegion
@@ -1901,14 +1931,25 @@ void LayerTreeHost::SetEnableFrameRateThrottling(
}
void LayerTreeHost::SetDelegatedInkMetadata(
- std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
+ std::unique_ptr<gfx::DelegatedInkMetadata> metadata) {
delegated_ink_metadata_ = std::move(metadata);
SetNeedsCommit();
}
+gfx::RenderingPipeline* LayerTreeHost::TakeMainPipeline() {
+ auto* pipeline = main_thread_pipeline_;
+ main_thread_pipeline_ = nullptr;
+ return pipeline;
+}
+
+gfx::RenderingPipeline* LayerTreeHost::TakeCompositorPipeline() {
+ auto* pipeline = compositor_thread_pipeline_;
+ compositor_thread_pipeline_ = nullptr;
+ return pipeline;
+}
+
std::vector<std::unique_ptr<DocumentTransitionRequest>>
LayerTreeHost::TakeDocumentTransitionRequestsForTesting() {
return std::move(document_transition_requests_);
}
-
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index 3447ff7c385..ec44f47b6d5 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -52,15 +52,16 @@
#include "cc/trees/swap_promise_manager.h"
#include "cc/trees/target_property.h"
#include "cc/trees/viewport_layers.h"
-#include "components/viz/common/delegated_ink_metadata.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "ui/gfx/delegated_ink_metadata.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/overlay_transform.h"
namespace gfx {
struct PresentationFeedback;
+class RenderingPipeline;
}
namespace cc {
@@ -114,6 +115,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner;
MutatorHost* mutator_host = nullptr;
RasterDarkModeFilter* dark_mode_filter = nullptr;
+ gfx::RenderingPipeline* main_thread_pipeline = nullptr;
+ gfx::RenderingPipeline* compositor_thread_pipeline = nullptr;
// The image worker task runner is used to schedule image decodes. The
// compositor thread may make sync calls to this thread, analogous to the
@@ -424,6 +427,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
gfx::Rect device_viewport_rect() const { return device_viewport_rect_; }
+ void UpdateViewportIsMobileOptimized(bool is_viewport_mobile_optimized);
+
void SetBrowserControlsParams(const BrowserControlsParams& params);
void SetBrowserControlsShownRatio(float top_ratio, float bottom_ratio);
@@ -627,6 +632,11 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time,
ActiveFrameSequenceTrackers trackers);
void NotifyThroughputTrackerResults(CustomTrackerResults results);
+ void NotifyTransitionRequestsFinished(
+ const std::vector<uint32_t>& sequence_ids);
+ // Called during impl side initialization.
+ gfx::RenderingPipeline* TakeMainPipeline();
+ gfx::RenderingPipeline* TakeCompositorPipeline();
LayerTreeHostClient* client() { return client_; }
LayerTreeHostSchedulingClient* scheduling_client() {
@@ -727,8 +737,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
}
void SetDelegatedInkMetadata(
- std::unique_ptr<viz::DelegatedInkMetadata> metadata);
- viz::DelegatedInkMetadata* DelegatedInkMetadataForTesting() {
+ std::unique_ptr<gfx::DelegatedInkMetadata> metadata);
+ gfx::DelegatedInkMetadata* DelegatedInkMetadataForTesting() {
return delegated_ink_metadata_.get();
}
@@ -839,7 +849,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// destroyed midway which causes a crash. crbug.com/654672
bool inside_main_frame_ = false;
+ // State cached until impl side is initialized.
TaskGraphRunner* task_graph_runner_;
+ gfx::RenderingPipeline* main_thread_pipeline_;
+ gfx::RenderingPipeline* compositor_thread_pipeline_;
uint32_t num_consecutive_frames_without_slow_paths_ = 0;
@@ -882,6 +895,12 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
gfx::Rect visual_device_viewport_intersection_rect_;
gfx::Size visual_device_viewport_size_;
+ // Set to true if viewport is mobile optimized by using meta tag
+ // <meta name="viewport" content="width=device-width">
+ // or
+ // <meta name="viewport" content="initial-scale=1.0">
+ bool is_viewport_mobile_optimized_ = false;
+
bool have_scroll_event_handlers_ = false;
EventListenerProperties event_listener_properties_
[static_cast<size_t>(EventListenerClass::kLast) + 1];
@@ -963,17 +982,15 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// stroke. std::unique_ptr was specifically chosen so that it would be cleared
// as it is forwarded along the pipeline to avoid old information incorrectly
// sticking around and potentially being reused.
- std::unique_ptr<viz::DelegatedInkMetadata> delegated_ink_metadata_;
+ std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata_;
// A list of document transitions that need to be transported from Blink to
// Viz, as a CompositorFrameTransitionDirective.
std::vector<std::unique_ptr<DocumentTransitionRequest>>
document_transition_requests_;
- // A list of callbacks that need to be invoked in commit callback,
- // representing document transitions that have been committed to
- // LayerTreeImpl.
- std::vector<base::OnceClosure> committed_document_transition_callbacks_;
+ // A list of callbacks that need to be invoked when they are processed.
+ base::flat_map<uint32_t, base::OnceClosure> document_transition_callbacks_;
// Used to vend weak pointers to LayerTreeHost to ScopedDeferMainFrameUpdate
// objects.
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index 2c3b6b3a2a8..94c8f648d1b 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -10,6 +10,8 @@
#include <algorithm>
#include <limits>
#include <list>
+#include <map>
+#include <memory>
#include <string>
#include "base/auto_reset.h"
@@ -20,6 +22,7 @@
#include "base/containers/flat_map.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
+#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -172,7 +175,10 @@ bool HasMobileViewport(LayerTreeImpl* active_tree) {
bool IsMobileOptimized(LayerTreeImpl* active_tree) {
bool has_mobile_viewport = HasMobileViewport(active_tree);
bool has_fixed_page_scale = HasFixedPageScale(active_tree);
- return has_fixed_page_scale || has_mobile_viewport;
+ return has_fixed_page_scale || has_mobile_viewport ||
+ (base::FeatureList::IsEnabled(
+ ::features::kRemoveMobileViewportDoubleTap) &&
+ active_tree->viewport_mobile_optimized());
}
viz::ResourceFormat TileRasterBufferFormat(
@@ -1172,12 +1178,14 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
size_t surface_index = render_surface_list_size - 1 - i;
RenderSurfaceImpl* render_surface =
(*frame->render_surface_list)[surface_index];
+ const auto& shared_element_id =
+ render_surface->GetDocumentTransitionSharedElementId();
bool is_root_surface =
render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
bool should_draw_into_render_pass =
is_root_surface || render_surface->contributes_to_drawn_surface() ||
- render_surface->CopyOfOutputRequired();
+ render_surface->CopyOfOutputRequired() || shared_element_id.valid();
if (should_draw_into_render_pass)
frame->render_passes.push_back(render_surface->CreateRenderPass());
}
@@ -2031,6 +2039,8 @@ void LayerTreeHostImpl::DidReceiveCompositorFrameAck() {
void LayerTreeHostImpl::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) {
+ devtools_instrumentation::DidPresentFrame(
+ id_, frame_token, details.presentation_feedback.timestamp);
PresentationTimeCallbackBuffer::PendingCallbacks activated_callbacks =
presentation_time_callbacks_.PopPendingCallbacks(frame_token);
@@ -2157,6 +2167,12 @@ void LayerTreeHostImpl::OnDraw(const gfx::Transform& transform,
}
}
+void LayerTreeHostImpl::OnCompositorFrameTransitionDirectiveProcessed(
+ uint32_t sequence_id) {
+ finished_transition_request_sequence_ids_.push_back(sequence_id);
+ SetNeedsCommit();
+}
+
void LayerTreeHostImpl::OnCanDrawStateChangedForTree() {
client_->OnCanDrawStateChanged(CanDraw());
}
@@ -2210,7 +2226,7 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
metadata.display_transform_hint = active_tree_->display_transform_hint();
- if (std::unique_ptr<viz::DelegatedInkMetadata> delegated_ink_metadata =
+ if (std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata =
active_tree_->take_delegated_ink_metadata()) {
delegated_ink_metadata->set_frame_time(CurrentBeginFrameArgs().frame_time);
TRACE_EVENT_INSTANT1(
@@ -2219,10 +2235,6 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
delegated_ink_metadata->ToString());
metadata.delegated_ink_metadata = std::move(delegated_ink_metadata);
}
-
- for (auto& request : active_tree_->TakeDocumentTransitionRequests())
- metadata.transition_directives.push_back(request->ConstructDirective());
-
return metadata;
}
@@ -2415,7 +2427,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
active_tree_->ResetAllChangeTracking();
active_tree_->set_has_ever_been_drawn(true);
- devtools_instrumentation::DidDrawFrame(id_);
+ devtools_instrumentation::DidDrawFrame(id_, frame_token);
benchmark_instrumentation::IssueImplThreadRenderingStatsEvent(
rendering_stats_instrumentation_->TakeImplThreadRenderingStats());
@@ -2483,6 +2495,25 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
}
viz::CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
+
+ std::map<DocumentTransitionSharedElementId, viz::CompositorRenderPassId>
+ shared_element_render_pass_id_map;
+ for (RenderSurfaceImpl* render_surface : *frame->render_surface_list) {
+ const auto& shared_element_id =
+ render_surface->GetDocumentTransitionSharedElementId();
+ if (!shared_element_id.valid())
+ continue;
+ DCHECK(
+ !base::Contains(shared_element_render_pass_id_map, shared_element_id));
+ shared_element_render_pass_id_map[shared_element_id] =
+ render_surface->render_pass_id();
+ }
+
+ for (auto& request : active_tree_->TakeDocumentTransitionRequests()) {
+ metadata.transition_directives.push_back(
+ request->ConstructDirective(shared_element_render_pass_id_map));
+ }
+
PopulateMetadataContentColorUsage(frame, &metadata);
metadata.may_contain_video = frame->may_contain_video;
metadata.deadline = viz::FrameDeadline(
@@ -2497,6 +2528,8 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
if (enable_frame_rate_throttling_) {
metadata.preferred_frame_interval = viz::BeginFrameArgs::MaxInterval();
} else if (mutator_host_->MainThreadAnimationsCount() == 0 &&
+ mutator_host_->NeedsTickAnimations() &&
+ !frame_rate_estimator_.input_priority_mode() &&
mutator_host_->MinimumTickInterval() > kMinDelta) {
// All animations are impl-thread animations that tick at no more than
// half the default display compositing fps.
@@ -2512,7 +2545,8 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
// to general webpages.
metadata.preferred_frame_interval = kTwiceOfDefaultInterval;
} else {
- // There are main-thread or high frequency impl-thread animations.
+ // There are main-thread, high frequency impl-thread animations, or input
+ // events.
frame_rate_estimator_.WillDraw(CurrentBeginFrameArgs().frame_time);
metadata.preferred_frame_interval =
frame_rate_estimator_.GetPreferredInterval();
@@ -2525,7 +2559,7 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
if (render_frame_metadata_observer_) {
last_draw_render_frame_metadata_ = MakeRenderFrameMetadata(frame);
- if (viz::DelegatedInkMetadata* ink_metadata =
+ if (gfx::DelegatedInkMetadata* ink_metadata =
metadata.delegated_ink_metadata.get()) {
last_draw_render_frame_metadata_->delegated_ink_metadata =
DelegatedInkBrowserMetadata(ink_metadata->is_hovering());
@@ -3434,8 +3468,8 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
TaskGraphRunner* task_graph_runner = task_graph_runner_;
if (is_synchronous_single_threaded_) {
DCHECK(!single_thread_synchronous_task_graph_runner_);
- single_thread_synchronous_task_graph_runner_.reset(
- new SynchronousTaskGraphRunner);
+ single_thread_synchronous_task_graph_runner_ =
+ std::make_unique<SynchronousTaskGraphRunner>();
task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
}
@@ -3548,6 +3582,13 @@ std::unique_ptr<MutatorEvents> LayerTreeHostImpl::TakeMutatorEvents() {
return events;
}
+std::vector<uint32_t>
+LayerTreeHostImpl::TakeFinishedTransitionRequestSequenceIds() {
+ std::vector<uint32_t> result;
+ result.swap(finished_transition_request_sequence_ids_);
+ return result;
+}
+
void LayerTreeHostImpl::ClearCaches() {
// It is safe to clear the decode policy tracking on navigations since it
// comes with an invalidation and the image ids are never re-used.
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index d62e352010b..3490d866cf5 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -395,6 +395,14 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// compositors. This is specified in device viewport coordinate space.
void SetVisualDeviceViewportSize(const gfx::Size&);
+ void set_viewport_mobile_optimized(bool viewport_mobile_optimized) {
+ is_viewport_mobile_optimized_ = viewport_mobile_optimized;
+ }
+
+ bool viewport_mobile_optimized() const {
+ return is_viewport_mobile_optimized_;
+ }
+
// Updates registered ElementIds present in |changed_list|. Call this after
// changing the property trees for the |changed_list| trees.
void UpdateElements(ElementListType changed_list);
@@ -549,6 +557,8 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
const gfx::Rect& viewport,
bool resourceless_software_draw,
bool skip_draw) override;
+ void OnCompositorFrameTransitionDirectiveProcessed(
+ uint32_t sequence_id) override;
// Called from LayerTreeImpl.
void OnCanDrawStateChangedForTree();
@@ -781,6 +791,9 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// Returns mutator events to be handled by BeginMainFrame.
std::unique_ptr<MutatorEvents> TakeMutatorEvents();
+ // Returns all of the transition request sequence ids that were finished.
+ std::vector<uint32_t> TakeFinishedTransitionRequestSequenceIds();
+
void ClearCaches();
void UpdateImageDecodingHints(
@@ -1138,6 +1151,11 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
std::unique_ptr<Viewport> viewport_;
gfx::Size visual_device_viewport_size_;
+ // Set to true if viewport is mobile optimized by using meta tag
+ // <meta name="viewport" content="width=device-width">
+ // or
+ // <meta name="viewport" content="initial-scale=1.0">
+ bool is_viewport_mobile_optimized_ = false;
std::unique_ptr<PendingTreeRasterDurationHistogramTimer>
pending_tree_raster_duration_timer_;
@@ -1239,6 +1257,8 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// some pre-defined criteria.
ThrottleDecider throttle_decider_;
+ std::vector<uint32_t> finished_transition_request_sequence_ids_;
+
// Must be the last member to ensure this is destroyed first in the
// destruction order and invalidates all weak pointers.
base::WeakPtrFactory<LayerTreeHostImpl> weak_factory_{this};
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index 3c78b9ea2eb..f695ad3a05c 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include <cmath>
+#include <memory>
#include <utility>
#include "base/base_switches.h"
@@ -108,12 +109,12 @@
statements; \
}
-using ::testing::Mock;
-using ::testing::Return;
+using media::VideoFrame;
+using ::testing::_;
using ::testing::AnyNumber;
using ::testing::AtLeast;
-using ::testing::_;
-using media::VideoFrame;
+using ::testing::Mock;
+using ::testing::Return;
using ScrollThread = cc::InputHandler::ScrollThread;
@@ -4479,9 +4480,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PageScaleAnimation) {
did_request_redraw_ = false;
did_request_next_frame_ = false;
host_impl_->active_tree()->SetPendingPageScaleAnimation(
- std::unique_ptr<PendingPageScaleAnimation>(
- new PendingPageScaleAnimation(gfx::Vector2d(), false, 2,
- duration)));
+ std::make_unique<PendingPageScaleAnimation>(gfx::Vector2d(), false, 2,
+ duration));
host_impl_->ActivateSyncTree();
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(did_request_next_frame_);
@@ -4540,9 +4540,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PageScaleAnimation) {
did_request_redraw_ = false;
did_request_next_frame_ = false;
host_impl_->active_tree()->SetPendingPageScaleAnimation(
- std::unique_ptr<PendingPageScaleAnimation>(
- new PendingPageScaleAnimation(gfx::Vector2d(25, 25), true,
- min_page_scale, duration)));
+ std::make_unique<PendingPageScaleAnimation>(gfx::Vector2d(25, 25), true,
+ min_page_scale, duration));
host_impl_->ActivateSyncTree();
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(did_request_next_frame_);
@@ -4606,8 +4605,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PageScaleAnimationNoOp) {
scroll_layer->element_id(), gfx::ScrollOffset(50, 50));
host_impl_->active_tree()->SetPendingPageScaleAnimation(
- std::unique_ptr<PendingPageScaleAnimation>(
- new PendingPageScaleAnimation(gfx::Vector2d(), true, 1, duration)));
+ std::make_unique<PendingPageScaleAnimation>(gfx::Vector2d(), true, 1,
+ duration));
host_impl_->ActivateSyncTree();
begin_frame_args.frame_time = start_time;
begin_frame_args.frame_id.sequence_number++;
@@ -4673,8 +4672,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
// Make sure TakePageScaleAnimation works properly.
host_impl_->sync_tree()->SetPendingPageScaleAnimation(
- std::unique_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
- gfx::Vector2d(), false, target_scale, duration)));
+ std::make_unique<PendingPageScaleAnimation>(gfx::Vector2d(), false,
+ target_scale, duration));
std::unique_ptr<PendingPageScaleAnimation> psa =
host_impl_->sync_tree()->TakePendingPageScaleAnimation();
EXPECT_EQ(target_scale, psa->scale);
@@ -4686,8 +4685,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
did_request_redraw_ = false;
did_request_next_frame_ = false;
host_impl_->sync_tree()->SetPendingPageScaleAnimation(
- std::unique_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
- gfx::Vector2d(), false, target_scale, duration)));
+ std::make_unique<PendingPageScaleAnimation>(gfx::Vector2d(), false,
+ target_scale, duration));
begin_frame_args.frame_time = halfway_through_animation;
begin_frame_args.frame_id.sequence_number++;
host_impl_->WillBeginImplFrame(begin_frame_args);
@@ -4786,8 +4785,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
did_complete_page_scale_animation_ = false;
host_impl_->active_tree()->SetPendingPageScaleAnimation(
- std::unique_ptr<PendingPageScaleAnimation>(
- new PendingPageScaleAnimation(gfx::Vector2d(), false, 2, duration)));
+ std::make_unique<PendingPageScaleAnimation>(gfx::Vector2d(), false, 2,
+ duration));
host_impl_->ActivateSyncTree();
begin_frame_args.frame_time = start_time;
begin_frame_args.frame_id.sequence_number++;
@@ -4847,14 +4846,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
gfx::Point position(295, 195);
gfx::Vector2dF offset(0, 50);
-// TODO(bokan): Unfortunately, Mac currently doesn't support smooth scrolling
-// wheel events. https://crbug.com/574283.
-#if defined(OS_MAC)
- std::vector<ui::ScrollInputType> types = {ui::ScrollInputType::kScrollbar};
-#else
std::vector<ui::ScrollInputType> types = {ui::ScrollInputType::kScrollbar,
ui::ScrollInputType::kWheel};
-#endif
for (auto type : types) {
auto begin_state = BeginState(position, offset, type);
begin_state->data()->set_current_native_scrolling_element(
@@ -13142,32 +13135,6 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1, 1));
}
-#if defined(OS_MAC)
-// Ensure Mac wheel scrolling causes instant scrolling. This test can be removed
-// once https://crbug.com/574283 is fixed.
-TEST_P(ScrollUnifiedLayerTreeHostImplTest, MacWheelIsNonAnimated) {
- const gfx::Size content_size(1000, 1000);
- const gfx::Size viewport_size(50, 100);
- SetupViewportLayersOuterScrolls(viewport_size, content_size);
- LayerImpl* scrolling_layer = OuterViewportScrollLayer();
-
- host_impl_->set_force_smooth_wheel_scrolling_for_testing(false);
- ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
- GetInputHandler()
- .ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 50),
- ui::ScrollInputType::kWheel)
- .get(),
- ui::ScrollInputType::kWheel)
- .thread);
- GetInputHandler().ScrollUpdate(
- AnimatedUpdateState(gfx::Point(), gfx::Vector2d(0, 50)).get());
-
- // Ensure the scroll update happens immediately.
- EXPECT_EQ(CurrentScrollOffset(scrolling_layer).y(), 50);
- GetInputHandler().ScrollEnd();
-}
-#endif
-
TEST_P(ScrollUnifiedLayerTreeHostImplTest, OneScrollForFirstScrollDelay) {
LayerTreeSettings settings = DefaultSettings();
settings.commit_to_active_tree = false;
@@ -18270,7 +18237,8 @@ TEST_F(LayerTreeHostImplTest, DocumentTransitionRequestCausesDamage) {
// Adding a transition effect should cause us to redraw.
host_impl_->active_tree()->AddDocumentTransitionRequest(
- DocumentTransitionRequest::CreateStart(base::OnceClosure()));
+ DocumentTransitionRequest::CreateStart(
+ /*document_tag=*/0, /*shared_element_count=*/0, base::OnceClosure()));
// Ensure there is damage and we requested a redraw.
host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index d0a756797cf..68f86cbdd79 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -4,6 +4,8 @@
#include <stddef.h>
+#include <memory>
+
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
@@ -77,6 +79,9 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LayerTreeHostFiltersPixelTest);
+
using LayerTreeHostFiltersPixelTestGPU = LayerTreeHostFiltersPixelTest;
INSTANTIATE_TEST_SUITE_P(All,
@@ -84,6 +89,9 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetGpuRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetGpuRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LayerTreeHostFiltersPixelTestGPU);
+
TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRect) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -223,11 +231,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) {
1.01f * percentage_pixels_small_error;
// Divide average error by 4 since we blur most of the result.
float average_error_allowed_in_bad_pixels = small_error_threshold / 4.f;
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
true, // discard_alpha
percentage_pixels_large_or_small_error, percentage_pixels_small_error,
average_error_allowed_in_bad_pixels, large_error_limit,
- small_error_threshold));
+ small_error_threshold);
RunPixelTest(background, use_software_renderer()
? base::FilePath(FILE_PATH_LITERAL(
@@ -360,6 +368,10 @@ INSTANTIATE_TEST_SUITE_P(PixelResourceTest,
::testing::ValuesIn(viz::GetGpuRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetGpuRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostBlurFiltersPixelTestGPULayerList);
+
// TODO(michaelludwig): Re-enable after Skia roll and update expected images.
// See skbug.com/9545
TEST_P(LayerTreeHostBlurFiltersPixelTestGPULayerList,
@@ -466,6 +478,10 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostFiltersScaledPixelTest);
+
TEST_P(LayerTreeHostFiltersScaledPixelTest, StandardDpi) {
RunPixelTestType(100, 1.f);
}
@@ -575,7 +591,8 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) {
filter->SetBackdropFilters(filters);
filter->ClearBackdropFilterBounds();
-#if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64)
+#if defined(OS_WIN) || defined(OS_MAC) || defined(_MIPS_ARCH_LOONGSON) || \
+ defined(ARCH_CPU_ARM64)
#if defined(OS_WIN)
// Windows has 153 pixels off by at most 2: crbug.com/225027
float percentage_pixels_large_error = 0.3825f; // 153px / (200*200)
@@ -585,6 +602,10 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) {
percentage_pixels_large_error = 0.415f; // 166px / (200*200)
large_error_allowed = 1;
}
+#elif defined(OS_MAC)
+ // There's a 1 pixel error on MacOS
+ float percentage_pixels_large_error = 0.0025f; // 1px / (200*200)
+ int large_error_allowed = 1;
#elif defined(_MIPS_ARCH_LOONGSON)
// Loongson has 2 pixels off by at most 2: crbug.com/819075
float percentage_pixels_large_error = 0.005f; // 2px / (200*200)
@@ -596,11 +617,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) {
float percentage_pixels_small_error = 0.0f;
float average_error_allowed_in_bad_pixels = 1.f;
int small_error_allowed = 0;
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
true, // discard_alpha
percentage_pixels_large_error, percentage_pixels_small_error,
average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed));
+ small_error_allowed);
#endif
RunPixelTest(
@@ -657,11 +678,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterRotated) {
float average_error_allowed_in_bad_pixels = 2.f;
int large_error_allowed = 2;
int small_error_allowed = 0;
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
true, // discard_alpha
percentage_pixels_large_error, percentage_pixels_small_error,
average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed));
+ small_error_allowed);
RunPixelTest(background,
base::FilePath(FILE_PATH_LITERAL("backdrop_filter_rotated_.png"))
@@ -715,10 +736,10 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageRenderSurfaceScaled) {
average_error_allowed_in_bad_pixels = 1.f;
large_error_allowed = 1;
}
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
/*discard_alpha=*/true, percentage_pixels_large_error,
percentage_pixels_small_error, average_error_allowed_in_bad_pixels,
- large_error_allowed, small_error_allowed));
+ large_error_allowed, small_error_allowed);
RunPixelTest(
background,
@@ -843,11 +864,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedFilter) {
#endif
float percentage_pixels_small_error = 0.0f;
int small_error_allowed = 0;
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
true, // discard_alpha
percentage_pixels_large_error, percentage_pixels_small_error,
average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed));
+ small_error_allowed);
#endif
RunPixelTest(background,
@@ -882,7 +903,8 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
background->AddChild(child);
-#if defined(OS_WIN) || defined(ARCH_CPU_ARM64)
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_CHROMEOS) || \
+ defined(ARCH_CPU_ARM64) || defined(USE_OZONE)
#if defined(ARCH_CPU_ARM64) && \
(defined(OS_WIN) || defined(OS_FUCHSIA) || defined(OS_MAC))
// Windows, macOS, and Fuchsia on ARM64 has some pixels difference.
@@ -890,6 +912,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
float percentage_pixels_large_error = 0.89f;
float average_error_allowed_in_bad_pixels = 5.f;
int large_error_allowed = 17;
+#elif defined(OS_MAC) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+ // There's a 1 pixel error on MacOS and ChromeOS
+ float percentage_pixels_large_error = 0.00111112f; // 1px / (300*300)
+ float average_error_allowed_in_bad_pixels = 1.f;
+ int large_error_allowed = 1;
#else
// Windows and all other ARM64 have 3 pixels off by 1: crbug.com/259915
float percentage_pixels_large_error = 0.00333334f; // 3px / (300*300)
@@ -901,11 +928,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
#endif
float percentage_pixels_small_error = 0.0f;
int small_error_allowed = 0;
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
true, // discard_alpha
percentage_pixels_large_error, percentage_pixels_small_error,
average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed));
+ small_error_allowed);
#else
if (use_skia_vulkan())
pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
@@ -1158,6 +1185,9 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BackdropFilterOffsetTest);
+
TEST_P(BackdropFilterOffsetTest, StandardDpi) {
RunPixelTestType(1.f);
}
@@ -1194,11 +1224,11 @@ class BackdropFilterInvertTest : public LayerTreeHostFiltersPixelTest {
int large_error_allowed = 1;
float percentage_pixels_small_error = 0.0f;
int small_error_allowed = 0;
- pixel_comparator_.reset(new FuzzyPixelComparator(
+ pixel_comparator_ = std::make_unique<FuzzyPixelComparator>(
true, // discard_alpha
percentage_pixels_large_error, percentage_pixels_small_error,
average_error_allowed_in_bad_pixels, large_error_allowed,
- small_error_allowed));
+ small_error_allowed);
}
RunPixelTest(std::move(root), expected_result);
}
@@ -1218,6 +1248,9 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BackdropFilterInvertTest);
+
TEST_P(BackdropFilterInvertTest, StandardDpi) {
RunPixelTestType(1.f);
}
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
index ea957180edb..4a7504c5a5b 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -105,7 +105,9 @@ class LayerTreeHostReadbackPixelTest
void ReadbackResultAsBitmap(std::unique_ptr<viz::CopyOutputResult> result) {
EXPECT_TRUE(task_runner_provider()->IsMainThread());
EXPECT_FALSE(result->IsEmpty());
- result_bitmap_ = std::make_unique<SkBitmap>(result->AsSkBitmap());
+ auto scoped_sk_bitmap = result->ScopedAccessSkBitmap();
+ result_bitmap_ =
+ std::make_unique<SkBitmap>(scoped_sk_bitmap.GetOutScopedBitmap());
EXPECT_TRUE(result_bitmap_->readyToDraw());
EndTest();
}
@@ -121,12 +123,12 @@ class LayerTreeHostReadbackPixelTest
std::unique_ptr<viz::SingleReleaseCallback> release_callback =
result->TakeTextureOwnership();
- const SkBitmap bitmap =
+ SkBitmap bitmap =
CopyMailboxToBitmap(result->size(), mailbox, sync_token, color_space);
release_callback->Run(gpu::SyncToken(), false);
ReadbackResultAsBitmap(std::make_unique<viz::CopyOutputSkBitmapResult>(
- result->rect(), bitmap));
+ result->rect(), std::move(bitmap)));
}
gfx::Rect copy_subrect_;
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index b531ed8694d..9eb9276fe56 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -78,6 +78,9 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetGpuRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetGpuRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LayerTreeHostScrollbarsPixelTest);
+
TEST_P(LayerTreeHostScrollbarsPixelTest, NoScale) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -258,6 +261,10 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetGpuRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetGpuRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostOverlayScrollbarsPixelTest);
+
// Simulate increasing the thickness of a painted overlay scrollbar. Ensure that
// the scrollbar border remains crisp.
TEST_P(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) {
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
index 266aabd3262..5e19dadb059 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
@@ -56,6 +56,10 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(viz::GetGpuRendererTypes()),
::testing::PrintToStringParamName());
+// viz::GetGpuRendererTypes() can return an empty list on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostSynchronousPixelTest);
+
TEST_P(LayerTreeHostSynchronousPixelTest, OneContentLayerZeroCopy) {
set_raster_type(TestRasterType::kZeroCopy);
DoContentLayerTest();
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
index a3f7a12b671..a10ad840469 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -284,6 +284,10 @@ INSTANTIATE_TEST_SUITE_P(All,
::testing::ValuesIn(kTestCasesMultiThread),
::testing::PrintToStringParamName());
+// kTestCasesMultiThread is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostTilesTestPartialInvalidationMultiThread);
+
#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER)
// Flaky on Linux TSAN. https://crbug.com/707711
#define MAYBE_PartialRaster DISABLED_PartialRaster
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index 79ceaf87f18..221b06ff45e 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <algorithm>
+#include <memory>
#include "base/auto_reset.h"
#include "base/bind.h"
@@ -2998,7 +2999,7 @@ class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest {
&client_, std::move(recording));
root_layer_->SetBounds(gfx::Size(50, 50));
- recording.reset(new FakeRecordingSource);
+ recording = std::make_unique<FakeRecordingSource>();
child_layer_ = FakePictureLayer::CreateWithRecordingSource(
&client_, std::move(recording));
child_layer_->SetBounds(gfx::Size(25, 25));
@@ -3047,13 +3048,13 @@ class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest {
host_impl->active_tree()->LayerById(child_layer_->id()));
// We remove tilings pretty aggressively if they are not ideal. Add this
// back in so that we can compare
- // child_layer_impl->visible_drawable_content_rect() to the damage.
+ // child_layer_impl->GetEnclosingRectInTargetSpace to the damage.
child_layer_impl->AddTilingUntilNextDraw(1.3f);
- EXPECT_EQ(gfx::Rect(25, 25), root_damage_rect);
- EXPECT_EQ(child_layer_impl->visible_drawable_content_rect(),
+ EXPECT_EQ(gfx::Rect(26, 26), root_damage_rect);
+ EXPECT_EQ(child_layer_impl->GetEnclosingRectInTargetSpace(),
root_damage_rect);
- EXPECT_TRUE(child_layer_impl->visible_drawable_content_rect().Contains(
+ EXPECT_TRUE(child_layer_impl->GetEnclosingRectInTargetSpace().Contains(
gfx::Rect(child_layer_->bounds())));
break;
}
@@ -8903,10 +8904,10 @@ class LayerTreeHostTestDelegatedInkMetadataOnAndOff
base::TimeTicks timestamp = base::TimeTicks::Now();
bool is_hovering = true;
- expected_metadata_ = viz::DelegatedInkMetadata(
+ expected_metadata_ = gfx::DelegatedInkMetadata(
point, diameter, color, timestamp, area, is_hovering);
layer_tree_host()->SetDelegatedInkMetadata(
- std::make_unique<viz::DelegatedInkMetadata>(
+ std::make_unique<gfx::DelegatedInkMetadata>(
expected_metadata_.value()));
}
@@ -8928,7 +8929,7 @@ class LayerTreeHostTestDelegatedInkMetadataOnAndOff
void ExpectMetadata(base::Optional<DelegatedInkBrowserMetadata>
browser_delegated_ink_metadata,
- viz::DelegatedInkMetadata* actual_metadata) {
+ gfx::DelegatedInkMetadata* actual_metadata) {
if (expected_metadata_.has_value()) {
EXPECT_TRUE(browser_delegated_ink_metadata.has_value());
EXPECT_TRUE(actual_metadata);
@@ -8965,7 +8966,7 @@ class LayerTreeHostTestDelegatedInkMetadataOnAndOff
}
private:
- base::Optional<viz::DelegatedInkMetadata> expected_metadata_;
+ base::Optional<gfx::DelegatedInkMetadata> expected_metadata_;
FakeContentLayerClient client_;
scoped_refptr<Layer> layer_;
bool set_needs_display_ = true;
@@ -9464,10 +9465,11 @@ class LayerTreeHostTestDocumentTransitionsPropagatedToMetadata
layer_tree_host()->AddDocumentTransitionRequest(
DocumentTransitionRequest::CreatePrepare(
DocumentTransitionRequest::Effect::kExplode,
- base::TimeDelta::FromMilliseconds(123),
+ /*document_tag=*/0, /*shared_element_count=*/0,
base::BindLambdaForTesting([this]() { CommitLambdaCalled(); })));
layer_tree_host()->AddDocumentTransitionRequest(
DocumentTransitionRequest::CreateStart(
+ /*document_tag=*/0, /*shared_element_count=*/0,
base::BindLambdaForTesting([this]() { CommitLambdaCalled(); })));
}
@@ -9477,23 +9479,29 @@ class LayerTreeHostTestDocumentTransitionsPropagatedToMetadata
const viz::CompositorFrame& frame) override {
ASSERT_EQ(2u, frame.metadata.transition_directives.size());
const auto& save = frame.metadata.transition_directives[0];
+ submitted_sequence_ids_.push_back(save.sequence_id());
EXPECT_EQ(save.type(),
viz::CompositorFrameTransitionDirective::Type::kSave);
EXPECT_EQ(save.effect(),
viz::CompositorFrameTransitionDirective::Effect::kExplode);
- EXPECT_EQ(save.duration(), base::TimeDelta::FromMilliseconds(123));
const auto& animate = frame.metadata.transition_directives[1];
EXPECT_GT(animate.sequence_id(), save.sequence_id());
EXPECT_EQ(animate.type(),
viz::CompositorFrameTransitionDirective::Type::kAnimate);
+ submitted_sequence_ids_.push_back(animate.sequence_id());
+ }
+ void DidReceiveCompositorFrameAck() override {
+ layer_tree_host()->NotifyTransitionRequestsFinished(
+ submitted_sequence_ids_);
EndTest();
}
void AfterTest() override { EXPECT_EQ(2, num_lambda_calls_); }
+ std::vector<uint32_t> submitted_sequence_ids_;
int num_lambda_calls_ = 0;
};
diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
index 4d80dbe7f76..1b528540583 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -185,7 +185,7 @@ class LayerTreeHostAnimationTestAddKeyframeModel
int group) override {
EXPECT_LT(base::TimeTicks(), monotonic_time);
- KeyframeModel* keyframe_model =
+ gfx::KeyframeModel* keyframe_model =
animation_->GetKeyframeModel(TargetProperty::OPACITY);
if (keyframe_model)
animation_->RemoveKeyframeModel(keyframe_model->id());
@@ -936,7 +936,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
GetImplTimelineAndAnimationByID(*host_impl);
// This happens after the impl-only animation is added in
// WillCommitCompleteOnThread.
- KeyframeModel* keyframe_model =
+ gfx::KeyframeModel* keyframe_model =
ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_)
.GetKeyframeModel(TargetProperty::SCROLL_OFFSET);
DCHECK(keyframe_model);
@@ -962,7 +962,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
if (host_impl->sync_tree()->source_frame_number() == 1) {
- KeyframeModel* keyframe_model =
+ gfx::KeyframeModel* keyframe_model =
ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_)
.GetKeyframeModel(TargetProperty::SCROLL_OFFSET);
DCHECK(keyframe_model);
diff --git a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
index 9801b1718cb..6c47500d499 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
@@ -20,8 +20,9 @@ const char kCheckerboardImagesMetric[] = "CheckerboardedImagesCount";
class LayerTreeHostCheckerImagingTest : public LayerTreeTest {
public:
- LayerTreeHostCheckerImagingTest() : url_(GURL("https://example.com")),
- ukm_source_id_(123) {}
+ LayerTreeHostCheckerImagingTest()
+ : url_(GURL("https://example.com")),
+ ukm_source_id_(ukm::AssignNewSourceId()) {}
void BeginTest() override {
layer_tree_host()->SetSourceURL(ukm_source_id_, url_);
@@ -36,8 +37,9 @@ class LayerTreeHostCheckerImagingTest : public LayerTreeTest {
recorder->UpdateSourceURL(ukm_source_id_, url_);
// Change the source to ensure any accumulated metrics are flushed.
- impl->ukm_manager()->SetSourceId(200);
- recorder->UpdateSourceURL(200, GURL("chrome://test2"));
+ ukm::SourceId newSourceId = ukm::AssignNewSourceId();
+ impl->ukm_manager()->SetSourceId(newSourceId);
+ recorder->UpdateSourceURL(newSourceId, GURL("chrome://test2"));
const auto& entries = recorder->GetEntriesByName(kRenderingEvent);
ASSERT_EQ(1u, entries.size());
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index d6fbf463ba1..73e69db5df9 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -158,7 +158,8 @@ class LayerTreeHostCopyRequestTestMultipleRequests
std::unique_ptr<viz::CopyOutputResult> result) {
EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread());
EXPECT_FALSE(result->IsEmpty());
- const SkBitmap& bitmap = result->AsSkBitmap();
+ auto scoped_sk_bitmap = result->ScopedAccessSkBitmap();
+ const SkBitmap& bitmap = scoped_sk_bitmap.bitmap();
EXPECT_TRUE(bitmap.readyToDraw());
EXPECT_EQ(result->size(), gfx::Size(bitmap.width(), bitmap.height()));
callbacks_[id] = result->size();
@@ -179,6 +180,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestMultipleRequests);
+
TEST_P(LayerTreeHostCopyRequestTestMultipleRequests, Test) {
RunTest(compositor_mode());
}
@@ -222,6 +227,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder);
+
TEST_P(LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder, Test) {
RunTest(compositor_mode());
}
@@ -281,6 +290,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestCompletionCausesCommit);
+
TEST_P(LayerTreeHostCopyRequestCompletionCausesCommit, Test) {
RunTest(compositor_mode());
}
@@ -388,6 +401,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestLayerDestroyed);
+
TEST_P(LayerTreeHostCopyRequestTestLayerDestroyed, Test) {
RunTest(compositor_mode());
}
@@ -494,6 +511,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestInHiddenSubtree);
+
TEST_P(LayerTreeHostCopyRequestTestInHiddenSubtree, Test) {
RunTest(compositor_mode());
}
@@ -615,6 +636,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest);
+
TEST_P(LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest, Test) {
RunTest(compositor_mode());
}
@@ -671,6 +696,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestClippedOut);
+
TEST_P(LayerTreeHostCopyRequestTestClippedOut, Test) {
RunTest(compositor_mode());
}
@@ -731,6 +760,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestScaledLayer);
+
TEST_P(LayerTreeHostCopyRequestTestScaledLayer, Test) {
RunTest(compositor_mode());
}
@@ -825,6 +858,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
+
TEST_P(LayerTreeHostTestAsyncTwoReadbacksWithoutDraw, Test) {
RunTest(compositor_mode());
}
@@ -975,6 +1012,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestDeleteSharedImage);
+
TEST_P(LayerTreeHostCopyRequestTestDeleteSharedImage, Test) {
RunTest(compositor_mode());
}
@@ -1125,6 +1166,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestCreatesSharedImage);
+
TEST_P(LayerTreeHostCopyRequestTestCreatesSharedImage, Test) {
RunTest(compositor_mode());
}
@@ -1213,6 +1258,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestDestroyBeforeCopy);
+
TEST_P(LayerTreeHostCopyRequestTestDestroyBeforeCopy, Test) {
RunTest(compositor_mode());
}
@@ -1296,6 +1345,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestShutdownBeforeCopy);
+
TEST_P(LayerTreeHostCopyRequestTestShutdownBeforeCopy, Test) {
RunTest(compositor_mode());
}
@@ -1428,6 +1481,10 @@ INSTANTIATE_TEST_SUITE_P(
CombineWithCompositorModes(viz::GetGpuRendererTypesNoDawn()),
PrintTupleToStringParamName());
+// viz::GetGpuRendererTypesNoDawn() is empty on some platforms.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest);
+
TEST_P(LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest, Test) {
RunTest(compositor_mode());
}
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index 1aa61b98e70..16dc43ba245 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -541,7 +541,7 @@ class LayerTreeHostScrollTestScrollSnapping : public LayerTreeHostScrollTest {
PostSetNeedsCommitToMainThread();
break;
case 2:
- translate.Translate(-3, 0);
+ translate.Translate(-4, 0);
EXPECT_EQ(translate,
scroll_layer->draw_properties().screen_space_transform);
EndTest();
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index 1ac475f2afe..171f018b5c9 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -1491,7 +1491,7 @@ LayerImpl* LayerTreeImpl::LayerById(int id) const {
return iter != layer_id_map_.end() ? iter->second : nullptr;
}
-// TODO(masonfreed): If this shows up on profiles, this could use
+// TODO(masonf): If this shows up on profiles, this could use
// a layer_element_map_ approach similar to LayerById().
LayerImpl* LayerTreeImpl::LayerByElementId(ElementId element_id) const {
auto it =
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index ec13bafda99..6d8a6ce426a 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -735,10 +735,10 @@ class CC_EXPORT LayerTreeImpl {
// only be called after the JS API |updateInkTrailStartPoint| has been
// called, which populates the metadata with provided information.
void set_delegated_ink_metadata(
- std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
+ std::unique_ptr<gfx::DelegatedInkMetadata> metadata) {
delegated_ink_metadata_ = std::move(metadata);
}
- std::unique_ptr<viz::DelegatedInkMetadata> take_delegated_ink_metadata() {
+ std::unique_ptr<gfx::DelegatedInkMetadata> take_delegated_ink_metadata() {
return std::move(delegated_ink_metadata_);
}
@@ -750,6 +750,10 @@ class CC_EXPORT LayerTreeImpl {
return device_viewport_rect_changed_;
}
+ bool viewport_mobile_optimized() const {
+ return host_impl_->viewport_mobile_optimized();
+ }
+
// Add a document transition request from the embedder.
void AddDocumentTransitionRequest(
std::unique_ptr<DocumentTransitionRequest> request);
@@ -914,7 +918,7 @@ class CC_EXPORT LayerTreeImpl {
// Event metrics that are reported back from the main thread.
EventMetrics::List events_metrics_from_main_thread_;
- std::unique_ptr<viz::DelegatedInkMetadata> delegated_ink_metadata_;
+ std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata_;
// Document transition requests to be transferred to Viz.
std::vector<std::unique_ptr<DocumentTransitionRequest>>
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index 8bc3982468a..541f361a773 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -1534,10 +1534,7 @@ void ScrollTree::CollectScrollDeltas(
}
}
-void ScrollTree::CollectScrollDeltasForTesting() {
- LayerTreeSettings settings;
- bool use_fractional_deltas = settings.commit_fractional_scroll_deltas;
-
+void ScrollTree::CollectScrollDeltasForTesting(bool use_fractional_deltas) {
for (auto map_entry : synced_scroll_offset_map_) {
PullDeltaForMainThread(map_entry.second.get(), use_fractional_deltas);
}
@@ -1545,7 +1542,8 @@ void ScrollTree::CollectScrollDeltasForTesting() {
void ScrollTree::PushScrollUpdatesFromMainThread(
PropertyTrees* main_property_trees,
- LayerTreeImpl* sync_tree) {
+ LayerTreeImpl* sync_tree,
+ bool use_fractional_deltas) {
DCHECK(!property_trees()->is_main_thread);
const ScrollOffsetMap& main_scroll_offset_map =
main_property_trees->scroll_tree.scroll_offset_map_;
@@ -1571,6 +1569,16 @@ void ScrollTree::PushScrollUpdatesFromMainThread(
// committed PropertyTrees.
bool needs_scroll_update =
synced_scroll_offset->PushMainToPending(map_entry.second);
+ // If `use_fractional_deltas` is false, then check against the rounded
+ // pending offset instead of the offset directly. This matches
+ // PullDeltaForMainThread where only an integer delta is extracted and
+ // prevents unnecessary property change in this case.
+ if (!use_fractional_deltas) {
+ gfx::ScrollOffset pending_offset = synced_scroll_offset->Current(false);
+ gfx::ScrollOffset rounded_offset = gfx::ScrollOffset(
+ roundf(pending_offset.x()), roundf(pending_offset.y()));
+ needs_scroll_update = map_entry.second != rounded_offset;
+ }
// If we are committing directly to the active tree, push pending to active
// here. If the value differs between the pending and active trees, we need
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index 2bb36062737..b9ebbce70f0 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -461,7 +461,8 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
// Pushes scroll updates from the ScrollTree on the main thread onto the
// impl thread associated state.
void PushScrollUpdatesFromMainThread(PropertyTrees* main_property_trees,
- LayerTreeImpl* sync_tree);
+ LayerTreeImpl* sync_tree,
+ bool use_fractional_deltas);
// Pushes scroll updates from the ScrollTree on the pending tree onto the
// active tree associated state.
@@ -481,7 +482,7 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
const gfx::Vector2dF& delta);
const gfx::ScrollOffset GetScrollOffsetBaseForTesting(ElementId id) const;
const gfx::ScrollOffset GetScrollOffsetDeltaForTesting(ElementId id) const;
- void CollectScrollDeltasForTesting();
+ void CollectScrollDeltasForTesting(bool use_fractional_deltas = false);
gfx::Vector2dF ScrollBy(const ScrollNode& scroll_node,
const gfx::Vector2dF& scroll,
diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc
index 489ece12ea2..0bd9e1bd1a5 100644
--- a/chromium/cc/trees/property_tree_unittest.cc
+++ b/chromium/cc/trees/property_tree_unittest.cc
@@ -7,10 +7,14 @@
#include <utility>
#include "cc/input/main_thread_scrolling_reason.h"
+#include "cc/test/fake_impl_task_runner_provider.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
+#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
@@ -629,5 +633,70 @@ TEST(ScrollTreeTest, GetPixelSnappedScrollOffsetNegativeOffset) {
EXPECT_EQ(offset.y(), 0);
}
+// Verify that when fractional scroll delta is turned off, that the remaining
+// fractional delta does not cause additional property changes.
+TEST(ScrollTreeTest, PushScrollUpdatesFromMainThreadIntegerDelta) {
+ const bool use_fractional_deltas = false;
+
+ // Set up main property trees.
+ PropertyTrees property_trees;
+ ScrollTree& main_scroll_tree = property_trees.scroll_tree;
+ TransformTree& transform_tree = property_trees.transform_tree;
+ ElementId element_id(5);
+ int transform_node_id = transform_tree.Insert(TransformNode(), 0);
+ int scroll_node_id = main_scroll_tree.Insert(ScrollNode(), 0);
+ main_scroll_tree.Node(scroll_node_id)->transform_id = transform_node_id;
+ main_scroll_tree.Node(scroll_node_id)->element_id = element_id;
+
+ // Set up FakeLayerTreeHostImpl.
+ TestTaskGraphRunner task_graph_runner;
+ FakeImplTaskRunnerProvider impl_task_runner_provider;
+ FakeLayerTreeHostImpl host_impl(
+ LayerTreeSettings(), &impl_task_runner_provider, &task_graph_runner);
+ host_impl.CreatePendingTree();
+
+ // Set up pending property trees.
+ PropertyTrees* pending_property_trees =
+ host_impl.pending_tree()->property_trees();
+ EXPECT_TRUE(pending_property_trees);
+ ScrollTree& pending_scroll_tree = pending_property_trees->scroll_tree;
+ TransformTree& pending_transform_tree =
+ pending_property_trees->transform_tree;
+ transform_node_id = pending_transform_tree.Insert(TransformNode(), 0);
+ scroll_node_id = pending_scroll_tree.Insert(ScrollNode(), 0);
+ pending_scroll_tree.Node(scroll_node_id)->transform_id = transform_node_id;
+ pending_scroll_tree.Node(scroll_node_id)->element_id = element_id;
+ pending_property_trees->element_id_to_scroll_node_index[element_id] =
+ scroll_node_id;
+
+ // Push main scroll to pending.
+ main_scroll_tree.SetScrollOffset(element_id, gfx::ScrollOffset(0, 1));
+ pending_scroll_tree.PushScrollUpdatesFromMainThread(
+ &property_trees, host_impl.pending_tree(), use_fractional_deltas);
+ const SyncedScrollOffset* scroll_offset =
+ pending_scroll_tree.GetSyncedScrollOffset(element_id);
+ EXPECT_TRUE(scroll_offset);
+
+ // Set a fractional delta and check it is not pulled with fractional delta
+ // turned off.
+ pending_scroll_tree.SetScrollOffsetDeltaForTesting(element_id,
+ gfx::Vector2dF(0, 0.25));
+ main_scroll_tree.CollectScrollDeltasForTesting(use_fractional_deltas);
+ EXPECT_EQ(gfx::ScrollOffset(0, 1),
+ main_scroll_tree.current_scroll_offset(element_id));
+
+ // Rounding logic turned on should not cause property change on push.
+ host_impl.pending_tree()->property_trees()->changed = false;
+ pending_scroll_tree.PushScrollUpdatesFromMainThread(
+ &property_trees, host_impl.pending_tree(), use_fractional_deltas);
+ EXPECT_FALSE(host_impl.pending_tree()->property_trees()->changed);
+
+ // Rounding logic turned off should cause property change on push.
+ host_impl.pending_tree()->property_trees()->changed = false;
+ pending_scroll_tree.PushScrollUpdatesFromMainThread(
+ &property_trees, host_impl.pending_tree(), true);
+ EXPECT_TRUE(host_impl.pending_tree()->property_trees()->changed);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/proxy_common.h b/chromium/cc/trees/proxy_common.h
index 51666ea720c..79c8a4bd243 100644
--- a/chromium/cc/trees/proxy_common.h
+++ b/chromium/cc/trees/proxy_common.h
@@ -32,6 +32,7 @@ struct CC_EXPORT BeginMainFrameAndCommitState {
// Bit encoding of the FrameSequenceTrackerType for active trackers
ActiveFrameSequenceTrackers active_sequence_trackers = 0;
bool evicted_ui_resources = false;
+ std::vector<uint32_t> finished_transition_request_sequence_ids;
};
} // namespace cc
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index a67c14b6b64..d9d417b439a 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -7,6 +7,7 @@
#include <string.h>
#include <algorithm>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -90,9 +91,11 @@ ProxyImpl::ProxyImpl(base::WeakPtr<ProxyMain> proxy_main_weak_ptr,
CompositorTimingHistory::RENDERER_UMA,
layer_tree_host->rendering_stats_instrumentation(),
host_impl_->compositor_frame_reporting_controller()));
- scheduler_.reset(new Scheduler(this, scheduler_settings, layer_tree_host_id_,
- task_runner_provider_->ImplThreadTaskRunner(),
- std::move(compositor_timing_history)));
+ scheduler_ = std::make_unique<Scheduler>(
+ this, scheduler_settings, layer_tree_host_id_,
+ task_runner_provider_->ImplThreadTaskRunner(),
+ std::move(compositor_timing_history), layer_tree_host->TakeMainPipeline(),
+ layer_tree_host->TakeCompositorPipeline());
DCHECK_EQ(scheduler_->visible(), host_impl_->visible());
}
@@ -614,6 +617,8 @@ void ProxyImpl::ScheduledActionSendBeginMainFrame(
begin_main_frame_state->commit_data = host_impl_->ProcessCompositorDeltas();
begin_main_frame_state->completed_image_decode_requests =
host_impl_->TakeCompletedImageDecodeRequests();
+ begin_main_frame_state->finished_transition_request_sequence_ids =
+ host_impl_->TakeFinishedTransitionRequestSequenceIds();
begin_main_frame_state->mutator_events = host_impl_->TakeMutatorEvents();
begin_main_frame_state->active_sequence_trackers =
host_impl_->FrameSequenceTrackerActiveTypes();
@@ -771,7 +776,8 @@ DrawResult ProxyImpl::DrawInternal(bool forced_draw) {
DCHECK_NE(frame.frame_token, 0u);
// Drawing implies we submitted a frame to the LayerTreeFrameSink.
scheduler_->DidSubmitCompositorFrame(frame.frame_token,
- host_impl_->TakeEventsMetrics());
+ host_impl_->TakeEventsMetrics(),
+ frame.has_missing_content);
}
result = DRAW_SUCCESS;
} else {
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index cfafe9c81b5..6f1e341a730 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -145,6 +145,9 @@ void ProxyMain::BeginMainFrame(
layer_tree_host_->ImageDecodesFinished(
std::move(begin_main_frame_state->completed_image_decode_requests));
+ layer_tree_host_->NotifyTransitionRequestsFinished(std::move(
+ begin_main_frame_state->finished_transition_request_sequence_ids));
+
// Visibility check needs to happen before setting
// max_requested_pipeline_stage_. Otherwise a requested commit could get lost
// after tab becomes visible again.
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index 628454e3b90..8f563410e76 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -87,10 +87,12 @@ void SingleThreadProxy::Start() {
CompositorTimingHistory::BROWSER_UMA,
layer_tree_host_->rendering_stats_instrumentation(),
host_impl_->compositor_frame_reporting_controller()));
- scheduler_on_impl_thread_.reset(
- new Scheduler(this, scheduler_settings, layer_tree_host_->GetId(),
- task_runner_provider_->MainThreadTaskRunner(),
- std::move(compositor_timing_history)));
+ scheduler_on_impl_thread_ = std::make_unique<Scheduler>(
+ this, scheduler_settings, layer_tree_host_->GetId(),
+ task_runner_provider_->MainThreadTaskRunner(),
+ std::move(compositor_timing_history),
+ layer_tree_host_->TakeMainPipeline(),
+ layer_tree_host_->TakeCompositorPipeline());
}
}
@@ -212,6 +214,9 @@ void SingleThreadProxy::DoCommit(const viz::BeginFrameArgs& commit_args) {
IssueImageDecodeFinishedCallbacks();
host_impl_->CommitComplete();
+ layer_tree_host_->NotifyTransitionRequestsFinished(
+ host_impl_->TakeFinishedTransitionRequestSequenceIds());
+
// Commit goes directly to the active tree, but we need to synchronously
// "activate" the tree still during commit to satisfy any potential
// SetNextCommitWaitsForActivation calls. Unfortunately, the tree
@@ -516,6 +521,9 @@ void SingleThreadProxy::NotifyImageDecodeRequestFinished() {
DebugScopedSetImplThread impl(task_runner_provider_);
IssueImageDecodeFinishedCallbacks();
+
+ layer_tree_host_->NotifyTransitionRequestsFinished(
+ host_impl_->TakeFinishedTransitionRequestSequenceIds());
return;
}
SetNeedsCommitOnImplThread();
@@ -625,6 +633,7 @@ void SingleThreadProxy::CompositeImmediatelyForTest(
// Note: We do not want to prevent SetNeedsAnimate from requesting
// a commit here.
commit_requested_ = true;
+ StopDeferringCommits(PaintHoldingCommitTrigger::kFeatureDisabled);
DoBeginMainFrame(begin_frame_args);
commit_requested_ = false;
DoPainting();
@@ -712,7 +721,8 @@ DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
if (scheduler_on_impl_thread_) {
// Drawing implies we submitted a frame to the LayerTreeFrameSink.
scheduler_on_impl_thread_->DidSubmitCompositorFrame(
- frame->frame_token, host_impl_->TakeEventsMetrics());
+ frame->frame_token, host_impl_->TakeEventsMetrics(),
+ frame->has_missing_content);
}
single_thread_client_->DidSubmitCompositorFrame();
}