diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-03-11 11:32:04 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-03-18 13:40:17 +0000 |
commit | 31ccca0778db85c159634478b4ec7997f6704860 (patch) | |
tree | 3d33fc3afd9d5ec95541e1bbe074a9cf8da12a0e /chromium/cc | |
parent | 248b70b82a40964d5594eb04feca0fa36716185d (diff) |
BASELINE: Update Chromium to 80.0.3987.136
Change-Id: I98e1649aafae85ba3a83e67af00bb27ef301db7b
Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'chromium/cc')
216 files changed, 8125 insertions, 5193 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn index da40ffada58..335cbec2c77 100644 --- a/chromium/cc/BUILD.gn +++ b/chromium/cc/BUILD.gn @@ -77,7 +77,6 @@ cc_component("cc") { "layers/heads_up_display_layer_impl.h", "layers/layer.cc", "layers/layer.h", - "layers/layer_client.h", "layers/layer_collections.h", "layers/layer_impl.cc", "layers/layer_impl.h", @@ -159,6 +158,8 @@ cc_component("cc") { "metrics/compositor_timing_history.h", "metrics/frame_sequence_tracker.cc", "metrics/frame_sequence_tracker.h", + "metrics/throughput_ukm_reporter.cc", + "metrics/throughput_ukm_reporter.h", "raster/bitmap_raster_buffer_provider.cc", "raster/bitmap_raster_buffer_provider.h", "raster/gpu_raster_buffer_provider.cc", @@ -277,6 +278,8 @@ cc_component("cc") { "trees/animated_paint_worklet_tracker.h", "trees/animation_effect_timings.h", "trees/animation_options.h", + "trees/browser_controls_params.cc", + "trees/browser_controls_params.h", "trees/clip_expander.cc", "trees/clip_expander.h", "trees/clip_node.cc", @@ -374,6 +377,7 @@ cc_component("cc") { "//cc/base", "//cc/paint", "//components/viz/common", + "//services/tracing/public/cpp:cpp", "//skia", ] deps = [ @@ -474,8 +478,6 @@ cc_test_static_library("test_support") { "test/layer_tree_pixel_test.h", "test/layer_tree_test.cc", "test/layer_tree_test.h", - "test/mock_layer_client.cc", - "test/mock_layer_client.h", "test/mock_layer_tree_mutator.cc", "test/mock_layer_tree_mutator.h", "test/mock_occlusion_tracker.h", @@ -643,6 +645,7 @@ cc_test("cc_unittests") { "metrics/compositor_frame_reporter_unittest.cc", "metrics/compositor_frame_reporting_controller_unittest.cc", "metrics/compositor_timing_history_unittest.cc", + "metrics/frame_sequence_metrics_unittest.cc", "metrics/frame_sequence_tracker_unittest.cc", "mojo_embedder/async_layer_tree_frame_sink_unittest.cc", "paint/discardable_image_map_unittest.cc", diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS index 8d3576c0da9..fa357abd483 100644 --- a/chromium/cc/DEPS +++ b/chromium/cc/DEPS @@ -29,11 +29,13 @@ include_rules = [ "+mojo/public/cpp/system/platform_handle.h", "+skia/ext", "+services/metrics/public/cpp", + "+services/tracing/public/cpp", "+third_party/khronos/GLES2/gl2.h", "+third_party/khronos/GLES2/gl2ext.h", "+third_party/libyuv", "+third_party/skia/include", "+third_party/skia/src/core/SkRemoteGlyphCache.h", + "+third_party/perfetto/protos/perfetto/trace/track_event", "+ui/events/types", "+ui/latency", "+ui/gfx", diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS index 820c023d3a5..c5524c67483 100644 --- a/chromium/cc/OWNERS +++ b/chromium/cc/OWNERS @@ -9,6 +9,7 @@ enne@chromium.org danakj@chromium.org pdr@chromium.org +wangxianzhu@chromium.org # mac-specific ccameron@chromium.org @@ -30,6 +31,7 @@ flackr@chromium.org chrishtr@chromium.org weiliangc@chromium.org pdr@chromium.org +wangxianzhu@chromium.org # animation flackr@chromium.org diff --git a/chromium/cc/animation/BUILD.gn b/chromium/cc/animation/BUILD.gn index cdad662a244..19627f46816 100644 --- a/chromium/cc/animation/BUILD.gn +++ b/chromium/cc/animation/BUILD.gn @@ -32,6 +32,8 @@ cc_component("animation") { "keyframed_animation_curve.h", "scroll_offset_animation_curve.cc", "scroll_offset_animation_curve.h", + "scroll_offset_animation_curve_factory.cc", + "scroll_offset_animation_curve_factory.h", "scroll_offset_animations.cc", "scroll_offset_animations.h", "scroll_offset_animations_impl.cc", diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc index 9d32d45f668..5bc03dde436 100644 --- a/chromium/cc/animation/animation.cc +++ b/chromium/cc/animation/animation.cc @@ -271,36 +271,55 @@ void Animation::RemoveFromTicking() { animation_host_->RemoveFromTicking(this); } -void Animation::NotifyKeyframeModelStarted(const AnimationEvent& event) { - if (animation_delegate_) { - animation_delegate_->NotifyAnimationStarted( - event.monotonic_time, event.target_property, event.group_id); - } -} - -void Animation::NotifyKeyframeModelFinished(const AnimationEvent& event) { - if (animation_delegate_) { - animation_delegate_->NotifyAnimationFinished( - event.monotonic_time, event.target_property, event.group_id); - } -} - -void Animation::NotifyKeyframeModelAborted(const AnimationEvent& event) { - if (animation_delegate_) { - animation_delegate_->NotifyAnimationAborted( - event.monotonic_time, event.target_property, event.group_id); +void Animation::DispatchAndDelegateAnimationEvent(const AnimationEvent& event) { + if (event.ShouldDispatchToKeyframeEffectAndModel()) { + KeyframeEffect* keyframe_effect = + GetKeyframeEffectById(event.uid.effect_id); + if (!keyframe_effect || + !keyframe_effect->DispatchAnimationEventToKeyframeModel(event)) { + // If we fail to dispatch the event, it is to clean up an obsolete + // animation and should not notify the delegate. + // TODO(gerchiko): Determine when we expect the referenced animations not + // to exist. + return; + } } + DelegateAnimationEvent(event); } -void Animation::NotifyKeyframeModelTakeover(const AnimationEvent& event) { - DCHECK(event.target_property == TargetProperty::SCROLL_OFFSET); - +void Animation::DelegateAnimationEvent(const AnimationEvent& event) { if (animation_delegate_) { - DCHECK(event.curve); - std::unique_ptr<AnimationCurve> animation_curve = event.curve->Clone(); - animation_delegate_->NotifyAnimationTakeover( - event.monotonic_time, event.target_property, event.animation_start_time, - std::move(animation_curve)); + switch (event.type) { + case AnimationEvent::STARTED: + animation_delegate_->NotifyAnimationStarted( + event.monotonic_time, event.target_property, event.group_id); + break; + + case AnimationEvent::FINISHED: + animation_delegate_->NotifyAnimationFinished( + event.monotonic_time, event.target_property, event.group_id); + break; + + case AnimationEvent::ABORTED: + animation_delegate_->NotifyAnimationAborted( + event.monotonic_time, event.target_property, event.group_id); + break; + + case AnimationEvent::TAKEOVER: + // TODO(crbug.com/1018213): Routing TAKEOVER events is broken. + DCHECK(!event.is_impl_only); + DCHECK(event.target_property == TargetProperty::SCROLL_OFFSET); + DCHECK(event.curve); + animation_delegate_->NotifyAnimationTakeover( + event.monotonic_time, event.target_property, + event.animation_start_time, event.curve->Clone()); + break; + + case AnimationEvent::TIME_UPDATED: + DCHECK(!event.is_impl_only); + animation_delegate_->NotifyLocalTimeUpdated(event.local_time); + break; + } } } diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h index 06df05510a6..9697a657589 100644 --- a/chromium/cc/animation/animation.h +++ b/chromium/cc/animation/animation.h @@ -95,17 +95,19 @@ class CC_ANIMATION_EXPORT Animation : public base::RefCounted<Animation> { virtual void PushPropertiesTo(Animation* animation_impl); - void UpdateState(bool start_ready_keyframe_models, AnimationEvents* events); + virtual void UpdateState(bool start_ready_keyframe_models, + AnimationEvents* events); virtual void Tick(base::TimeTicks monotonic_time); void AddToTicking(); void RemoveFromTicking(); - // AnimationDelegate routing. - void NotifyKeyframeModelStarted(const AnimationEvent& event); - void NotifyKeyframeModelFinished(const AnimationEvent& event); - void NotifyKeyframeModelAborted(const AnimationEvent& event); - void NotifyKeyframeModelTakeover(const AnimationEvent& event); + // Dispatches animation event to the animation keyframe effect and model when + // appropriate, based on the event characteristics. + // Delegates animation event that was successfully dispatched or doesn't need + // to be dispatched. + void DispatchAndDelegateAnimationEvent(const AnimationEvent& event); + size_t TickingKeyframeModelsCount() const; bool AffectsCustomProperty() const; @@ -146,6 +148,9 @@ class CC_ANIMATION_EXPORT Animation : public base::RefCounted<Animation> { void PushAttachedKeyframeEffectsToImplThread(Animation* animation_impl) const; void PushPropertiesToImplThread(Animation* animation_impl); + // Delegates animation event + void DelegateAnimationEvent(const AnimationEvent& event); + protected: explicit Animation(int id); virtual ~Animation(); diff --git a/chromium/cc/animation/animation_delegate.h b/chromium/cc/animation/animation_delegate.h index 013e3431848..0adbb115c59 100644 --- a/chromium/cc/animation/animation_delegate.h +++ b/chromium/cc/animation/animation_delegate.h @@ -35,6 +35,8 @@ class CC_ANIMATION_EXPORT AnimationDelegate { int target_property, base::TimeTicks animation_start_time, std::unique_ptr<AnimationCurve> curve) = 0; + virtual void NotifyLocalTimeUpdated( + base::Optional<base::TimeDelta> local_time) = 0; protected: virtual ~AnimationDelegate() {} diff --git a/chromium/cc/animation/animation_events.cc b/chromium/cc/animation/animation_events.cc index 4d9387aa43e..1382569b09f 100644 --- a/chromium/cc/animation/animation_events.cc +++ b/chromium/cc/animation/animation_events.cc @@ -7,20 +7,36 @@ namespace cc { AnimationEvent::AnimationEvent(AnimationEvent::Type type, - ElementId element_id, + UniqueKeyframeModelId uid, int group_id, int target_property, base::TimeTicks monotonic_time) : type(type), - element_id(element_id), + uid(uid), group_id(group_id), target_property(target_property), monotonic_time(monotonic_time), - is_impl_only(false) {} + is_impl_only(false), + local_time() {} + +AnimationEvent::AnimationEvent(int timeline_id, + int animation_id, + base::Optional<base::TimeDelta> local_time) + : type(TIME_UPDATED), + // Initializing model_id with an invalid value (0). + // Also initializing keyframe_id with 0 which in its case is a valid + // value. However this is safe since keyframe_id and model_id are not used + // when routing a TIME_UPDATED event. + uid({timeline_id, animation_id, 0, 0}), + group_id(), + target_property(), + monotonic_time(), + is_impl_only(false), + local_time(local_time) {} AnimationEvent::AnimationEvent(const AnimationEvent& other) { type = other.type; - element_id = other.element_id; + uid = other.uid; group_id = other.group_id; target_property = other.target_property; monotonic_time = other.monotonic_time; @@ -28,11 +44,12 @@ AnimationEvent::AnimationEvent(const AnimationEvent& other) { animation_start_time = other.animation_start_time; if (other.curve) curve = other.curve->Clone(); + local_time = other.local_time; } AnimationEvent& AnimationEvent::operator=(const AnimationEvent& other) { type = other.type; - element_id = other.element_id; + uid = other.uid; group_id = other.group_id; target_property = other.target_property; monotonic_time = other.monotonic_time; @@ -40,6 +57,7 @@ AnimationEvent& AnimationEvent::operator=(const AnimationEvent& other) { animation_start_time = other.animation_start_time; if (other.curve) curve = other.curve->Clone(); + local_time = other.local_time; return *this; } @@ -53,4 +71,13 @@ bool AnimationEvents::IsEmpty() const { return events_.empty(); } +bool AnimationEvent::ShouldDispatchToKeyframeEffectAndModel() const { + // TIME_UPDATED events are used to synchronize effect time between cc and + // main thread worklet animations. Keyframe models are not involved in + // this process. + // is_impl_only events are not dispatched because they don't have + // corresponding main thread components. + return type != TIME_UPDATED && !is_impl_only; +} + } // namespace cc diff --git a/chromium/cc/animation/animation_events.h b/chromium/cc/animation/animation_events.h index cec76160ce8..2835c41336f 100644 --- a/chromium/cc/animation/animation_events.h +++ b/chromium/cc/animation/animation_events.h @@ -10,28 +10,41 @@ #include "cc/animation/animation_curve.h" #include "cc/animation/animation_export.h" -#include "cc/animation/keyframe_model.h" -#include "cc/paint/element_id.h" #include "cc/trees/mutator_host.h" namespace cc { struct CC_ANIMATION_EXPORT AnimationEvent { - enum Type { STARTED, FINISHED, ABORTED, TAKEOVER }; + enum Type { STARTED, FINISHED, ABORTED, TAKEOVER, TIME_UPDATED }; + + typedef size_t KeyframeEffectId; + struct UniqueKeyframeModelId { + int timeline_id; + int animation_id; + KeyframeEffectId effect_id; + int model_id; + }; AnimationEvent(Type type, - ElementId element_id, + UniqueKeyframeModelId uid, int group_id, int target_property, base::TimeTicks monotonic_time); + // Constructs AnimationEvent of TIME_UPDATED type. + AnimationEvent(int timeline_id, + int animation_id, + base::Optional<base::TimeDelta> local_time); + AnimationEvent(const AnimationEvent& other); AnimationEvent& operator=(const AnimationEvent& other); ~AnimationEvent(); + bool ShouldDispatchToKeyframeEffectAndModel() const; + Type type; - ElementId element_id; + UniqueKeyframeModelId uid; int group_id; int target_property; base::TimeTicks monotonic_time; @@ -40,6 +53,9 @@ struct CC_ANIMATION_EXPORT AnimationEvent { // For continuing a scroll offset animation on the main thread. base::TimeTicks animation_start_time; std::unique_ptr<AnimationCurve> curve; + + // Set for TIME_UPDATED events. + base::Optional<base::TimeDelta> local_time; }; class CC_ANIMATION_EXPORT AnimationEvents : public MutatorEvents { diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc index 2e4dbb4e434..10c6f2ecd83 100644 --- a/chromium/cc/animation/animation_host.cc +++ b/chromium/cc/animation/animation_host.cc @@ -490,31 +490,12 @@ void AnimationHost::SetAnimationEvents( for (size_t event_index = 0; event_index < events->events_.size(); ++event_index) { - ElementId element_id = events->events_[event_index].element_id; - - // Use the map of all ElementAnimations, not just ticking animations, since - // non-ticking animations may still receive events for impl-only animations. - const ElementToAnimationsMap& all_element_animations = - element_to_animations_map_; - auto iter = all_element_animations.find(element_id); - if (iter != all_element_animations.end()) { - switch (events->events_[event_index].type) { - case AnimationEvent::STARTED: - (*iter).second->NotifyAnimationStarted(events->events_[event_index]); - break; - - case AnimationEvent::FINISHED: - (*iter).second->NotifyAnimationFinished(events->events_[event_index]); - break; - - case AnimationEvent::ABORTED: - (*iter).second->NotifyAnimationAborted(events->events_[event_index]); - break; - - case AnimationEvent::TAKEOVER: - (*iter).second->NotifyAnimationTakeover(events->events_[event_index]); - break; - } + AnimationEvent& event = events->events_[event_index]; + AnimationTimeline* timeline = GetTimelineById(event.uid.timeline_id); + if (timeline) { + Animation* animation = timeline->GetAnimationById(event.uid.animation_id); + if (animation) + animation->DispatchAndDelegateAnimationEvent(event); } } } @@ -667,7 +648,7 @@ void AnimationHost::ImplOnlyScrollAnimationCreate( base::TimeDelta delayed_by, base::TimeDelta animation_start_offset) { DCHECK(scroll_offset_animations_impl_); - scroll_offset_animations_impl_->ScrollAnimationCreate( + scroll_offset_animations_impl_->MouseWheelScrollAnimationCreate( element_id, target_offset, current_offset, delayed_by, animation_start_offset); } @@ -730,6 +711,20 @@ void AnimationHost::SetLayerTreeMutator( mutator_->SetClient(this); } +WorkletAnimation* AnimationHost::FindWorkletAnimation(WorkletAnimationId id) { + // TODO(majidvp): Use a map to make lookup O(1) + auto animation = std::find_if( + ticking_animations_.begin(), ticking_animations_.end(), [id](auto& it) { + return it->IsWorkletAnimation() && + ToWorkletAnimation(it.get())->worklet_animation_id() == id; + }); + + if (animation == ticking_animations_.end()) + return nullptr; + + return ToWorkletAnimation(animation->get()); +} + void AnimationHost::SetMutationUpdate( std::unique_ptr<MutatorOutputState> output_state) { if (!output_state) @@ -739,17 +734,9 @@ void AnimationHost::SetMutationUpdate( for (auto& animation_state : output_state->animations) { WorkletAnimationId id = animation_state.worklet_animation_id; - // TODO(majidvp): Use a map to make lookup O(1) - auto to_update = std::find_if( - ticking_animations_.begin(), ticking_animations_.end(), [id](auto& it) { - return it->IsWorkletAnimation() && - ToWorkletAnimation(it.get())->worklet_animation_id() == id; - }); - - if (to_update == ticking_animations_.end()) - continue; - - ToWorkletAnimation(to_update->get())->SetOutputState(animation_state); + WorkletAnimation* to_update = FindWorkletAnimation(id); + if (to_update) + to_update->SetOutputState(animation_state); } } diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h index fa0a1a5a0a6..a31347032b7 100644 --- a/chromium/cc/animation/animation_host.h +++ b/chromium/cc/animation/animation_host.h @@ -32,6 +32,7 @@ class LayerTreeHost; class KeyframeEffect; class ScrollOffsetAnimations; class ScrollOffsetAnimationsImpl; +class WorkletAnimation; enum class ThreadInstance { MAIN, IMPL }; @@ -235,6 +236,10 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, const ScrollTree& scroll_tree, bool is_active_tree); + // Returns a pointer to a worklet animation by worklet animation id or null + // if there is no match. + WorkletAnimation* FindWorkletAnimation(WorkletAnimationId id); + ElementToAnimationsMap element_to_animations_map_; AnimationsList ticking_animations_; diff --git a/chromium/cc/animation/animation_host_unittest.cc b/chromium/cc/animation/animation_host_unittest.cc index 206919ee556..45fd8ccc4db 100644 --- a/chromium/cc/animation/animation_host_unittest.cc +++ b/chromium/cc/animation/animation_host_unittest.cc @@ -177,7 +177,7 @@ TEST_F(AnimationHostTest, FastLayerTreeMutatorUpdateTakesEffectInSameFrame) { // Ticking host should cause layer tree mutator to update output state which // should take effect in the same animation frame. - TickAnimationsTransferEvents(base::TimeTicks(), 0u); + TickAnimationsTransferEvents(base::TimeTicks(), 1u); // Emulate behavior in PrepareToDraw. Animation worklet updates are best // effort, and the animation tick is deferred until draw to allow time for the diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc index 08cf3f95751..03996f2b245 100644 --- a/chromium/cc/animation/element_animations.cc +++ b/chromium/cc/animation/element_animations.cc @@ -175,41 +175,6 @@ void ElementAnimations::RemoveKeyframeEffectsFromTicking() const { keyframe_effect.RemoveFromTicking(); } -void ElementAnimations::NotifyAnimationStarted(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - for (auto& keyframe_effect : keyframe_effects_list_) { - if (keyframe_effect.NotifyKeyframeModelStarted(event)) - break; - } -} - -void ElementAnimations::NotifyAnimationFinished(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - for (auto& keyframe_effect : keyframe_effects_list_) { - if (keyframe_effect.NotifyKeyframeModelFinished(event)) - break; - } -} - -void ElementAnimations::NotifyAnimationTakeover(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - DCHECK(event.target_property == TargetProperty::SCROLL_OFFSET); - - for (auto& keyframe_effect : keyframe_effects_list_) - keyframe_effect.NotifyKeyframeModelTakeover(event); -} - -void ElementAnimations::NotifyAnimationAborted(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - - for (auto& keyframe_effect : keyframe_effects_list_) { - if (keyframe_effect.NotifyKeyframeModelAborted(event)) - break; - } - - UpdateClientAnimationState(); -} - bool ElementAnimations::AnimationsPreserveAxisAlignment() const { for (auto& keyframe_effect : keyframe_effects_list_) { if (!keyframe_effect.AnimationsPreserveAxisAlignment()) diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h index 3bf69aa9d13..22a29defd10 100644 --- a/chromium/cc/animation/element_animations.h +++ b/chromium/cc/animation/element_animations.h @@ -26,7 +26,6 @@ class FilterOperations; class KeyframeEffect; class TransformOperations; enum class ElementListType; -struct AnimationEvent; // An ElementAnimations owns a list of all KeyframeEffects attached to a single // target (represented by an ElementId). @@ -89,11 +88,6 @@ class CC_ANIMATION_EXPORT ElementAnimations bool IsCurrentlyAnimatingProperty(TargetProperty::Type target_property, ElementListType list_type) const; - void NotifyAnimationStarted(const AnimationEvent& event); - void NotifyAnimationFinished(const AnimationEvent& event); - void NotifyAnimationAborted(const AnimationEvent& event); - void NotifyAnimationTakeover(const AnimationEvent& event); - bool has_element_in_active_list() const { return has_element_in_active_list_; } diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc index 54920ea0693..6b274dd13f5 100644 --- a/chromium/cc/animation/element_animations_unittest.cc +++ b/chromium/cc/animation/element_animations_unittest.cc @@ -13,6 +13,7 @@ #include "cc/animation/keyframe_effect.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/scroll_offset_animation_curve.h" +#include "cc/animation/scroll_offset_animation_curve_factory.h" #include "cc/animation/single_keyframe_effect_animation.h" #include "cc/animation/transform_operations.h" #include "cc/test/animation_test_common.h" @@ -266,9 +267,8 @@ TEST_F(ElementAnimationsTest, // Animation with initial value set. std::unique_ptr<ScrollOffsetAnimationCurve> curve_fixed( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve_fixed->SetInitialValue(initial_value); const int animation1_id = 1; std::unique_ptr<KeyframeModel> animation_fixed(KeyframeModel::Create( @@ -284,9 +284,8 @@ TEST_F(ElementAnimationsTest, // Animation without initial value set. std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); const int animation2_id = 2; std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), animation2_id, 1, TargetProperty::SCROLL_OFFSET)); @@ -369,7 +368,7 @@ TEST_F(ElementAnimationsTest, AddedAnimationIsDestroyed) { EXPECT_EQ(AnimationEvent::STARTED, events->events_[0].type); // The actual detachment happens here, inside the callback - animation2->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation2->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_TRUE(delegate.started()); } @@ -401,7 +400,7 @@ TEST_F(ElementAnimationsTest, DoNotClobberStartTimes) { // Synchronize the start times. EXPECT_EQ(1u, events->events_.size()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_EQ(animation_->keyframe_effect() ->GetKeyframeModelById(keyframe_model_id) ->start_time(), @@ -448,7 +447,7 @@ TEST_F(ElementAnimationsTest, UseSpecifiedStartTimes) { // Synchronize the start times. EXPECT_EQ(1u, events->events_.size()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_EQ(start_time, animation_->keyframe_effect() ->GetKeyframeModelById(keyframe_model_id) @@ -505,7 +504,7 @@ TEST_F(ElementAnimationsTest, Activation) { animation_impl_->Tick(kInitialTickTime); animation_impl_->UpdateState(true, events.get()); EXPECT_EQ(1u, events->events_.size()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_EQ(1u, host->ticking_animations_for_testing().size()); EXPECT_EQ(1u, host_impl->ticking_animations_for_testing().size()); @@ -532,8 +531,7 @@ TEST_F(ElementAnimationsTest, Activation) { EXPECT_EQ(0u, host_impl->ticking_animations_for_testing().size()); EXPECT_EQ(1u, events->events_.size()); - animation_->keyframe_effect()->NotifyKeyframeModelFinished( - events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1500)); animation_->UpdateState(true, nullptr); @@ -587,7 +585,7 @@ TEST_F(ElementAnimationsTest, SyncPause) { animation_->Tick(time); animation_->UpdateState(true, nullptr); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_EQ(KeyframeModel::RUNNING, animation_impl_->keyframe_effect() @@ -664,7 +662,7 @@ TEST_F(ElementAnimationsTest, DoNotSyncFinishedAnimation) { EXPECT_EQ(AnimationEvent::STARTED, events->events_[0].type); // Notify main thread animations that the animation has started. - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); // Complete animation on impl thread. events = CreateEventsForTesting(); @@ -673,8 +671,7 @@ TEST_F(ElementAnimationsTest, DoNotSyncFinishedAnimation) { EXPECT_EQ(1u, events->events_.size()); EXPECT_EQ(AnimationEvent::FINISHED, events->events_[0].type); - animation_->keyframe_effect()->NotifyKeyframeModelFinished( - events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); animation_->Tick(kInitialTickTime + TimeDelta::FromSeconds(2)); animation_->UpdateState(true, nullptr); @@ -715,7 +712,7 @@ TEST_F(ElementAnimationsTest, AnimationsAreDeleted) { // There should be a STARTED event for the animation. EXPECT_EQ(1u, events->events_.size()); EXPECT_EQ(AnimationEvent::STARTED, events->events_[0].type); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); animation_->UpdateState(true, nullptr); @@ -737,8 +734,7 @@ TEST_F(ElementAnimationsTest, AnimationsAreDeleted) { EXPECT_TRUE(animation_->GetKeyframeModel(TargetProperty::OPACITY)); EXPECT_TRUE(animation_impl_->GetKeyframeModel(TargetProperty::OPACITY)); - animation_->keyframe_effect()->NotifyKeyframeModelFinished( - events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(3000)); animation_->UpdateState(true, nullptr); @@ -894,9 +890,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransition) { gfx::ScrollOffset initial_value(100.f, 300.f); gfx::ScrollOffset target_value(300.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); @@ -928,7 +923,7 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransition) { EXPECT_EQ(initial_value, client_impl_.GetScrollOffset(element_id_, ElementListType::ACTIVE)); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); animation_->Tick(kInitialTickTime + duration / 2); animation_->UpdateState(true, nullptr); EXPECT_TRUE(animation_->keyframe_effect()->HasTickingKeyframeModel()); @@ -965,9 +960,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionOnImplOnly) { gfx::ScrollOffset initial_value(100.f, 300.f); gfx::ScrollOffset target_value(300.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve->SetInitialValue(initial_value); double duration_in_seconds = curve->Duration().InSecondsF(); @@ -1067,9 +1061,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionNoImplProvider) { gfx::ScrollOffset initial_value(500.f, 100.f); gfx::ScrollOffset target_value(300.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); @@ -1109,7 +1102,7 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionNoImplProvider) { animation_impl_->UpdateState(true, events.get()); DCHECK_EQ(1UL, events->events_.size()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); animation_->Tick(kInitialTickTime + duration / 2); animation_->UpdateState(true, nullptr); EXPECT_TRUE(animation_->keyframe_effect()->HasTickingKeyframeModel()); @@ -1146,9 +1139,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) { // First test the 1-argument version of RemoveKeyframeModel. gfx::ScrollOffset target_value(300.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); int keyframe_model_id = 1; std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( @@ -1177,9 +1169,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) { ->scroll_offset_animation_was_interrupted()); // Now, test the 2-argument version of RemoveKeyframeModel. - curve = ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT)); + curve = ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value); keyframe_model = KeyframeModel::Create(std::move(curve), keyframe_model_id, 0, TargetProperty::SCROLL_OFFSET); keyframe_model->set_needs_synchronized_start_time(true); @@ -1270,9 +1261,8 @@ TEST_F(ElementAnimationsTest, gfx::ScrollOffset initial_value(100.f, 300.f); gfx::ScrollOffset target_value(300.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve->SetInitialValue(initial_value); TimeDelta duration = curve->Duration(); std::unique_ptr<KeyframeModel> to_add(KeyframeModel::Create( @@ -1333,7 +1323,7 @@ TEST_F(ElementAnimationsTest, SpecifiedStartTimesAreSentToMainThreadDelegate) { // Synchronize the start times. EXPECT_EQ(1u, events->events_.size()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); // Validate start time on the main thread delegate. EXPECT_EQ(start_time, delegate.start_time()); @@ -1352,6 +1342,7 @@ TEST_F(ElementAnimationsTest, std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)), 1, TargetProperty::OPACITY)); to_add->set_needs_synchronized_start_time(true); + int keyframe_model_id = to_add->id(); // We should pause at the first keyframe indefinitely waiting for that // animation to start. @@ -1370,9 +1361,12 @@ TEST_F(ElementAnimationsTest, EXPECT_EQ(0.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE)); // Send the synchronized start time. - animation_->keyframe_effect()->NotifyKeyframeModelStarted(AnimationEvent( - AnimationEvent::STARTED, ElementId(), 1, TargetProperty::OPACITY, - kInitialTickTime + TimeDelta::FromMilliseconds(2000))); + animation_->DispatchAndDelegateAnimationEvent( + AnimationEvent(AnimationEvent::STARTED, + {animation_->animation_timeline()->id(), animation_->id(), + animation_->keyframe_effect()->id(), keyframe_model_id}, + 1, TargetProperty::OPACITY, + kInitialTickTime + TimeDelta::FromMilliseconds(2000))); animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(5000)); animation_->UpdateState(true, events.get()); EXPECT_EQ(1.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE)); @@ -2017,7 +2011,7 @@ TEST_F(ElementAnimationsTest, ImplThreadAbortedAnimationGetsDeleted) { KeyframeModel::WAITING_FOR_DELETION, animation_impl_->GetKeyframeModel(TargetProperty::OPACITY)->run_state()); - animation_->keyframe_effect()->NotifyKeyframeModelAborted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_EQ(KeyframeModel::ABORTED, animation_->GetKeyframeModel(TargetProperty::OPACITY)->run_state()); EXPECT_TRUE(delegate.aborted()); @@ -2054,9 +2048,8 @@ TEST_F(ElementAnimationsTest, ImplThreadTakeoverAnimationGetsDeleted) { gfx::ScrollOffset initial_value(100.f, 300.f); gfx::ScrollOffset target_value(300.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve->SetInitialValue(initial_value); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), keyframe_model_id, 0, TargetProperty::SCROLL_OFFSET)); @@ -2093,8 +2086,7 @@ TEST_F(ElementAnimationsTest, ImplThreadTakeoverAnimationGetsDeleted) { animation_impl_->GetKeyframeModel(TargetProperty::SCROLL_OFFSET)); // MT receives the event to take over. - animation_->keyframe_effect()->NotifyKeyframeModelTakeover( - events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_TRUE(delegate.takeover()); // SingleKeyframeEffectAnimation::NotifyAnimationTakeover requests @@ -2680,7 +2672,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) { animation_impl_->Tick(kInitialTickTime); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); // Finish the animation. @@ -2753,7 +2745,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_->RemoveKeyframeModel(keyframe_model_id); @@ -2806,7 +2798,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM, @@ -2823,7 +2815,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); animation_impl_->UpdateState(true, events.get()); - element_animations_->NotifyAnimationAborted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_FALSE(client_.GetHasPotentialTransformAnimation( element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(client_.GetTransformIsCurrentlyAnimating( @@ -2907,7 +2899,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) { animation_impl_->Tick(kInitialTickTime); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); // Finish the animation. @@ -2969,7 +2961,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_->RemoveKeyframeModel(keyframe_model_id); @@ -3021,7 +3013,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, @@ -3038,7 +3030,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); animation_impl_->UpdateState(true, events.get()); - element_animations_->NotifyAnimationAborted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_FALSE(client_.GetHasPotentialOpacityAnimation( element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(client_.GetOpacityIsCurrentlyAnimating(element_id_, @@ -3121,7 +3113,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) { animation_impl_->Tick(kInitialTickTime); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); // Finish the animation. @@ -3183,7 +3175,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_->RemoveKeyframeModel(keyframe_model_id); @@ -3235,7 +3227,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_impl_->AbortKeyframeModelsWithProperty(TargetProperty::FILTER, @@ -3252,7 +3244,7 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) { animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); animation_impl_->UpdateState(true, events.get()); - element_animations_->NotifyAnimationAborted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_FALSE(client_.GetHasPotentialFilterAnimation(element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(client_.GetFilterIsCurrentlyAnimating(element_id_, @@ -3336,7 +3328,7 @@ TEST_F(ElementAnimationsTest, animation_impl_->Tick(kInitialTickTime); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); // Finish the animation. @@ -3398,7 +3390,7 @@ TEST_F(ElementAnimationsTest, animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_->RemoveKeyframeModel(keyframe_model_id); @@ -3450,7 +3442,7 @@ TEST_F(ElementAnimationsTest, animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); animation_impl_->UpdateState(true, events.get()); - animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); events->events_.clear(); animation_impl_->AbortKeyframeModelsWithProperty( @@ -3467,7 +3459,7 @@ TEST_F(ElementAnimationsTest, animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); animation_impl_->UpdateState(true, events.get()); - element_animations_->NotifyAnimationAborted(events->events_[0]); + animation_->DispatchAndDelegateAnimationEvent(events->events_[0]); EXPECT_FALSE(client_.GetHasPotentialBackdropFilterAnimation( element_id_, ElementListType::ACTIVE)); EXPECT_FALSE(client_.GetBackdropFilterIsCurrentlyAnimating( diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc index ecbd64a259d..d3a7543adc1 100644 --- a/chromium/cc/animation/keyframe_effect.cc +++ b/chromium/cc/animation/keyframe_effect.cc @@ -11,6 +11,7 @@ #include "cc/animation/animation.h" #include "cc/animation/animation_curve.h" #include "cc/animation/animation_host.h" +#include "cc/animation/animation_timeline.h" #include "cc/animation/keyframe_model.h" #include "cc/animation/scroll_offset_animation_curve.h" #include "cc/animation/transform_operations.h" @@ -394,62 +395,65 @@ void KeyframeEffect::KeyframeModelAdded() { element_animations_->UpdateClientAnimationState(); } -bool KeyframeEffect::NotifyKeyframeModelStarted(const AnimationEvent& event) { +bool KeyframeEffect::DispatchAnimationEventToKeyframeModel( + const AnimationEvent& event) { DCHECK(!event.is_impl_only); - for (auto& keyframe_model : keyframe_models_) { - if (keyframe_model->group() == event.group_id && - keyframe_model->target_property_id() == event.target_property && - keyframe_model->needs_synchronized_start_time()) { - keyframe_model->set_needs_synchronized_start_time(false); - if (!keyframe_model->has_set_start_time()) - keyframe_model->set_start_time(event.monotonic_time); - animation_->NotifyKeyframeModelStarted(event); - return true; - } - } - return false; -} - -bool KeyframeEffect::NotifyKeyframeModelFinished(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - for (auto& keyframe_model : keyframe_models_) { - if (keyframe_model->group() == event.group_id && - keyframe_model->target_property_id() == event.target_property) { - keyframe_model->set_received_finished_event(true); - animation_->NotifyKeyframeModelFinished(event); - return true; - } - } - - // This is for the case when a keyframe_model is already removed on main - // thread, but the impl version of it sent a finished event and is now waiting - // for deletion. We would need to delete that keyframe_model during push - // properties. - SetNeedsPushProperties(); - return false; -} + KeyframeModel* keyframe_model = GetKeyframeModelById(event.uid.model_id); + bool dispatched = false; + switch (event.type) { + case AnimationEvent::STARTED: + if (keyframe_model && keyframe_model->needs_synchronized_start_time()) { + keyframe_model->set_needs_synchronized_start_time(false); + if (!keyframe_model->has_set_start_time()) + keyframe_model->set_start_time(event.monotonic_time); + dispatched = true; + } + break; -void KeyframeEffect::NotifyKeyframeModelTakeover(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); + case AnimationEvent::FINISHED: + if (keyframe_model) { + keyframe_model->set_received_finished_event(true); + dispatched = true; + } else { + // This is for the case when a keyframe_model is already removed on main + // thread, but the impl version of it sent a finished event and is now + // waiting for deletion. We would need to delete that keyframe_model + // during push properties. + SetNeedsPushProperties(); + } + break; - // We need to purge KeyframeModels marked for deletion on CT. - SetNeedsPushProperties(); + case AnimationEvent::ABORTED: + if (keyframe_model) { + keyframe_model->SetRunState(KeyframeModel::ABORTED, + event.monotonic_time); + keyframe_model->set_received_finished_event(true); + dispatched = true; + + ElementAnimations* element_animations = + animation_->animation_host() + ->GetElementAnimationsForElementId(element_id()) + .get(); + if (element_animations) + element_animations->UpdateClientAnimationState(); + } + break; - animation_->NotifyKeyframeModelTakeover(event); -} + case AnimationEvent::TAKEOVER: + // TODO(crbug.com/1018213): Routing TAKEOVER events is broken. + // We need to purge KeyframeModels marked for deletion on CT. + SetNeedsPushProperties(); + dispatched = true; + break; -bool KeyframeEffect::NotifyKeyframeModelAborted(const AnimationEvent& event) { - DCHECK(!event.is_impl_only); - for (auto& keyframe_model : keyframe_models_) { - if (keyframe_model->group() == event.group_id && - keyframe_model->target_property_id() == event.target_property) { - keyframe_model->SetRunState(KeyframeModel::ABORTED, event.monotonic_time); - keyframe_model->set_received_finished_event(true); - animation_->NotifyKeyframeModelAborted(event); - return true; - } + case AnimationEvent::TIME_UPDATED: + // TIME_UPDATED events are used to synchronize effect time between cc and + // main thread worklet animations. Keyframe models are not involved in + // this process. + NOTREACHED(); + break; } - return false; + return dispatched; } bool KeyframeEffect::HasTickingKeyframeModel() const { @@ -778,6 +782,10 @@ void KeyframeEffect::PushPropertiesTo(KeyframeEffect* keyframe_effect_impl) { } } + keyframe_effect_impl->scroll_offset_animation_was_interrupted_ = + scroll_offset_animation_was_interrupted_; + scroll_offset_animation_was_interrupted_ = false; + // If neither main nor impl have any KeyframeModels, there is nothing further // to synchronize. if (!has_any_keyframe_model() && @@ -799,9 +807,6 @@ void KeyframeEffect::PushPropertiesTo(KeyframeEffect* keyframe_effect_impl) { if (current_impl) keyframe_model->PushPropertiesTo(current_impl); } - keyframe_effect_impl->scroll_offset_animation_was_interrupted_ = - scroll_offset_animation_was_interrupted_; - scroll_offset_animation_was_interrupted_ = false; keyframe_effect_impl->UpdateTickingState(); } @@ -1082,7 +1087,10 @@ void KeyframeEffect::GenerateEvent(AnimationEvents* events, if (!events) return; - AnimationEvent event(type, element_id_, keyframe_model.group(), + AnimationEvent event(type, + {animation_->animation_timeline()->id(), + animation_->id(), id(), keyframe_model.id()}, + keyframe_model.group(), keyframe_model.target_property_id(), monotonic_time); event.is_impl_only = keyframe_model.is_impl_only(); if (!event.is_impl_only) { @@ -1090,22 +1098,7 @@ void KeyframeEffect::GenerateEvent(AnimationEvents* events, return; } // For impl only animations notify delegate directly, do not record the event. - switch (type) { - case AnimationEvent::FINISHED: - animation_->NotifyKeyframeModelFinished(event); - break; - case AnimationEvent::STARTED: - animation_->NotifyKeyframeModelStarted(event); - break; - case AnimationEvent::ABORTED: - animation_->NotifyKeyframeModelAborted(event); - break; - case AnimationEvent::TAKEOVER: - // We never expect to receive a TAKEOVER notification on impl only - // animations. - NOTREACHED(); - break; - } + animation_->DispatchAndDelegateAnimationEvent(event); } void KeyframeEffect::GenerateTakeoverEventForScrollAnimation( @@ -1116,17 +1109,28 @@ void KeyframeEffect::GenerateTakeoverEventForScrollAnimation( if (!events) return; - AnimationEvent takeover_event( - AnimationEvent::TAKEOVER, element_id_, keyframe_model.group(), - keyframe_model.target_property_id(), monotonic_time); + AnimationEvent takeover_event(AnimationEvent::TAKEOVER, + {animation_->animation_timeline()->id(), + animation_->id(), id(), keyframe_model.id()}, + keyframe_model.group(), + keyframe_model.target_property_id(), + monotonic_time); takeover_event.animation_start_time = keyframe_model.start_time(); const ScrollOffsetAnimationCurve* scroll_offset_animation_curve = keyframe_model.curve()->ToScrollOffsetAnimationCurve(); takeover_event.curve = scroll_offset_animation_curve->Clone(); - // Notify the compositor that the animation is finished. - animation_->NotifyKeyframeModelFinished(takeover_event); // Notify main thread. events->events_.push_back(takeover_event); + + AnimationEvent finished_event(AnimationEvent::FINISHED, + {animation_->animation_timeline()->id(), + animation_->id(), id(), keyframe_model.id()}, + keyframe_model.group(), + keyframe_model.target_property_id(), + monotonic_time); + // Notify the compositor that the animation is finished. + finished_event.is_impl_only = true; + animation_->DispatchAndDelegateAnimationEvent(finished_event); } } // namespace cc diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h index e3816763e85..a450d22a003 100644 --- a/chromium/cc/animation/keyframe_effect.h +++ b/chromium/cc/animation/keyframe_effect.h @@ -105,14 +105,9 @@ class CC_ANIMATION_EXPORT KeyframeEffect { void KeyframeModelAdded(); - // The following methods should be called to notify the KeyframeEffect that - // an animation event has been received for the same target (ElementId) as - // this keyframe_effect. If the event matches a KeyframeModel owned by this - // KeyframeEffect the call will return true, else it will return false. - bool NotifyKeyframeModelStarted(const AnimationEvent& event); - bool NotifyKeyframeModelFinished(const AnimationEvent& event); - void NotifyKeyframeModelTakeover(const AnimationEvent& event); - bool NotifyKeyframeModelAborted(const AnimationEvent& event); + // Dispatches animation event to a keyframe model specified as part of the + // event. Returns true if the event is dispatched, false otherwise. + bool DispatchAnimationEventToKeyframeModel(const AnimationEvent& event); // Returns true if there are any KeyframeModels that have neither finished // nor aborted. diff --git a/chromium/cc/animation/keyframe_model.h b/chromium/cc/animation/keyframe_model.h index c5e0dee5b4d..b7b52cd8cbf 100644 --- a/chromium/cc/animation/keyframe_model.h +++ b/chromium/cc/animation/keyframe_model.h @@ -22,9 +22,6 @@ class AnimationCurve; // It represents a model of the keyframes (internally represented as a curve). class CC_ANIMATION_EXPORT KeyframeModel { public: - // TODO(yigu): RunState is supposed to be managed/accessed at Animation - // level rather than KeyframeModel level. See https://crbug.com/812652. - // // KeyframeModels begin in the 'WAITING_FOR_TARGET_AVAILABILITY' state. A // KeyframeModel waiting for target availibility will run as soon as its // target property is free (and all the KeyframeModels animating with it are diff --git a/chromium/cc/animation/scroll_offset_animation_curve.cc b/chromium/cc/animation/scroll_offset_animation_curve.cc index 6ec55b7472b..bcb46ad170e 100644 --- a/chromium/cc/animation/scroll_offset_animation_curve.cc +++ b/chromium/cc/animation/scroll_offset_animation_curve.cc @@ -14,8 +14,6 @@ #include "cc/base/time_util.h" #include "ui/gfx/animation/tween.h" -using DurationBehavior = cc::ScrollOffsetAnimationCurve::DurationBehavior; - const double kConstantDuration = 9.0; const double kDurationDivisor = 60.0; @@ -44,7 +42,7 @@ static float MaximumDimension(const gfx::Vector2dF& delta) { return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y(); } -static std::unique_ptr<TimingFunction> EaseOutWithInitialVelocity( +static std::unique_ptr<TimingFunction> EaseInOutWithInitialVelocity( double velocity) { // Clamp velocity to a sane value. velocity = base::ClampToRange(velocity, -1000.0, 1000.0); @@ -61,33 +59,30 @@ static std::unique_ptr<TimingFunction> EaseOutWithInitialVelocity( base::Optional<double> ScrollOffsetAnimationCurve::animation_duration_for_testing_; -std::unique_ptr<ScrollOffsetAnimationCurve> ScrollOffsetAnimationCurve::Create( - const gfx::ScrollOffset& target_value, - std::unique_ptr<TimingFunction> timing_function, - DurationBehavior duration_behavior) { - return base::WrapUnique(new ScrollOffsetAnimationCurve( - target_value, std::move(timing_function), duration_behavior)); -} - ScrollOffsetAnimationCurve::ScrollOffsetAnimationCurve( const gfx::ScrollOffset& target_value, std::unique_ptr<TimingFunction> timing_function, - DurationBehavior duration_behavior) + AnimationType animation_type, + base::Optional<DurationBehavior> duration_behavior) : target_value_(target_value), timing_function_(std::move(timing_function)), + animation_type_(animation_type), duration_behavior_(duration_behavior), - has_set_initial_value_(false) {} + has_set_initial_value_(false) { + DCHECK_EQ((animation_type == AnimationType::kEaseInOut), + duration_behavior.has_value()); +} ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() = default; -base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration( +// static +base::TimeDelta ScrollOffsetAnimationCurve::EaseInOutSegmentDuration( const gfx::Vector2dF& delta, - DurationBehavior behavior, - base::TimeDelta delayed_by, - float velocity) { + DurationBehavior duration_behavior, + base::TimeDelta delayed_by) { double duration = kConstantDuration; if (!animation_duration_for_testing_) { - switch (behavior) { + switch (duration_behavior) { case DurationBehavior::CONSTANT: duration = kConstantDuration; break; @@ -102,24 +97,33 @@ base::TimeDelta ScrollOffsetAnimationCurve::SegmentDuration( duration = base::ClampToRange(duration, kInverseDeltaMinDuration, kInverseDeltaMaxDuration); break; - case DurationBehavior::CONSTANT_VELOCITY: - duration = - std::abs(MaximumDimension(delta) / velocity * kDurationDivisor); - break; - default: - NOTREACHED(); } + duration /= kDurationDivisor; } else { duration = animation_duration_for_testing_.value(); } - base::TimeDelta time_delta = base::TimeDelta::FromMicroseconds( - duration / kDurationDivisor * base::Time::kMicrosecondsPerSecond); + base::TimeDelta delay_adjusted_duration = + base::TimeDelta::FromSecondsD(duration) - delayed_by; + return (delay_adjusted_duration >= base::TimeDelta()) + ? delay_adjusted_duration + : base::TimeDelta(); +} - time_delta -= delayed_by; - if (time_delta >= base::TimeDelta()) - return time_delta; - return base::TimeDelta(); +// static +base::TimeDelta ScrollOffsetAnimationCurve::LinearSegmentDuration( + const gfx::Vector2dF& delta, + base::TimeDelta delayed_by, + float velocity) { + double duration_in_seconds = + (animation_duration_for_testing_.has_value()) + ? animation_duration_for_testing_.value() + : std::abs(MaximumDimension(delta) / velocity); + base::TimeDelta delay_adjusted_duration = + base::TimeDelta::FromSecondsD(duration_in_seconds) - delayed_by; + return (delay_adjusted_duration >= base::TimeDelta()) + ? delay_adjusted_duration + : base::TimeDelta(); } void ScrollOffsetAnimationCurve::SetInitialValue( @@ -128,9 +132,17 @@ void ScrollOffsetAnimationCurve::SetInitialValue( float velocity) { initial_value_ = initial_value; has_set_initial_value_ = true; - total_animation_duration_ = - SegmentDuration(target_value_.DeltaFrom(initial_value_), - duration_behavior_, delayed_by, velocity); + gfx::Vector2dF delta = target_value_.DeltaFrom(initial_value); + switch (animation_type_) { + case AnimationType::kEaseInOut: + total_animation_duration_ = EaseInOutSegmentDuration( + delta, duration_behavior_.value(), delayed_by); + break; + case AnimationType::kLinear: + total_animation_duration_ = + LinearSegmentDuration(delta, delayed_by, velocity); + break; + } } bool ScrollOffsetAnimationCurve::HasSetInitialValue() const { @@ -159,10 +171,10 @@ gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue( double progress = timing_function_->GetValue(TimeUtil::Divide(t, duration)); return gfx::ScrollOffset( - gfx::Tween::FloatValueBetween( - progress, initial_value_.x(), target_value_.x()), - gfx::Tween::FloatValueBetween( - progress, initial_value_.y(), target_value_.y())); + gfx::Tween::FloatValueBetween(progress, initial_value_.x(), + target_value_.x()), + gfx::Tween::FloatValueBetween(progress, initial_value_.y(), + target_value_.y())); } base::TimeDelta ScrollOffsetAnimationCurve::Duration() const { @@ -181,8 +193,9 @@ std::unique_ptr<ScrollOffsetAnimationCurve> ScrollOffsetAnimationCurve::CloneToScrollOffsetAnimationCurve() const { std::unique_ptr<TimingFunction> timing_function( static_cast<TimingFunction*>(timing_function_->Clone().release())); - std::unique_ptr<ScrollOffsetAnimationCurve> curve_clone = - Create(target_value_, std::move(timing_function), duration_behavior_); + std::unique_ptr<ScrollOffsetAnimationCurve> curve_clone = base::WrapUnique( + new ScrollOffsetAnimationCurve(target_value_, std::move(timing_function), + animation_type_, duration_behavior_)); curve_clone->initial_value_ = initial_value_; curve_clone->total_animation_duration_ = total_animation_duration_; curve_clone->last_retarget_ = last_retarget_; @@ -192,7 +205,7 @@ ScrollOffsetAnimationCurve::CloneToScrollOffsetAnimationCurve() const { void ScrollOffsetAnimationCurve::SetAnimationDurationForTesting( base::TimeDelta duration) { - animation_duration_for_testing_ = duration.InSecondsF() * kDurationDivisor; + animation_duration_for_testing_ = duration.InSecondsF(); } static base::TimeDelta VelocityBasedDurationBound( @@ -227,6 +240,15 @@ static base::TimeDelta VelocityBasedDurationBound( void ScrollOffsetAnimationCurve::UpdateTarget( base::TimeDelta t, const gfx::ScrollOffset& new_target) { + DCHECK_NE(animation_type_, AnimationType::kLinear) + << "UpdateTarget is not supported on linear scroll animations."; + EaseInOutUpdateTarget(t, new_target); +} + +void ScrollOffsetAnimationCurve::EaseInOutUpdateTarget( + base::TimeDelta t, + const gfx::ScrollOffset& new_target) { + DCHECK_EQ(animation_type_, AnimationType::kEaseInOut); if (std::abs(MaximumDimension(target_value_.DeltaFrom(new_target))) < kEpsilon) { target_value_ = new_target; @@ -243,8 +265,8 @@ void ScrollOffsetAnimationCurve::UpdateTarget( // The last segment was of zero duration. if ((total_animation_duration_ - last_retarget_).is_zero()) { DCHECK_EQ(t, last_retarget_); - total_animation_duration_ = SegmentDuration(new_delta, duration_behavior_, - delayed_by, /*velocity*/ 0); + total_animation_duration_ = EaseInOutSegmentDuration( + new_delta, duration_behavior_.value(), delayed_by); target_value_ = new_target; return; } @@ -257,8 +279,8 @@ void ScrollOffsetAnimationCurve::UpdateTarget( // segment duration. This minimizes the "rubber-band" bouncing effect when // old_normalized_velocity is large and new_delta is small. base::TimeDelta new_duration = - std::min(SegmentDuration(new_delta, duration_behavior_, delayed_by, - /*velocity*/ 0), + std::min(EaseInOutSegmentDuration(new_delta, duration_behavior_.value(), + delayed_by), VelocityBasedDurationBound(old_delta, old_normalized_velocity, old_duration, new_delta)); @@ -281,7 +303,7 @@ void ScrollOffsetAnimationCurve::UpdateTarget( target_value_ = new_target; total_animation_duration_ = t + new_duration; last_retarget_ = t; - timing_function_ = EaseOutWithInitialVelocity(new_normalized_velocity); + timing_function_ = EaseInOutWithInitialVelocity(new_normalized_velocity); } } // namespace cc diff --git a/chromium/cc/animation/scroll_offset_animation_curve.h b/chromium/cc/animation/scroll_offset_animation_curve.h index 42b774b9c47..1438fe4bd74 100644 --- a/chromium/cc/animation/scroll_offset_animation_curve.h +++ b/chromium/cc/animation/scroll_offset_animation_curve.h @@ -26,7 +26,8 @@ class TimingFunction; class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve { public: - // Indicates how the animation duration should be computed. + // Indicates how the animation duration should be computed for Ease-in-out + // style scroll animation curves. enum class DurationBehavior { // Duration proportional to scroll delta; used for programmatic scrolls. DELTA_BASED, @@ -35,19 +36,23 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve { // Duration inversely proportional to scroll delta within certain bounds. // Used for mouse wheels, makes fast wheel flings feel "snappy" while // preserving smoothness of slow wheel movements. - INVERSE_DELTA, - // Constant velocity; used for autoscrolls. - CONSTANT_VELOCITY, + INVERSE_DELTA }; - static std::unique_ptr<ScrollOffsetAnimationCurve> Create( - const gfx::ScrollOffset& target_value, - std::unique_ptr<TimingFunction> timing_function, - DurationBehavior = DurationBehavior::DELTA_BASED); - static base::TimeDelta SegmentDuration(const gfx::Vector2dF& delta, - DurationBehavior behavior, - base::TimeDelta delayed_by, - float velocity); + // There is inherent delay in input processing; it may take many milliseconds + // from the time of user input to when when we're actually able to handle it + // here. This delay is represented by the |delayed_by| value. The way we have + // decided to factor this in is by reducing the duration of the resulting + // animation by this delayed amount. This also applies to + // LinearSegmentDuration. + static base::TimeDelta EaseInOutSegmentDuration( + const gfx::Vector2dF& delta, + DurationBehavior duration_behavior, + base::TimeDelta delayed_by); + + static base::TimeDelta LinearSegmentDuration(const gfx::Vector2dF& delta, + base::TimeDelta delayed_by, + float velocity); ScrollOffsetAnimationCurve(const ScrollOffsetAnimationCurve&) = delete; ~ScrollOffsetAnimationCurve() override; @@ -84,9 +89,19 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve { static void SetAnimationDurationForTesting(base::TimeDelta duration); private: - ScrollOffsetAnimationCurve(const gfx::ScrollOffset& target_value, - std::unique_ptr<TimingFunction> timing_function, - DurationBehavior); + friend class ScrollOffsetAnimationCurveFactory; + enum class AnimationType { kLinear, kEaseInOut }; + + // |duration_behavior| should be provided if (and only if) |animation_type| is + // kEaseInOut. + ScrollOffsetAnimationCurve( + const gfx::ScrollOffset& target_value, + std::unique_ptr<TimingFunction> timing_function, + AnimationType animation_type, + base::Optional<DurationBehavior> duration_behavior = base::nullopt); + + void EaseInOutUpdateTarget(base::TimeDelta t, + const gfx::ScrollOffset& new_target); gfx::ScrollOffset initial_value_; gfx::ScrollOffset target_value_; @@ -96,7 +111,10 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve { base::TimeDelta last_retarget_; std::unique_ptr<TimingFunction> timing_function_; - DurationBehavior duration_behavior_; + AnimationType animation_type_; + + // Only valid when |animation_type_| is EASE_IN_OUT. + base::Optional<DurationBehavior> duration_behavior_; bool has_set_initial_value_; diff --git a/chromium/cc/animation/scroll_offset_animation_curve_factory.cc b/chromium/cc/animation/scroll_offset_animation_curve_factory.cc new file mode 100644 index 00000000000..9efcda486a5 --- /dev/null +++ b/chromium/cc/animation/scroll_offset_animation_curve_factory.cc @@ -0,0 +1,76 @@ +// Copyright 2019 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. + +#include "cc/animation/scroll_offset_animation_curve_factory.h" + +#include "base/memory/ptr_util.h" +#include "cc/animation/timing_function.h" + +namespace cc { +namespace { +ScrollOffsetAnimationCurve::DurationBehavior GetDurationBehaviorFromScrollType( + ScrollOffsetAnimationCurveFactory::ScrollType scroll_type) { + switch (scroll_type) { + case ScrollOffsetAnimationCurveFactory::ScrollType::kProgrammatic: + return ScrollOffsetAnimationCurve::DurationBehavior::DELTA_BASED; + case ScrollOffsetAnimationCurveFactory::ScrollType::kKeyboard: + return ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT; + case ScrollOffsetAnimationCurveFactory::ScrollType::kMouseWheel: + return ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA; + case ScrollOffsetAnimationCurveFactory::ScrollType::kAutoScroll: + NOTREACHED(); + return ScrollOffsetAnimationCurve::DurationBehavior::DELTA_BASED; + } +} +} // namespace + +// static +std::unique_ptr<ScrollOffsetAnimationCurve> +ScrollOffsetAnimationCurveFactory::CreateAnimation( + const gfx::ScrollOffset& target_value, + ScrollType scroll_type) { + return (scroll_type == ScrollType::kAutoScroll) + ? CreateLinearAnimation(target_value) + : CreateEaseInOutAnimation( + target_value, + GetDurationBehaviorFromScrollType(scroll_type)); +} + +// static +std::unique_ptr<ScrollOffsetAnimationCurve> +ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + const gfx::ScrollOffset& target_value, + ScrollOffsetAnimationCurve::DurationBehavior duration_behavior) { + return CreateEaseInOutAnimation(target_value, duration_behavior); +} + +// static +std::unique_ptr<ScrollOffsetAnimationCurve> +ScrollOffsetAnimationCurveFactory::CreateLinearAnimationForTesting( + const gfx::ScrollOffset& target_value) { + return CreateLinearAnimation(target_value); +} + +// static +std::unique_ptr<ScrollOffsetAnimationCurve> +ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimation( + const gfx::ScrollOffset& target_value, + ScrollOffsetAnimationCurve::DurationBehavior duration_behavior) { + return base::WrapUnique(new ScrollOffsetAnimationCurve( + target_value, + CubicBezierTimingFunction::CreatePreset( + CubicBezierTimingFunction::EaseType::EASE_IN_OUT), + ScrollOffsetAnimationCurve::AnimationType::kEaseInOut, + duration_behavior)); +} + +// static +std::unique_ptr<ScrollOffsetAnimationCurve> +ScrollOffsetAnimationCurveFactory::CreateLinearAnimation( + const gfx::ScrollOffset& target_value) { + return base::WrapUnique(new ScrollOffsetAnimationCurve( + target_value, LinearTimingFunction::Create(), + ScrollOffsetAnimationCurve::AnimationType::kLinear)); +} +} // namespace cc diff --git a/chromium/cc/animation/scroll_offset_animation_curve_factory.h b/chromium/cc/animation/scroll_offset_animation_curve_factory.h new file mode 100644 index 00000000000..c3438ae2cb7 --- /dev/null +++ b/chromium/cc/animation/scroll_offset_animation_curve_factory.h @@ -0,0 +1,38 @@ +// Copyright 2019 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_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_FACTORY_H_ +#define CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_FACTORY_H_ + +#include "cc/animation/scroll_offset_animation_curve.h" + +namespace cc { +class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurveFactory { + public: + enum class ScrollType { kProgrammatic, kKeyboard, kMouseWheel, kAutoScroll }; + + static std::unique_ptr<ScrollOffsetAnimationCurve> CreateAnimation( + const gfx::ScrollOffset& target_value, + ScrollType scroll_type); + + static std::unique_ptr<ScrollOffsetAnimationCurve> + CreateEaseInOutAnimationForTesting( + const gfx::ScrollOffset& target_value, + ScrollOffsetAnimationCurve::DurationBehavior duration_behavior = + ScrollOffsetAnimationCurve::DurationBehavior::DELTA_BASED); + + static std::unique_ptr<ScrollOffsetAnimationCurve> + CreateLinearAnimationForTesting(const gfx::ScrollOffset& target_value); + + private: + static std::unique_ptr<ScrollOffsetAnimationCurve> CreateEaseInOutAnimation( + const gfx::ScrollOffset& target_value, + ScrollOffsetAnimationCurve::DurationBehavior duration_hint); + + static std::unique_ptr<ScrollOffsetAnimationCurve> CreateLinearAnimation( + const gfx::ScrollOffset& target_value); +}; +} // namespace cc + +#endif // CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_FACTORY_H_ diff --git a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc index 61bc09be18e..70790871d9d 100644 --- a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc +++ b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc @@ -4,10 +4,13 @@ #include "cc/animation/scroll_offset_animation_curve.h" +#include "cc/animation/scroll_offset_animation_curve_factory.h" #include "cc/animation/timing_function.h" #include "cc/test/geometry_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +using DurationBehavior = cc::ScrollOffsetAnimationCurve::DurationBehavior; + const double kConstantDuration = 9.0; const double kDurationDivisor = 60.0; const double kInverseDeltaMaxDuration = 12.0; @@ -18,9 +21,8 @@ namespace { TEST(ScrollOffsetAnimationCurveTest, DeltaBasedDuration) { gfx::ScrollOffset target_value(100.f, 200.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve->SetInitialValue(target_value); EXPECT_DOUBLE_EQ(0.0, curve->Duration().InSecondsF()); @@ -62,9 +64,8 @@ TEST(ScrollOffsetAnimationCurveTest, GetValue) { gfx::ScrollOffset initial_value(2.f, 40.f); gfx::ScrollOffset target_value(10.f, 20.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve->SetInitialValue(initial_value); base::TimeDelta duration = curve->Duration(); @@ -95,9 +96,8 @@ TEST(ScrollOffsetAnimationCurveTest, Clone) { gfx::ScrollOffset initial_value(2.f, 40.f); gfx::ScrollOffset target_value(10.f, 20.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value)); curve->SetInitialValue(initial_value); base::TimeDelta duration = curve->Duration(); @@ -129,15 +129,13 @@ TEST(ScrollOffsetAnimationCurveTest, Clone) { EXPECT_NEAR(37.4168f, value.y(), 0.0002f); } -TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) { +TEST(ScrollOffsetAnimationCurveTest, EaseInOutUpdateTarget) { gfx::ScrollOffset initial_value(0.f, 0.f); gfx::ScrollOffset target_value(0.f, 3600.f); double duration = kConstantDuration / kDurationDivisor; std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_value, CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT), - ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT)); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + target_value, DurationBehavior::CONSTANT)); curve->SetInitialValue(initial_value); EXPECT_NEAR(duration, curve->Duration().InSecondsF(), 0.0002f); EXPECT_NEAR( @@ -180,11 +178,8 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) { TEST(ScrollOffsetAnimationCurveTest, InverseDeltaDuration) { std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(0.f, 100.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA)); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(0.f, 100.f), DurationBehavior::INVERSE_DELTA)); curve->SetInitialValue(gfx::ScrollOffset()); double smallDeltaDuration = curve->Duration().InSecondsF(); @@ -205,14 +200,13 @@ TEST(ScrollOffsetAnimationCurveTest, InverseDeltaDuration) { EXPECT_EQ(largeDeltaDuration, curve->Duration().InSecondsF()); } -TEST(ScrollOffsetAnimationCurveTest, ConstantVelocityDuration) { +TEST(ScrollOffsetAnimationCurveTest, LinearAnimation) { // Testing autoscroll downwards for a scroller of length 1000px. gfx::ScrollOffset current_offset(0.f, 0.f); gfx::ScrollOffset target_offset(0.f, 1000.f); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - target_offset, LinearTimingFunction::Create(), - ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT_VELOCITY)); + ScrollOffsetAnimationCurveFactory::CreateLinearAnimationForTesting( + target_offset)); const float autoscroll_velocity = 800.f; // pixels per second. curve->SetInitialValue(current_offset, base::TimeDelta(), @@ -234,11 +228,8 @@ TEST(ScrollOffsetAnimationCurveTest, ConstantVelocityDuration) { TEST(ScrollOffsetAnimationCurveTest, CurveWithDelay) { std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(0.f, 100.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA)); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(0.f, 100.f), DurationBehavior::INVERSE_DELTA)); double duration_in_seconds = kInverseDeltaMaxDuration / kDurationDivisor; double delay_in_seconds = 0.02; double curve_duration = duration_in_seconds - delay_in_seconds; @@ -254,12 +245,10 @@ TEST(ScrollOffsetAnimationCurveTest, CurveWithDelay) { } TEST(ScrollOffsetAnimationCurveTest, CurveWithLargeDelay) { + DurationBehavior duration_hint = DurationBehavior::INVERSE_DELTA; std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(0.f, 100.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA)); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(0.f, 100.f), duration_hint)); curve->SetInitialValue(gfx::ScrollOffset(), base::TimeDelta::FromSecondsD(0.2)); EXPECT_EQ(0.f, curve->Duration().InSecondsF()); @@ -267,22 +256,19 @@ TEST(ScrollOffsetAnimationCurveTest, CurveWithLargeDelay) { // Re-targeting when animation duration is 0. curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.01), gfx::ScrollOffset(0.f, 300.f)); - double duration = - ScrollOffsetAnimationCurve::SegmentDuration( - gfx::Vector2dF(0.f, 200.f), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA, - base::TimeDelta::FromSecondsD(0.01), /*velocity*/ 0) - .InSecondsF(); + double duration = ScrollOffsetAnimationCurve::EaseInOutSegmentDuration( + gfx::Vector2dF(0.f, 200.f), duration_hint, + base::TimeDelta::FromSecondsD(0.01)) + .InSecondsF(); EXPECT_EQ(duration, curve->Duration().InSecondsF()); // Re-targeting before last_retarget_, the difference should be accounted for // in duration. curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.01), gfx::ScrollOffset(0.f, 500.f)); - duration = ScrollOffsetAnimationCurve::SegmentDuration( - gfx::Vector2dF(0.f, 500.f), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA, - base::TimeDelta::FromSecondsD(0.01), /*velocity*/ 0) + duration = ScrollOffsetAnimationCurve::EaseInOutSegmentDuration( + gfx::Vector2dF(0.f, 500.f), duration_hint, + base::TimeDelta::FromSecondsD(0.01)) .InSecondsF(); EXPECT_EQ(duration, curve->Duration().InSecondsF()); @@ -293,12 +279,10 @@ TEST(ScrollOffsetAnimationCurveTest, CurveWithLargeDelay) { // This test verifies that if the last segment duration is zero, ::UpdateTarget // simply updates the total animation duration see crbug.com/645317. TEST(ScrollOffsetAnimationCurveTest, UpdateTargetZeroLastSegmentDuration) { + DurationBehavior duration_hint = DurationBehavior::INVERSE_DELTA; std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(0.f, 100.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA)); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(0.f, 100.f), duration_hint)); double duration_in_seconds = kInverseDeltaMaxDuration / kDurationDivisor; double delay_in_seconds = 0.02; double curve_duration = duration_in_seconds - delay_in_seconds; @@ -312,10 +296,9 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTargetZeroLastSegmentDuration) { gfx::ScrollOffset(0.f, 200.f) - curve->GetValue(base::TimeDelta::FromSecondsD(0.05)); double expected_duration = - ScrollOffsetAnimationCurve::SegmentDuration( - gfx::Vector2dF(new_delta.x(), new_delta.y()), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA, - base::TimeDelta(), /*velocity*/ 0) + ScrollOffsetAnimationCurve::EaseInOutSegmentDuration( + gfx::Vector2dF(new_delta.x(), new_delta.y()), duration_hint, + base::TimeDelta()) .InSecondsF() + 0.05; curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.05), @@ -332,12 +315,10 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTargetZeroLastSegmentDuration) { // Re-target 3, this should set total_animation_duration based on new_delta. new_delta = gfx::ScrollOffset(0.f, 500.f) - curve->GetValue(base::TimeDelta::FromSecondsD(0.05)); - expected_duration = - ScrollOffsetAnimationCurve::SegmentDuration( - gfx::Vector2dF(new_delta.x(), new_delta.y()), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA, - base::TimeDelta::FromSecondsD(0.15), /*velocity*/ 0) - .InSecondsF(); + expected_duration = ScrollOffsetAnimationCurve::EaseInOutSegmentDuration( + gfx::Vector2dF(new_delta.x(), new_delta.y()), + duration_hint, base::TimeDelta::FromSecondsD(0.15)) + .InSecondsF(); curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.1), gfx::ScrollOffset(0.f, 500.f)); EXPECT_NEAR(expected_duration, curve->Duration().InSecondsF(), 0.0002f); diff --git a/chromium/cc/animation/scroll_offset_animations_impl.cc b/chromium/cc/animation/scroll_offset_animations_impl.cc index 5c7ff936114..bd2df46089c 100644 --- a/chromium/cc/animation/scroll_offset_animations_impl.cc +++ b/chromium/cc/animation/scroll_offset_animations_impl.cc @@ -10,6 +10,7 @@ #include "cc/animation/animation_id_provider.h" #include "cc/animation/animation_timeline.h" #include "cc/animation/element_animations.h" +#include "cc/animation/scroll_offset_animation_curve_factory.h" #include "cc/animation/single_keyframe_effect_animation.h" #include "cc/animation/timing_function.h" @@ -41,27 +42,26 @@ void ScrollOffsetAnimationsImpl::AutoScrollAnimationCreate( float autoscroll_velocity, base::TimeDelta animation_start_offset) { std::unique_ptr<ScrollOffsetAnimationCurve> curve = - ScrollOffsetAnimationCurve::Create( - target_offset, LinearTimingFunction::Create(), - ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT_VELOCITY); + ScrollOffsetAnimationCurveFactory::CreateAnimation( + target_offset, + ScrollOffsetAnimationCurveFactory::ScrollType::kAutoScroll); curve->SetInitialValue(current_offset, base::TimeDelta(), autoscroll_velocity); ScrollAnimationCreateInternal(element_id, std::move(curve), animation_start_offset); } -void ScrollOffsetAnimationsImpl::ScrollAnimationCreate( +void ScrollOffsetAnimationsImpl::MouseWheelScrollAnimationCreate( ElementId element_id, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset, base::TimeDelta delayed_by, base::TimeDelta animation_start_offset) { std::unique_ptr<ScrollOffsetAnimationCurve> curve = - ScrollOffsetAnimationCurve::Create( + ScrollOffsetAnimationCurveFactory::CreateAnimation( target_offset, - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT), - ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA); + ScrollOffsetAnimationCurveFactory::ScrollType::kMouseWheel); + curve->SetInitialValue(current_offset, delayed_by); ScrollAnimationCreateInternal(element_id, std::move(curve), animation_start_offset); diff --git a/chromium/cc/animation/scroll_offset_animations_impl.h b/chromium/cc/animation/scroll_offset_animations_impl.h index 4371deed459..3f5b8b3ad27 100644 --- a/chromium/cc/animation/scroll_offset_animations_impl.h +++ b/chromium/cc/animation/scroll_offset_animations_impl.h @@ -41,11 +41,11 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl // |delayed_by| shrinks the duration of the // animation. |animation_start_offset| causes us to start the animation // partway through. - void ScrollAnimationCreate(ElementId element_id, - const gfx::ScrollOffset& target_offset, - const gfx::ScrollOffset& current_offset, - base::TimeDelta delayed_by, - base::TimeDelta animation_start_offset); + void MouseWheelScrollAnimationCreate(ElementId element_id, + const gfx::ScrollOffset& target_offset, + const gfx::ScrollOffset& current_offset, + base::TimeDelta delayed_by, + base::TimeDelta animation_start_offset); bool ScrollAnimationUpdateTarget(ElementId element_id, const gfx::Vector2dF& scroll_delta, @@ -75,6 +75,8 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl base::TimeTicks animation_start_time, std::unique_ptr<AnimationCurve> curve) override { } + void NotifyLocalTimeUpdated( + base::Optional<base::TimeDelta> local_time) override {} bool IsAnimating() const; diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h index 66b39d562fc..d3003e90b69 100644 --- a/chromium/cc/animation/scroll_timeline.h +++ b/chromium/cc/animation/scroll_timeline.h @@ -22,6 +22,10 @@ class ScrollTree; // https://wicg.github.io/scroll-animations/#scrolltimeline-interface. class CC_ANIMATION_EXPORT ScrollTimeline { public: + // cc does not know about writing modes. The ScrollDirection below is + // converted using blink::scroll_timeline_util::ConvertOrientation which takes + // the spec-compliant ScrollDirection enumeration. + // https://drafts.csswg.org/scroll-animations/#scrolldirection-enumeration enum ScrollDirection { ScrollUp, ScrollDown, diff --git a/chromium/cc/animation/single_keyframe_effect_animation.cc b/chromium/cc/animation/single_keyframe_effect_animation.cc index a467e5ee4e3..bbc0cfa7fd3 100644 --- a/chromium/cc/animation/single_keyframe_effect_animation.cc +++ b/chromium/cc/animation/single_keyframe_effect_animation.cc @@ -95,13 +95,16 @@ void SingleKeyframeEffectAnimation::AbortKeyframeModel(int keyframe_model_id) { GetKeyframeEffect()->id()); } -bool SingleKeyframeEffectAnimation::NotifyKeyframeModelFinishedForTesting( +void SingleKeyframeEffectAnimation::NotifyKeyframeModelFinishedForTesting( + int timeline_id, + int keyframe_model_id, TargetProperty::Type target_property, int group_id) { - AnimationEvent event(AnimationEvent::FINISHED, - GetKeyframeEffect()->element_id(), group_id, - target_property, base::TimeTicks()); - return GetKeyframeEffect()->NotifyKeyframeModelFinished(event); + AnimationEvent event( + AnimationEvent::FINISHED, + {timeline_id, id(), GetKeyframeEffect()->id(), keyframe_model_id}, + group_id, target_property, base::TimeTicks()); + DispatchAndDelegateAnimationEvent(event); } KeyframeModel* SingleKeyframeEffectAnimation::GetKeyframeModel( diff --git a/chromium/cc/animation/single_keyframe_effect_animation.h b/chromium/cc/animation/single_keyframe_effect_animation.h index a79566ae28e..68eab8495fb 100644 --- a/chromium/cc/animation/single_keyframe_effect_animation.h +++ b/chromium/cc/animation/single_keyframe_effect_animation.h @@ -50,7 +50,9 @@ class CC_ANIMATION_EXPORT SingleKeyframeEffectAnimation : public Animation { virtual void RemoveKeyframeModel(int keyframe_model_id); void AbortKeyframeModel(int keyframe_model_id); - bool NotifyKeyframeModelFinishedForTesting( + void NotifyKeyframeModelFinishedForTesting( + int timeline_id, + int keyframe_model_id, TargetProperty::Type target_property, int group_id); KeyframeModel* GetKeyframeModel(TargetProperty::Type target_property) const; diff --git a/chromium/cc/animation/worklet_animation.cc b/chromium/cc/animation/worklet_animation.cc index a6d109fac1b..811b9e41337 100644 --- a/chromium/cc/animation/worklet_animation.cc +++ b/chromium/cc/animation/worklet_animation.cc @@ -5,7 +5,9 @@ #include "cc/animation/worklet_animation.h" #include <utility> +#include "cc/animation/animation_delegate.h" #include "cc/animation/animation_id_provider.h" +#include "cc/animation/animation_timeline.h" #include "cc/animation/keyframe_effect.h" #include "cc/animation/scroll_timeline.h" #include "cc/trees/animation_effect_timings.h" @@ -50,6 +52,7 @@ WorkletAnimation::WorkletAnimation( options_(std::move(options)), effect_timings_(std::move(effect_timings)), local_time_(base::nullopt), + last_synced_local_time_(base::nullopt), start_time_(base::nullopt), last_current_time_(base::nullopt), has_pending_tree_lock_(false), @@ -107,6 +110,19 @@ void WorkletAnimation::Tick(base::TimeTicks monotonic_time) { keyframe_effect()->Tick(monotonic_time); } +void WorkletAnimation::UpdateState(bool start_ready_animations, + AnimationEvents* events) { + Animation::UpdateState(start_ready_animations, events); + if (last_synced_local_time_ != local_time_) { + AnimationEvent event(animation_timeline()->id(), id_, local_time_); + // TODO(http://crbug.com/1013654): Instead of pushing multiple events per + // single main frame, push just the recent one to be handled by next main + // frame. + events->events_.push_back(event); + last_synced_local_time_ = local_time_; + } +} + void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, base::TimeTicks monotonic_time, const ScrollTree& scroll_tree, @@ -131,6 +147,9 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, DCHECK(is_timeline_active || state_ == State::REMOVED); + // TODO(https://crbug.com/1011138): Initialize current_time to null if the + // timeline is inactive. It might be inactive here when state is + // State::REMOVED. base::Optional<base::TimeDelta> current_time = CurrentTime(monotonic_time, scroll_tree, is_active_tree); @@ -141,6 +160,8 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, if (!is_timeline_active) current_time = last_current_time_; + // TODO(https://crbug.com/1011138): Do not early exit if state is + // State::REMOVED. The animation must be removed in this case. if (!current_time) return; last_current_time_ = current_time; diff --git a/chromium/cc/animation/worklet_animation.h b/chromium/cc/animation/worklet_animation.h index 508c0be4cf4..84e52079011 100644 --- a/chromium/cc/animation/worklet_animation.h +++ b/chromium/cc/animation/worklet_animation.h @@ -64,6 +64,9 @@ class CC_ANIMATION_EXPORT WorkletAnimation final void Tick(base::TimeTicks monotonic_time) override; + void UpdateState(bool start_ready_animations, + AnimationEvents* events) override; + void UpdateInputState(MutatorInputState* input_state, base::TimeTicks monotonic_time, const ScrollTree& scroll_tree, @@ -130,7 +133,7 @@ class CC_ANIMATION_EXPORT WorkletAnimation final } // Updates the playback rate of the Impl thread instance. - // Called by the UI thread WorletAnimation instance during commit. + // Called by the UI thread WorkletAnimation instance during commit. void SetPlaybackRate(double playback_rate); bool IsTimelineActive(const ScrollTree& scroll_tree, @@ -163,6 +166,11 @@ class CC_ANIMATION_EXPORT WorkletAnimation final // The value comes from the user script that runs inside the animation worklet // global scope. base::Optional<base::TimeDelta> local_time_; + // Local time passed to the main thread worklet animation to update its + // keyframe effect. We only set the most recent local time, meaning that if + // there are multiple compositor frames without a single main frame only + // the local time associated with the latest frame is sent to the main thread. + base::Optional<base::TimeDelta> last_synced_local_time_; base::Optional<base::TimeTicks> start_time_; diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc index 4d0e61ea073..cd33dee5afa 100644 --- a/chromium/cc/animation/worklet_animation_unittest.cc +++ b/chromium/cc/animation/worklet_animation_unittest.cc @@ -112,6 +112,52 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWhenTicking) { expected_opacity); } +// Test generation of animation events by worklet animations. +TEST_F(WorkletAnimationTest, AnimationEventLocalTimeUpdate) { + AttachWorkletAnimation(); + + base::Optional<base::TimeDelta> local_time = base::TimeDelta::FromSecondsD(1); + MutatorOutputState::AnimationState state(worklet_animation_id_); + state.local_times.push_back(local_time); + worklet_animation_->SetOutputState(state); + + std::unique_ptr<MutatorEvents> mutator_events = host_->CreateEvents(); + auto* animation_events = static_cast<AnimationEvents*>(mutator_events.get()); + worklet_animation_->UpdateState(true, animation_events); + + // One event is generated as a result of update state. + EXPECT_EQ(1u, animation_events->events_.size()); + AnimationEvent event = animation_events->events_[0]; + EXPECT_EQ(AnimationEvent::TIME_UPDATED, event.type); + EXPECT_EQ(worklet_animation_->id(), event.uid.animation_id); + EXPECT_EQ(local_time, event.local_time); + + // If the state is not updated no more events is generated. + mutator_events = host_->CreateEvents(); + animation_events = static_cast<AnimationEvents*>(mutator_events.get()); + worklet_animation_->UpdateState(true, animation_events); + EXPECT_EQ(0u, animation_events->events_.size()); + + // If local time is set to the same value no event is generated. + worklet_animation_->SetOutputState(state); + mutator_events = host_->CreateEvents(); + animation_events = static_cast<AnimationEvents*>(mutator_events.get()); + worklet_animation_->UpdateState(true, animation_events); + EXPECT_EQ(0u, animation_events->events_.size()); + + // If local time is set to null value, an animation event with null local + // time is generated. + state.local_times.clear(); + local_time = base::nullopt; + state.local_times.push_back(local_time); + worklet_animation_->SetOutputState(state); + mutator_events = host_->CreateEvents(); + animation_events = static_cast<AnimationEvents*>(mutator_events.get()); + worklet_animation_->UpdateState(true, animation_events); + EXPECT_EQ(1u, animation_events->events_.size()); + EXPECT_EQ(local_time, animation_events->events_[0].local_time); +} + TEST_F(WorkletAnimationTest, CurrentTimeCorrectlyUsesScrollTimeline) { auto scroll_timeline = std::make_unique<MockScrollTimeline>(); EXPECT_CALL(*scroll_timeline, IsActive(_, _)).WillRepeatedly(Return(true)); diff --git a/chromium/cc/base/devtools_instrumentation.cc b/chromium/cc/base/devtools_instrumentation.cc index 667b0eb8414..72b7be7a999 100644 --- a/chromium/cc/base/devtools_instrumentation.cc +++ b/chromium/cc/base/devtools_instrumentation.cc @@ -37,6 +37,7 @@ const char kLayerId[] = "layerId"; const char kLayerTreeId[] = "layerTreeId"; const char kPixelRefId[] = "pixelRefId"; +const char kImageUploadTask[] = "ImageUploadTask"; const char kImageDecodeTask[] = "ImageDecodeTask"; const char kBeginFrame[] = "BeginFrame"; const char kNeedsBeginFrameChanged[] = "NeedsBeginFrameChanged"; @@ -50,14 +51,47 @@ const char kCompositeLayers[] = "CompositeLayers"; const char kPaintSetup[] = "PaintSetup"; const char kUpdateLayer[] = "UpdateLayer"; +ScopedImageUploadTask::ScopedImageUploadTask(const void* image_ptr, + ImageType image_type) + : ScopedImageTask(image_type) { + TRACE_EVENT_BEGIN1(internal::CategoryName::kTimeline, + internal::kImageUploadTask, internal::kPixelRefId, + reinterpret_cast<uint64_t>(image_ptr)); +} + +ScopedImageUploadTask::~ScopedImageUploadTask() { + TRACE_EVENT_END0(internal::CategoryName::kTimeline, + internal::kImageUploadTask); + if (suppress_metrics_) + return; + + auto duration = base::TimeTicks::Now() - start_time_; + switch (image_type_) { + case ImageType::kWebP: + UmaHistogramCustomMicrosecondsTimes( + "Renderer4.ImageUploadTaskDurationUs.WebP", duration, hist_min_, + hist_max_, bucket_count_); + break; + case ImageType::kJpeg: + UmaHistogramCustomMicrosecondsTimes( + "Renderer4.ImageUploadTaskDurationUs.Jpeg", duration, hist_min_, + hist_max_, bucket_count_); + break; + case ImageType::kOther: + UmaHistogramCustomMicrosecondsTimes( + "Renderer4.ImageUploadTaskDurationUs.Other", duration, hist_min_, + hist_max_, bucket_count_); + break; + } +} + ScopedImageDecodeTask::ScopedImageDecodeTask(const void* image_ptr, DecodeType decode_type, TaskType task_type, ImageType image_type) - : decode_type_(decode_type), - task_type_(task_type), - start_time_(base::TimeTicks::Now()), - image_type_(image_type) { + : ScopedImageTask(image_type), + decode_type_(decode_type), + task_type_(task_type) { TRACE_EVENT_BEGIN1(internal::CategoryName::kTimeline, internal::kImageDecodeTask, internal::kPixelRefId, reinterpret_cast<uint64_t>(image_ptr)); @@ -69,37 +103,34 @@ ScopedImageDecodeTask::~ScopedImageDecodeTask() { if (suppress_metrics_) return; - const uint32_t bucket_count = 50; - base::TimeDelta min = base::TimeDelta::FromMicroseconds(1); - base::TimeDelta max = base::TimeDelta::FromMilliseconds(1000); auto duration = base::TimeTicks::Now() - start_time_; switch (image_type_) { case ImageType::kWebP: RecordMicrosecondTimesUmaByDecodeType( - "Renderer4.ImageDecodeTaskDurationUs.WebP", duration, min, max, - bucket_count, decode_type_); + "Renderer4.ImageDecodeTaskDurationUs.WebP", duration, hist_min_, + hist_max_, bucket_count_, decode_type_); break; case ImageType::kJpeg: RecordMicrosecondTimesUmaByDecodeType( - "Renderer4.ImageDecodeTaskDurationUs.Jpeg", duration, min, max, - bucket_count, decode_type_); + "Renderer4.ImageDecodeTaskDurationUs.Jpeg", duration, hist_min_, + hist_max_, bucket_count_, decode_type_); break; case ImageType::kOther: RecordMicrosecondTimesUmaByDecodeType( - "Renderer4.ImageDecodeTaskDurationUs.Other", duration, min, max, - bucket_count, decode_type_); + "Renderer4.ImageDecodeTaskDurationUs.Other", duration, hist_min_, + hist_max_, bucket_count_, decode_type_); break; } switch (task_type_) { case kInRaster: RecordMicrosecondTimesUmaByDecodeType( - "Renderer4.ImageDecodeTaskDurationUs", duration, min, max, - bucket_count, decode_type_); + "Renderer4.ImageDecodeTaskDurationUs", duration, hist_min_, hist_max_, + bucket_count_, decode_type_); break; case kOutOfRaster: RecordMicrosecondTimesUmaByDecodeType( - "Renderer4.ImageDecodeTaskDurationUs.OutOfRaster", duration, min, max, - bucket_count, decode_type_); + "Renderer4.ImageDecodeTaskDurationUs.OutOfRaster", duration, + hist_min_, hist_max_, bucket_count_, decode_type_); break; } } diff --git a/chromium/cc/base/devtools_instrumentation.h b/chromium/cc/base/devtools_instrumentation.h index f47b1278588..12e4c9c7016 100644 --- a/chromium/cc/base/devtools_instrumentation.h +++ b/chromium/cc/base/devtools_instrumentation.h @@ -64,12 +64,45 @@ class CC_BASE_EXPORT ScopedLayerTask { const char* event_name_; }; -class CC_BASE_EXPORT ScopedImageDecodeTask { +class CC_BASE_EXPORT ScopedImageTask { public: - enum DecodeType { kSoftware, kGpu }; - enum TaskType { kInRaster, kOutOfRaster }; enum ImageType { kWebP, kJpeg, kOther }; + ScopedImageTask(ImageType image_type) + : image_type_(image_type), start_time_(base::TimeTicks::Now()) {} + ScopedImageTask(const ScopedImageTask&) = delete; + ~ScopedImageTask() = default; + ScopedImageTask& operator=(const ScopedImageTask&) = delete; + + // Prevents logging duration metrics. Used in cases where a task performed + // uninteresting work or was terminated early. + void SuppressMetrics() { suppress_metrics_ = true; } + + protected: + bool suppress_metrics_ = false; + const ImageType image_type_; + const base::TimeTicks start_time_; + + // UMA histogram parameters + const uint32_t bucket_count_ = 50; + base::TimeDelta hist_min_ = base::TimeDelta::FromMicroseconds(1); + base::TimeDelta hist_max_ = base::TimeDelta::FromMilliseconds(1000); +}; + +class CC_BASE_EXPORT ScopedImageUploadTask : public ScopedImageTask { + public: + ScopedImageUploadTask(const void* image_ptr, ImageType image_type); + ScopedImageUploadTask(const ScopedImageUploadTask&) = delete; + ~ScopedImageUploadTask(); + + ScopedImageUploadTask& operator=(const ScopedImageUploadTask&) = delete; +}; + +class CC_BASE_EXPORT ScopedImageDecodeTask : public ScopedImageTask { + public: + enum TaskType { kInRaster, kOutOfRaster }; + enum DecodeType { kSoftware, kGpu }; + ScopedImageDecodeTask(const void* image_ptr, DecodeType decode_type, TaskType task_type, @@ -79,16 +112,9 @@ class CC_BASE_EXPORT ScopedImageDecodeTask { ScopedImageDecodeTask& operator=(const ScopedImageDecodeTask&) = delete; - // Prevents logging duration metrics. Used in cases where a task performed - // uninteresting work or was terminated early. - void SuppressMetrics() { suppress_metrics_ = true; } - private: const DecodeType decode_type_; const TaskType task_type_; - const base::TimeTicks start_time_; - bool suppress_metrics_ = false; - const ImageType image_type_; }; class CC_BASE_EXPORT ScopedLayerTreeTask { diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc index c16f4fbec8b..2edd38e2e0b 100644 --- a/chromium/cc/debug/debug_colors.cc +++ b/chromium/cc/debug/debug_colors.cc @@ -276,6 +276,17 @@ SkColor DebugColors::NonFastScrollableRectFillColor() { return SkColorSetARGB(30, 238, 163, 59); } +// Main-thread scrolling reason rects in yellow-orange. +SkColor DebugColors::MainThreadScrollingReasonRectBorderColor() { + return SkColorSetARGB(255, 200, 100, 0); +} +int DebugColors::MainThreadScrollingReasonRectBorderWidth() { + return 2; +} +SkColor DebugColors::MainThreadScrollingReasonRectFillColor() { + return SkColorSetARGB(30, 200, 100, 0); +} + // Animation bounds are lime-green. SkColor DebugColors::LayerAnimationBoundsBorderColor() { return SkColorSetARGB(255, 112, 229, 0); diff --git a/chromium/cc/debug/debug_colors.h b/chromium/cc/debug/debug_colors.h index 8e13fcbb8d4..639656a889e 100644 --- a/chromium/cc/debug/debug_colors.h +++ b/chromium/cc/debug/debug_colors.h @@ -104,6 +104,10 @@ class CC_DEBUG_EXPORT DebugColors { static int NonFastScrollableRectBorderWidth(); static SkColor NonFastScrollableRectFillColor(); + static SkColor MainThreadScrollingReasonRectBorderColor(); + static int MainThreadScrollingReasonRectBorderWidth(); + static SkColor MainThreadScrollingReasonRectFillColor(); + static SkColor LayerAnimationBoundsBorderColor(); static int LayerAnimationBoundsBorderWidth(); static SkColor LayerAnimationBoundsFillColor(); diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc index 8c154cc8f55..66d1e134c43 100644 --- a/chromium/cc/debug/layer_tree_debug_state.cc +++ b/chromium/cc/debug/layer_tree_debug_state.cc @@ -21,6 +21,7 @@ LayerTreeDebugState::LayerTreeDebugState() show_wheel_event_handler_rects(false), show_scroll_event_handler_rects(false), show_non_fast_scrollable_rects(false), + show_main_thread_scrolling_reason_rects(false), show_layer_animation_bounds_rects(false), slow_down_raster_scale_factor(0), rasterize_only_visible_content(false), @@ -50,6 +51,7 @@ bool LayerTreeDebugState::ShowHudRects() const { show_surface_damage_rects || show_screen_space_rects || show_touch_event_handler_rects || show_wheel_event_handler_rects || show_scroll_event_handler_rects || show_non_fast_scrollable_rects || + show_main_thread_scrolling_reason_rects || show_layer_animation_bounds_rects || show_layout_shift_regions; } @@ -71,6 +73,8 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a, a.show_wheel_event_handler_rects == b.show_wheel_event_handler_rects && a.show_scroll_event_handler_rects == b.show_scroll_event_handler_rects && a.show_non_fast_scrollable_rects == b.show_non_fast_scrollable_rects && + a.show_main_thread_scrolling_reason_rects == + b.show_main_thread_scrolling_reason_rects && a.show_layer_animation_bounds_rects == b.show_layer_animation_bounds_rects && a.slow_down_raster_scale_factor == b.slow_down_raster_scale_factor && @@ -96,6 +100,8 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a, r.show_wheel_event_handler_rects |= b.show_wheel_event_handler_rects; r.show_scroll_event_handler_rects |= b.show_scroll_event_handler_rects; r.show_non_fast_scrollable_rects |= b.show_non_fast_scrollable_rects; + r.show_main_thread_scrolling_reason_rects |= + b.show_main_thread_scrolling_reason_rects; r.show_layer_animation_bounds_rects |= b.show_layer_animation_bounds_rects; if (b.slow_down_raster_scale_factor) diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h index 50dd2308edb..db18711a3f0 100644 --- a/chromium/cc/debug/layer_tree_debug_state.h +++ b/chromium/cc/debug/layer_tree_debug_state.h @@ -41,6 +41,7 @@ class CC_DEBUG_EXPORT LayerTreeDebugState { bool show_wheel_event_handler_rects; bool show_scroll_event_handler_rects; bool show_non_fast_scrollable_rects; + bool show_main_thread_scrolling_reason_rects; bool show_layer_animation_bounds_rects; int slow_down_raster_scale_factor; diff --git a/chromium/cc/input/README.md b/chromium/cc/input/README.md new file mode 100644 index 00000000000..a5337e9cb94 --- /dev/null +++ b/chromium/cc/input/README.md @@ -0,0 +1,106 @@ +# cc/input + +This directory contains code specific to input handling and scrolling in in the +compositor. + +The renderer compositor typically receives, on the compositor thread, all input +events arriving from the browser. In some cases, the compositor can process +input without consulting the main thread. We strive for this since it means +input doesn't have to block on a potentially busy main thread. + +If the compositor determines that Blink must be consulted to correctly handle +the event. e.g. For detailed hit-testing or correct paint output. In these +cases, the event will be posted to the Blink main thread. + +See [InputHandlerProxy](../../ui/events/blink/input_handler_proxy.cc) for the +entry point to this code. + +## Scrolling + +### Viewport + +Viewport scrolling is special compared to scrolling regular ScrollNodes. The +main difference is that the viewport is composed of two scrollers: the inner +and outer scrollers. These correspond to the visual and layout viewports in +Blink, respectively. + +The reason for this composition is pinch-zoom; when a user zooms in, the layout +viewport remains unchanged (position: fixed elements don't stick to the user's +screen) and the user can pan the visual viewport within the layout viewport. +See [this demo](http://bokand.github.io/viewport/index.html) for a visual, +interactive example. + +This arrangement requires some special distribution and bubbling of +scroll delta. Additionally, viewport scrolling is also responsible for +overscroll effects like rubber-banding and gestural-navigation as well as URL +bar movement on Android. + +Notably, that the UI compositor as well as renderer compositors for +out-of-process iframes will not have an inner or an outer viewport scroll node. + +#### Scroll Chain Structure + +The inner viewport scroll node is always the first and only child of the root +scroll node; it is the top-level scrollable node in the scroll tree. The outer +viewport will typically be the one child of the inner viewport scroll node; +however, this may be changed on certain pages. This happens when a page is +given a non-document root scroller. For more information the root +scroller see the +[README](../../third_party/blink/renderer/core/page/scrolling/README.md) in +Blink's core/page/scrolling directory. + +#### Scrolling the Viewport + +Viewport scroll nodes are typically not scrolled directly, like other scroll +nodes. Instead, they're scrolled by using the cc::Viewport object. cc::Viewport +is an object that's lives on the LayerTreeHostImpl and operates on the active +tree's inner and outer scroll nodes. It encapsulates the bubbling, +distribution, top controls, etc. behavior we associate with scrolling the +viewport. + +We use the outer viewport scroll node to represent cc::Viewport scrolling in +cases where the scroller must be represented by a scroll node (e.g. +CurrentlyScrollingNode). In these cases we make sure to check for the outer +scroll node use cc::Viewport instead. This means that in cases where we want +"viewport" scrolling, we must use the outer viewport scroll node. This can also +happen when the inner viewport is reached in the scroll chain, for example, by +scroll bubbling from a `position: fixed` subtree; we use the outer scroll node +to scroll this case. + +The scroll chain is terminated once we've scrolled the cc::Viewport. i.e. +scrolls don't bubble above the cc::Viewport. + +#### Root Scroller Nuances + +When we have a non-document root scroller, there are cases where we +specifically wish to scroll only the inner viewport. For example, when a +scroll started from a non-descendant of the root scroller or a `position: +fixed` element and bubbles up. In these cases, we shouldn't scroll using +cc::Viewport because that would scroll the root scroller as well. Doing so +would create a difference in how scrolls chain based on which element is the +root scroller, something we must avoid for interop and compatibility reasons. + +This means that when we reach the inner viewport scroll node in the scroll +chain we need to know whether to use cc::Viewport or not. Blink sets the +|prevent\_viewport\_scrolling\_from\_inner| bit on the inner viewport scroll +node so that the compositor can know that scrolls bubbling to the inner +viewport should not use the cc::Viewport class. + +## Other Docs + +* [Blink Scrolling](../../third_party/blink/renderer/core/page/scrolling/README.md) + provides information about similar concepts in Blink and the web-platform. + +## Glossary + +### Inner Viewport + +Also called the "Visual Viewport" in web/Blink terminology. This is the +viewport the user actually sees and corresponds to the content visible in the +browser window. + +### Outer Viewport + +Also called the "Layout Viewport" in web/Blink terminology. This is the main +"content scroller" in a given page, typically the document (`<html>`) element. +This is the scroller to which position: fixed elements remain fixed to. diff --git a/chromium/cc/input/browser_controls_offset_manager.cc b/chromium/cc/input/browser_controls_offset_manager.cc index afbe9770086..fb59212a41d 100644 --- a/chromium/cc/input/browser_controls_offset_manager.cc +++ b/chromium/cc/input/browser_controls_offset_manager.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/numerics/ranges.h" #include "cc/input/browser_controls_offset_manager_client.h" #include "cc/trees/layer_tree_impl.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" @@ -38,10 +39,6 @@ BrowserControlsOffsetManager::BrowserControlsOffsetManager( float controls_show_threshold, float controls_hide_threshold) : client_(client), - animation_initialized_(false), - animation_start_value_(0.f), - animation_stop_value_(0.f), - animation_direction_(NO_ANIMATION), permitted_state_(BrowserControlsState::kBoth), accumulated_scroll_delta_(0.f), baseline_top_content_offset_(0.f), @@ -65,24 +62,43 @@ float BrowserControlsOffsetManager::ContentTopOffset() const { } float BrowserControlsOffsetManager::TopControlsShownRatio() const { - return client_->CurrentBrowserControlsShownRatio(); + return client_->CurrentTopControlsShownRatio(); } float BrowserControlsOffsetManager::TopControlsHeight() const { return client_->TopControlsHeight(); } +float BrowserControlsOffsetManager::TopControlsMinHeight() const { + return client_->TopControlsMinHeight(); +} + +float BrowserControlsOffsetManager::TopControlsMinShownRatio() const { + return TopControlsHeight() ? TopControlsMinHeight() / TopControlsHeight() + : 0.f; +} + float BrowserControlsOffsetManager::BottomControlsHeight() const { return client_->BottomControlsHeight(); } +float BrowserControlsOffsetManager::BottomControlsMinHeight() const { + return client_->BottomControlsMinHeight(); +} + +float BrowserControlsOffsetManager::BottomControlsMinShownRatio() const { + return BottomControlsHeight() + ? BottomControlsMinHeight() / BottomControlsHeight() + : 0.f; +} + float BrowserControlsOffsetManager::ContentBottomOffset() const { return BottomControlsHeight() > 0 ? BottomControlsShownRatio() * BottomControlsHeight() : 0.0f; } float BrowserControlsOffsetManager::BottomControlsShownRatio() const { - return TopControlsShownRatio(); + return client_->CurrentBottomControlsShownRatio(); } void BrowserControlsOffsetManager::UpdateBrowserControlsState( @@ -113,21 +129,28 @@ void BrowserControlsOffsetManager::UpdateBrowserControlsState( return; // Don't do anything if there is no change in offset. - float final_shown_ratio = 1.f; + float final_top_shown_ratio = 1.f; + float final_bottom_shown_ratio = 1.f; + AnimationDirection direction = SHOWING_CONTROLS; if (constraints == BrowserControlsState::kHidden || - current == BrowserControlsState::kHidden) - final_shown_ratio = 0.f; - if (final_shown_ratio == TopControlsShownRatio()) { - TRACE_EVENT_INSTANT0("cc", "Ratio Unchanged", TRACE_EVENT_SCOPE_THREAD); + current == BrowserControlsState::kHidden) { + final_top_shown_ratio = TopControlsMinShownRatio(); + final_bottom_shown_ratio = BottomControlsMinShownRatio(); + direction = HIDING_CONTROLS; + } + if (final_top_shown_ratio == TopControlsShownRatio() && + final_bottom_shown_ratio == BottomControlsShownRatio()) { + TRACE_EVENT_INSTANT0("cc", "Ratios Unchanged", TRACE_EVENT_SCOPE_THREAD); ResetAnimations(); return; } if (animate) { - SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS); + SetupAnimation(direction); } else { ResetAnimations(); - client_->SetCurrentBrowserControlsShownRatio(final_shown_ratio); + client_->SetCurrentBrowserControlsShownRatio(final_top_shown_ratio, + final_bottom_shown_ratio); } } @@ -139,6 +162,13 @@ BrowserControlsState BrowserControlsOffsetManager::PullConstraintForMainThread( return permitted_state_; } +void BrowserControlsOffsetManager::OnBrowserControlsParamsChanged( + bool animate_changes) { + // TODO(sinansahin): We should decide how to animate the controls at this + // point. If no animation is needed, we will need to snap to the final ratio, + // e.g. old min-height to 0. +} + void BrowserControlsOffsetManager::ScrollBegin() { if (pinch_gesture_active_) return; @@ -151,32 +181,57 @@ gfx::Vector2dF BrowserControlsOffsetManager::ScrollBy( const gfx::Vector2dF& pending_delta) { // If one or both of the top/bottom controls are showing, the shown ratio // needs to be computed. - float controls_height = - TopControlsHeight() ? TopControlsHeight() : BottomControlsHeight(); - - if (!controls_height) + if (!TopControlsHeight() && !BottomControlsHeight()) return pending_delta; if (pinch_gesture_active_) return pending_delta; - if (permitted_state_ == BrowserControlsState::kShown && pending_delta.y() > 0) - return pending_delta; - else if (permitted_state_ == BrowserControlsState::kHidden && - pending_delta.y() < 0) + if ((permitted_state_ == BrowserControlsState::kShown && + pending_delta.y() > 0) || + (permitted_state_ == BrowserControlsState::kHidden && + pending_delta.y() < 0)) return pending_delta; accumulated_scroll_delta_ += pending_delta.y(); + // We want to base our calculations on top or bottom controls. After consuming + // the scroll delta, we will calculate a shown ratio for the controls. The + // top controls have the priority because they need to visually be in sync + // with the web contents. + bool base_on_top_controls = TopControlsHeight(); + float old_top_offset = ContentTopOffset(); - float baseline_content_offset = TopControlsHeight() - ? baseline_top_content_offset_ : baseline_bottom_content_offset_; + float baseline_content_offset = base_on_top_controls + ? baseline_top_content_offset_ + : baseline_bottom_content_offset_; + // The top and bottom controls ratios can be calculated independently. + // However, we want the (normalized) ratios to be equal when scrolling. + // Having normalized ratios in this context means the top and bottom controls + // reach the min and max ratios at the same time when scrolling or during + // the usual show/hide animations, but they can have different shown ratios at + // any time. + float shown_ratio = + (baseline_content_offset - accumulated_scroll_delta_) / + (base_on_top_controls ? TopControlsHeight() : BottomControlsHeight()); + + float min_ratio = base_on_top_controls ? TopControlsMinShownRatio() + : BottomControlsMinShownRatio(); + float normalized_shown_ratio = + (base::ClampToRange(shown_ratio, min_ratio, 1.f) - min_ratio) / + (1.f - min_ratio); + // Even though the real shown ratios (shown height / total height) of the top + // and bottom controls can be different, they share the same + // relative/normalized ratio to keep them in sync. client_->SetCurrentBrowserControlsShownRatio( - (baseline_content_offset - accumulated_scroll_delta_) / controls_height); + TopControlsMinShownRatio() + + normalized_shown_ratio * (1.f - TopControlsMinShownRatio()), + BottomControlsMinShownRatio() + + normalized_shown_ratio * (1.f - BottomControlsMinShownRatio())); // If the controls are fully visible, treat the current position as the // new baseline even if the gesture didn't end. - if (TopControlsShownRatio() == 1.f) + if (TopControlsShownRatio() == 1.f && BottomControlsShownRatio() == 1.f) ResetBaseline(); ResetAnimations(); @@ -216,40 +271,30 @@ void BrowserControlsOffsetManager::MainThreadHasStoppedFlinging() { gfx::Vector2dF BrowserControlsOffsetManager::Animate( base::TimeTicks monotonic_time) { - if (!has_animation() || !client_->HaveRootScrollNode()) + if (!HasAnimation() || !client_->HaveRootScrollNode()) return gfx::Vector2dF(); - if (!animation_initialized_) { - // Setup the animation start and time here so that they use the same clock - // as frame times. This is helpful for tests that mock time. - animation_start_time_ = monotonic_time; - animation_stop_time_ = - animation_start_time_ + - base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs); - animation_initialized_ = true; - } - float old_offset = ContentTopOffset(); - float new_ratio = gfx::Tween::ClampedFloatValueBetween( - monotonic_time, animation_start_time_, animation_start_value_, - animation_stop_time_, animation_stop_value_); - client_->SetCurrentBrowserControlsShownRatio(new_ratio); - - if (IsAnimationComplete(new_ratio)) - ResetAnimations(); + float new_top_ratio = top_controls_animation_.Tick(monotonic_time); + if (new_top_ratio < 0) + new_top_ratio = TopControlsShownRatio(); + float new_bottom_ratio = bottom_controls_animation_.Tick(monotonic_time); + if (new_bottom_ratio < 0) + new_bottom_ratio = BottomControlsShownRatio(); + client_->SetCurrentBrowserControlsShownRatio(new_top_ratio, new_bottom_ratio); gfx::Vector2dF scroll_delta(0.f, ContentTopOffset() - old_offset); return scroll_delta; } -void BrowserControlsOffsetManager::ResetAnimations() { - animation_initialized_ = false; - animation_start_time_ = base::TimeTicks(); - animation_start_value_ = 0.f; - animation_stop_time_ = base::TimeTicks(); - animation_stop_value_ = 0.f; +bool BrowserControlsOffsetManager::HasAnimation() { + return top_controls_animation_.IsInitialized() || + bottom_controls_animation_.IsInitialized(); +} - animation_direction_ = NO_ANIMATION; +void BrowserControlsOffsetManager::ResetAnimations() { + top_controls_animation_.Reset(); + bottom_controls_animation_.Reset(); } void BrowserControlsOffsetManager::SetupAnimation( @@ -258,32 +303,51 @@ void BrowserControlsOffsetManager::SetupAnimation( DCHECK(direction != HIDING_CONTROLS || TopControlsShownRatio() > 0.f); DCHECK(direction != SHOWING_CONTROLS || TopControlsShownRatio() < 1.f); - if (has_animation() && animation_direction_ == direction) + if (top_controls_animation_.IsInitialized() && + top_controls_animation_.Direction() == direction && + bottom_controls_animation_.IsInitialized() && + bottom_controls_animation_.Direction() == direction) return; if (!TopControlsHeight() && !BottomControlsHeight()) { - client_->SetCurrentBrowserControlsShownRatio( - direction == HIDING_CONTROLS ? 0.f : 1.f); + float ratio = direction == HIDING_CONTROLS ? 0.f : 1.f; + client_->SetCurrentBrowserControlsShownRatio(ratio, ratio); return; } - animation_start_value_ = TopControlsShownRatio(); + top_controls_animation_.SetBounds(TopControlsMinShownRatio(), 1.f); + bottom_controls_animation_.SetBounds(BottomControlsMinShownRatio(), 1.f); + + // Providing artificially larger/smaller stop ratios to make the animation + // faster if the start ratio is closer to stop ratio. + const float max_stop_ratio = direction == SHOWING_CONTROLS ? 1 : -1; + float top_start_ratio = TopControlsShownRatio(); + float top_stop_ratio = top_start_ratio + max_stop_ratio; + top_controls_animation_.Initialize(direction, top_start_ratio, + top_stop_ratio); - const float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1); - animation_stop_value_ = animation_start_value_ + max_ending_ratio; + float bottom_start_ratio = BottomControlsShownRatio(); + float bottom_stop_ratio = bottom_start_ratio + max_stop_ratio; + bottom_controls_animation_.Initialize(direction, bottom_start_ratio, + bottom_stop_ratio); - animation_direction_ = direction; client_->DidChangeBrowserControlsPosition(); } void BrowserControlsOffsetManager::StartAnimationIfNecessary() { - if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f) + if ((TopControlsShownRatio() == TopControlsMinShownRatio() || + TopControlsShownRatio() == 1.f) && + (BottomControlsShownRatio() == BottomControlsMinShownRatio() || + BottomControlsShownRatio() == 1.f)) return; - if (TopControlsShownRatio() >= 1.f - controls_hide_threshold_) { + float normalized_top_ratio = + (TopControlsShownRatio() - TopControlsMinShownRatio()) / + (1.f - TopControlsMinShownRatio()); + if (normalized_top_ratio >= 1.f - controls_hide_threshold_) { // If we're showing so much that the hide threshold won't trigger, show. SetupAnimation(SHOWING_CONTROLS); - } else if (TopControlsShownRatio() <= controls_show_threshold_) { + } else if (normalized_top_ratio <= controls_show_threshold_) { // If we're showing so little that the show threshold won't trigger, hide. SetupAnimation(HIDING_CONTROLS); } else { @@ -295,15 +359,66 @@ void BrowserControlsOffsetManager::StartAnimationIfNecessary() { } } -bool BrowserControlsOffsetManager::IsAnimationComplete(float new_ratio) { - return (animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) || - (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f); -} - void BrowserControlsOffsetManager::ResetBaseline() { accumulated_scroll_delta_ = 0.f; baseline_top_content_offset_ = ContentTopOffset(); baseline_bottom_content_offset_ = ContentBottomOffset(); } +// class Animation + +void BrowserControlsOffsetManager::Animation::Initialize( + AnimationDirection direction, + float start_value, + float stop_value) { + direction_ = direction; + start_value_ = start_value; + stop_value_ = stop_value; + initialized_ = true; +} + +float BrowserControlsOffsetManager::Animation::Tick( + base::TimeTicks monotonic_time) { + if (!IsInitialized()) + return -1; + + if (!started_) { + start_time_ = monotonic_time; + stop_time_ = + start_time_ + base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs); + started_ = true; + } + + float value = gfx::Tween::ClampedFloatValueBetween( + monotonic_time, start_time_, start_value_, stop_time_, stop_value_); + + if (IsComplete(value)) { + value = stop_value_; + Reset(); + } + return base::ClampToRange(value, min_value_, max_value_); +} + +void BrowserControlsOffsetManager::Animation::SetBounds(float min, float max) { + min_value_ = min; + max_value_ = max; +} + +void BrowserControlsOffsetManager::Animation::Reset() { + started_ = false; + initialized_ = false; + start_time_ = base::TimeTicks(); + start_value_ = 0.f; + stop_time_ = base::TimeTicks(); + stop_value_ = 0.f; + direction_ = NO_ANIMATION; +} + +bool BrowserControlsOffsetManager::Animation::IsComplete(float value) { + return (direction_ == SHOWING_CONTROLS && + (value >= stop_value_ || value >= max_value_)) || + (direction_ == HIDING_CONTROLS && + (value <= stop_value_ || value <= min_value_)); +} + } // namespace cc diff --git a/chromium/cc/input/browser_controls_offset_manager.h b/chromium/cc/input/browser_controls_offset_manager.h index af00d337961..7e06c1e253a 100644 --- a/chromium/cc/input/browser_controls_offset_manager.h +++ b/chromium/cc/input/browser_controls_offset_manager.h @@ -40,6 +40,9 @@ class CC_EXPORT BrowserControlsOffsetManager { float ContentTopOffset() const; float TopControlsShownRatio() const; float TopControlsHeight() const; + float TopControlsMinHeight() const; + // The minimum shown ratio top controls can have. + float TopControlsMinShownRatio() const; // The amount of offset of the web content area, calculating from the bottom. // Same as the current shown height of the bottom controls. @@ -47,10 +50,12 @@ class CC_EXPORT BrowserControlsOffsetManager { // Similar to TopControlsHeight(), this method should return a static value. // The current animated height should be acquired from ContentBottomOffset(). float BottomControlsHeight() const; + float BottomControlsMinHeight() const; float BottomControlsShownRatio() const; + // The minimum shown ratio bottom controls can have. + float BottomControlsMinShownRatio() const; - bool has_animation() const { return animation_direction_ != NO_ANIMATION; } - AnimationDirection animation_direction() { return animation_direction_; } + bool HasAnimation(); void UpdateBrowserControlsState(BrowserControlsState constraints, BrowserControlsState current, @@ -59,6 +64,8 @@ class CC_EXPORT BrowserControlsOffsetManager { BrowserControlsState PullConstraintForMainThread( bool* out_changed_since_commit); + void OnBrowserControlsParamsChanged(bool animate_changes); + void ScrollBegin(); gfx::Vector2dF ScrollBy(const gfx::Vector2dF& pending_delta); void ScrollEnd(); @@ -81,21 +88,11 @@ class CC_EXPORT BrowserControlsOffsetManager { void ResetAnimations(); void SetupAnimation(AnimationDirection direction); void StartAnimationIfNecessary(); - bool IsAnimationComplete(float new_ratio); void ResetBaseline(); // The client manages the lifecycle of this. BrowserControlsOffsetManagerClient* client_; - // animation_initialized_ tracks if we've initialized the start and end - // times since that must happen at a BeginFrame. - bool animation_initialized_; - base::TimeTicks animation_start_time_; - float animation_start_value_; - base::TimeTicks animation_stop_time_; - float animation_stop_value_; - AnimationDirection animation_direction_; - BrowserControlsState permitted_state_; // Accumulated scroll delta since last baseline reset @@ -118,6 +115,49 @@ class CC_EXPORT BrowserControlsOffsetManager { // Used to track whether the constraint has changed and we need up reflect // the changes to Blink. bool constraint_changed_since_commit_; + + // Class that holds and manages the state of the controls animations. + class Animation { + public: + Animation() = default; + + // Whether the animation is initialized with a direction and start and stop + // values. + bool IsInitialized() { return initialized_; } + bool Direction() { return direction_; } + void Initialize(AnimationDirection direction, + float start_value, + float stop_value); + // Returns the animated value for the given monotonic time tick if the + // animation is initialized. Otherwise, returns -1. + float Tick(base::TimeTicks monotonic_time); + // Set the minimum and maximum values the animation can have. + void SetBounds(float min, float max); + void Reset(); + + private: + bool IsComplete(float value); + + // Whether the animation is running. + bool started_ = false; + // Whether the animation is initialized by setting start and stop time and + // values. + bool initialized_ = false; + AnimationDirection direction_ = NO_ANIMATION; + // Monotonic start and stop times. + base::TimeTicks start_time_; + base::TimeTicks stop_time_; + // Start and stop values. + float start_value_ = 0.f; + float stop_value_ = 0.f; + // Minimum and maximum values the animation can have, used to decide if the + // animation is complete. + float min_value_ = 0.f; + float max_value_ = 1.f; + }; + + Animation top_controls_animation_; + Animation bottom_controls_animation_; }; } // namespace cc diff --git a/chromium/cc/input/browser_controls_offset_manager_client.h b/chromium/cc/input/browser_controls_offset_manager_client.h index 5a2ce4cb5dc..8d97b85dd48 100644 --- a/chromium/cc/input/browser_controls_offset_manager_client.h +++ b/chromium/cc/input/browser_controls_offset_manager_client.h @@ -10,9 +10,13 @@ namespace cc { class CC_EXPORT BrowserControlsOffsetManagerClient { public: virtual float TopControlsHeight() const = 0; + virtual float TopControlsMinHeight() const = 0; virtual float BottomControlsHeight() const = 0; - virtual void SetCurrentBrowserControlsShownRatio(float ratio) = 0; - virtual float CurrentBrowserControlsShownRatio() const = 0; + virtual float BottomControlsMinHeight() const = 0; + virtual void SetCurrentBrowserControlsShownRatio(float top_ratio, + float bottom_ratio) = 0; + virtual float CurrentTopControlsShownRatio() const = 0; + virtual float CurrentBottomControlsShownRatio() const = 0; virtual void DidChangeBrowserControlsPosition() = 0; virtual bool HaveRootScrollNode() const = 0; virtual void SetNeedsCommit() = 0; diff --git a/chromium/cc/input/browser_controls_offset_manager_unittest.cc b/chromium/cc/input/browser_controls_offset_manager_unittest.cc index 3a8cfdc7df8..d838c4a0cf6 100644 --- a/chromium/cc/input/browser_controls_offset_manager_unittest.cc +++ b/chromium/cc/input/browser_controls_offset_manager_unittest.cc @@ -28,18 +28,17 @@ class MockBrowserControlsOffsetManagerClient MockBrowserControlsOffsetManagerClient(float top_controls_height, float browser_controls_show_threshold, float browser_controls_hide_threshold) - : host_impl_(&task_runner_provider_, - &task_graph_runner_), + : host_impl_(&task_runner_provider_, &task_graph_runner_), redraw_needed_(false), update_draw_properties_needed_(false), - bottom_controls_height_(0.f), + browser_controls_params_({top_controls_height, 0, 0, 0, false, false}), + bottom_controls_shown_ratio_(1.f), top_controls_shown_ratio_(1.f), - top_controls_height_(top_controls_height), browser_controls_show_threshold_(browser_controls_show_threshold), browser_controls_hide_threshold_(browser_controls_hide_threshold) { active_tree_ = std::make_unique<LayerTreeImpl>( &host_impl_, new SyncedProperty<ScaleGroup>, new SyncedBrowserControls, - new SyncedElasticOverscroll); + new SyncedBrowserControls, new SyncedElasticOverscroll); root_scroll_layer_ = LayerImpl::Create(active_tree_.get(), 1); } @@ -53,21 +52,43 @@ class MockBrowserControlsOffsetManagerClient bool HaveRootScrollNode() const override { return true; } float BottomControlsHeight() const override { - return bottom_controls_height_; + return browser_controls_params_.bottom_controls_height; } - float TopControlsHeight() const override { return top_controls_height_; } + float BottomControlsMinHeight() const override { + return browser_controls_params_.bottom_controls_min_height; + } + + float TopControlsHeight() const override { + return browser_controls_params_.top_controls_height; + } + + float TopControlsMinHeight() const override { + return browser_controls_params_.top_controls_min_height; + } + + void SetCurrentBrowserControlsShownRatio(float top_ratio, + float bottom_ratio) override { + AssertAndClamp(&top_ratio); + top_controls_shown_ratio_ = top_ratio; + + AssertAndClamp(&bottom_ratio); + bottom_controls_shown_ratio_ = bottom_ratio; + } - void SetCurrentBrowserControlsShownRatio(float ratio) override { - ASSERT_FALSE(std::isnan(ratio)); - ASSERT_FALSE(ratio == std::numeric_limits<float>::infinity()); - ASSERT_FALSE(ratio == -std::numeric_limits<float>::infinity()); - ratio = std::max(ratio, 0.f); - ratio = std::min(ratio, 1.f); - top_controls_shown_ratio_ = ratio; + void AssertAndClamp(float* ratio) { + ASSERT_FALSE(std::isnan(*ratio)); + ASSERT_FALSE(*ratio == std::numeric_limits<float>::infinity()); + ASSERT_FALSE(*ratio == -std::numeric_limits<float>::infinity()); + *ratio = std::max(*ratio, 0.f); + *ratio = std::min(*ratio, 1.f); } - float CurrentBrowserControlsShownRatio() const override { + float CurrentBottomControlsShownRatio() const override { + return bottom_controls_shown_ratio_; + } + + float CurrentTopControlsShownRatio() const override { return top_controls_shown_ratio_; } @@ -84,10 +105,8 @@ class MockBrowserControlsOffsetManagerClient return manager_.get(); } - void SetBrowserControlsHeight(float height) { top_controls_height_ = height; } - - void SetBottomControlsHeight(float height) { - bottom_controls_height_ = height; + void SetBrowserControlsParams(BrowserControlsParams params) { + browser_controls_params_ = params; } private: @@ -100,9 +119,9 @@ class MockBrowserControlsOffsetManagerClient bool redraw_needed_; bool update_draw_properties_needed_; - float bottom_controls_height_; + BrowserControlsParams browser_controls_params_; + float bottom_controls_shown_ratio_; float top_controls_shown_ratio_; - float top_controls_height_; float browser_controls_show_threshold_; float browser_controls_hide_threshold_; }; @@ -166,7 +185,7 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownHideAnimation) { EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -175,13 +194,13 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownHideAnimation) { manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_LT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); } @@ -189,7 +208,7 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownHideAnimation) { TEST(BrowserControlsOffsetManagerTest, BottomControlsPartialShownHideAnimation) { MockBrowserControlsOffsetManagerClient client(0.f, 0.5f, 0.5f); - client.SetBottomControlsHeight(100.f); + client.SetBrowserControlsParams({0, 0, 100, 0, false, false}); BrowserControlsOffsetManager* manager = client.manager(); manager->ScrollBegin(); manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); @@ -203,7 +222,7 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -212,13 +231,13 @@ TEST(BrowserControlsOffsetManagerTest, manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->BottomControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_LT(manager->BottomControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(0.f, manager->BottomControlsShownRatio()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); } @@ -238,7 +257,7 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownShowAnimation) { EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -247,13 +266,13 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownShowAnimation) { manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_GT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset()); } @@ -261,7 +280,7 @@ TEST(BrowserControlsOffsetManagerTest, PartialShownShowAnimation) { TEST(BrowserControlsOffsetManagerTest, BottomControlsPartialShownShowAnimation) { MockBrowserControlsOffsetManagerClient client(0.f, 0.5f, 0.5f); - client.SetBottomControlsHeight(100.f); + client.SetBrowserControlsParams({0, 0, 100, 0, false, false}); BrowserControlsOffsetManager* manager = client.manager(); manager->ScrollBegin(); @@ -270,7 +289,7 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -279,13 +298,13 @@ TEST(BrowserControlsOffsetManagerTest, manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->BottomControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_GT(manager->BottomControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(1.f, manager->BottomControlsShownRatio()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); } @@ -302,7 +321,7 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(80.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -311,13 +330,13 @@ TEST(BrowserControlsOffsetManagerTest, manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_GT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset()); } @@ -334,7 +353,7 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -343,13 +362,13 @@ TEST(BrowserControlsOffsetManagerTest, manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_LT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); } @@ -370,7 +389,7 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(20.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -379,13 +398,13 @@ TEST(BrowserControlsOffsetManagerTest, manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_LT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); } @@ -406,7 +425,7 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(30.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -415,13 +434,13 @@ TEST(BrowserControlsOffsetManagerTest, manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_GT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset()); } @@ -452,7 +471,7 @@ TEST(BrowserControlsOffsetManagerTest, PinchIgnoresScroll) { EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); } TEST(BrowserControlsOffsetManagerTest, PinchBeginStartsAnimationIfNecessary) { @@ -464,17 +483,17 @@ TEST(BrowserControlsOffsetManagerTest, PinchBeginStartsAnimationIfNecessary) { EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset()); manager->PinchBegin(); - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); manager->PinchEnd(); - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); manager->ScrollBy(gfx::Vector2dF(0.f, -15.f)); EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset()); manager->PinchBegin(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); base::TimeTicks time = base::TimeTicks::Now(); @@ -483,24 +502,24 @@ TEST(BrowserControlsOffsetManagerTest, PinchBeginStartsAnimationIfNecessary) { manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_LT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); manager->PinchEnd(); - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); manager->ScrollBy(gfx::Vector2dF(0.f, -55.f)); EXPECT_FLOAT_EQ(-45.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(55.f, manager->ContentTopOffset()); - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); manager->ScrollEnd(); - EXPECT_TRUE(manager->has_animation()); + EXPECT_TRUE(manager->HasAnimation()); time = base::TimeTicks::Now(); @@ -509,13 +528,13 @@ TEST(BrowserControlsOffsetManagerTest, PinchBeginStartsAnimationIfNecessary) { manager->Animate(time); EXPECT_EQ(manager->TopControlsShownRatio(), previous); - while (manager->has_animation()) { + while (manager->HasAnimation()) { previous = manager->TopControlsShownRatio(); time = base::TimeDelta::FromMicroseconds(100) + time; manager->Animate(time); EXPECT_GT(manager->TopControlsShownRatio(), previous); } - EXPECT_FALSE(manager->has_animation()); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); } @@ -526,13 +545,13 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); - client.SetBrowserControlsHeight(100.f); - EXPECT_FALSE(manager->has_animation()); + client.SetBrowserControlsParams({100, 0, 0, 0, false, false}); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(100.f, manager->TopControlsHeight()); EXPECT_FLOAT_EQ(0, manager->ControlsTopOffset()); - client.SetBrowserControlsHeight(50.f); - EXPECT_FALSE(manager->has_animation()); + client.SetBrowserControlsParams({50, 0, 0, 0, false, false}); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(50.f, manager->TopControlsHeight()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); } @@ -548,13 +567,13 @@ TEST(BrowserControlsOffsetManagerTest, EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); manager->ScrollEnd(); - client.SetBrowserControlsHeight(50.f); - EXPECT_FALSE(manager->has_animation()); + client.SetBrowserControlsParams({50, 0, 0, 0, false, false}); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(-50.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); - client.SetBrowserControlsHeight(0.f); - EXPECT_FALSE(manager->has_animation()); + client.SetBrowserControlsParams({0, 0, 0, 0, false, false}); + EXPECT_FALSE(manager->HasAnimation()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); } @@ -570,13 +589,13 @@ TEST(BrowserControlsOffsetManagerTest, ScrollByWithZeroHeightControlsIsNoop) { EXPECT_FLOAT_EQ(20.f, pending.y()); EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset()); EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset()); - EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio()); + EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio()); manager->ScrollEnd(); } TEST(BrowserControlsOffsetManagerTest, ScrollThenRestoreBottomControls) { MockBrowserControlsOffsetManagerClient client(100.f, 0.5f, 0.5f); - client.SetBottomControlsHeight(100.f); + client.SetBrowserControlsParams({0, 0, 100, 0, false, false}); BrowserControlsOffsetManager* manager = client.manager(); manager->ScrollBegin(); manager->ScrollBy(gfx::Vector2dF(0.f, 20.f)); @@ -594,7 +613,7 @@ TEST(BrowserControlsOffsetManagerTest, ScrollThenRestoreBottomControls) { TEST(BrowserControlsOffsetManagerTest, ScrollThenRestoreBottomControlsNoTopControls) { MockBrowserControlsOffsetManagerClient client(0.f, 0.5f, 0.5f); - client.SetBottomControlsHeight(100.f); + client.SetBrowserControlsParams({0, 0, 100, 0, false, false}); BrowserControlsOffsetManager* manager = client.manager(); manager->ScrollBegin(); manager->ScrollBy(gfx::Vector2dF(0.f, 20.f)); @@ -611,7 +630,7 @@ TEST(BrowserControlsOffsetManagerTest, TEST(BrowserControlsOffsetManagerTest, HideAndPeekBottomControls) { MockBrowserControlsOffsetManagerClient client(100.f, 0.5f, 0.5f); - client.SetBottomControlsHeight(100.f); + client.SetBrowserControlsParams({0, 0, 100, 0, false, false}); BrowserControlsOffsetManager* manager = client.manager(); manager->ScrollBegin(); manager->ScrollBy(gfx::Vector2dF(0.f, 300.f)); @@ -629,19 +648,60 @@ TEST(BrowserControlsOffsetManagerTest, HideAndPeekBottomControls) { TEST(BrowserControlsOffsetManagerTest, HideAndImmediateShowKeepsControlsVisible) { MockBrowserControlsOffsetManagerClient client(100.f, 0.5f, 0.5f); - client.SetBottomControlsHeight(100.f); + client.SetBrowserControlsParams({0, 0, 100, 0, false, false}); BrowserControlsOffsetManager* manager = client.manager(); - EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); manager->UpdateBrowserControlsState(BrowserControlsState::kBoth, BrowserControlsState::kHidden, true); - EXPECT_TRUE(manager->has_animation()); - EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio()); + EXPECT_TRUE(manager->HasAnimation()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); manager->UpdateBrowserControlsState(BrowserControlsState::kBoth, BrowserControlsState::kShown, true); - EXPECT_FALSE(manager->has_animation()); - EXPECT_FLOAT_EQ(1.f, client.CurrentBrowserControlsShownRatio()); + EXPECT_FALSE(manager->HasAnimation()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); +} + +TEST(BrowserControlsOffsetManagerTest, + ScrollWithMinHeightSetForTopControlsOnly) { + MockBrowserControlsOffsetManagerClient client(100, 0.5f, 0.5f); + client.SetBrowserControlsParams({100, 30, 100, 0, false, false}); + BrowserControlsOffsetManager* manager = client.manager(); + EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); + + manager->ScrollBegin(); + manager->ScrollBy(gfx::Vector2dF(0, 150)); + EXPECT_FLOAT_EQ(30.f / 100, client.CurrentTopControlsShownRatio()); + EXPECT_FLOAT_EQ(0.f, client.CurrentBottomControlsShownRatio()); + manager->ScrollEnd(); + + manager->ScrollBegin(); + manager->ScrollBy(gfx::Vector2dF(0, -70)); + EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); + manager->ScrollEnd(); +} + +TEST(BrowserControlsOffsetManagerTest, ScrollWithMinHeightSetForBothControls) { + MockBrowserControlsOffsetManagerClient client(100, 0.5f, 0.5f); + client.SetBrowserControlsParams({100, 30, 100, 20, false, false}); + BrowserControlsOffsetManager* manager = client.manager(); + EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); + + manager->ScrollBegin(); + manager->ScrollBy(gfx::Vector2dF(0, 150)); + EXPECT_FLOAT_EQ(30.f / 100, client.CurrentTopControlsShownRatio()); + EXPECT_FLOAT_EQ(20.f / 100, client.CurrentBottomControlsShownRatio()); + manager->ScrollEnd(); + + manager->ScrollBegin(); + manager->ScrollBy(gfx::Vector2dF(0, -70)); + EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio()); + EXPECT_FLOAT_EQ(1.f, client.CurrentBottomControlsShownRatio()); + manager->ScrollEnd(); } } // namespace diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h index f39e0062ffe..50896f5ffa5 100644 --- a/chromium/cc/input/input_handler.h +++ b/chromium/cc/input/input_handler.h @@ -25,11 +25,11 @@ class Point; class ScrollOffset; class SizeF; class Vector2dF; -} +} // namespace gfx namespace ui { class LatencyInfo; -} +} // namespace ui namespace cc { @@ -198,6 +198,8 @@ class CC_EXPORT InputHandler { virtual InputHandlerPointerResult MouseMoveAt( const gfx::Point& mouse_position) = 0; + // TODO(arakeri): Pass in the modifier instead of a bool once the refactor + // (crbug.com/1022097) is done. For details, see crbug.com/1016955. virtual InputHandlerPointerResult MouseDown(const gfx::PointF& mouse_position, bool shift_modifier) = 0; virtual InputHandlerPointerResult MouseUp( @@ -206,7 +208,7 @@ class CC_EXPORT InputHandler { // Stop scrolling the selected layer. Should only be called if ScrollBegin() // returned SCROLL_STARTED. Snap to a snap position if |should_snap| is true. - virtual void ScrollEnd(ScrollState* scroll_state, bool should_snap) = 0; + virtual void ScrollEnd(bool should_snap) = 0; // Requests a callback to UpdateRootLayerStateForSynchronousInputHandler() // giving the current root scroll and page scale information. @@ -278,10 +280,10 @@ class CC_EXPORT InputHandler { // |natural_displacement_in_viewport| is the estimated total scrolling for // the active scroll sequence. // Returns false if their is no position to snap to. - virtual bool GetSnapFlingInfo( + virtual bool GetSnapFlingInfoAndSetSnapTarget( const gfx::Vector2dF& natural_displacement_in_viewport, gfx::Vector2dF* initial_offset, - gfx::Vector2dF* target_offset) const = 0; + gfx::Vector2dF* target_offset) = 0; protected: InputHandler() = default; diff --git a/chromium/cc/input/layer_selection_bound.cc b/chromium/cc/input/layer_selection_bound.cc index 55f2e3a5fb4..81af0bf7d32 100644 --- a/chromium/cc/input/layer_selection_bound.cc +++ b/chromium/cc/input/layer_selection_bound.cc @@ -15,7 +15,7 @@ LayerSelectionBound::~LayerSelectionBound() = default; bool LayerSelectionBound::operator==(const LayerSelectionBound& other) const { return type == other.type && layer_id == other.layer_id && - edge_top == other.edge_top && edge_bottom == other.edge_bottom && + edge_start == other.edge_start && edge_end == other.edge_end && hidden == other.hidden; } @@ -25,8 +25,8 @@ bool LayerSelectionBound::operator!=(const LayerSelectionBound& other) const { std::string LayerSelectionBound::ToString() const { return base::StringPrintf("LayerSelectionBound(%s, %s, %d)", - edge_top.ToString().c_str(), - edge_bottom.ToString().c_str(), hidden); + edge_start.ToString().c_str(), + edge_end.ToString().c_str(), hidden); } } // namespace cc diff --git a/chromium/cc/input/layer_selection_bound.h b/chromium/cc/input/layer_selection_bound.h index a2a2583c143..43561075a34 100644 --- a/chromium/cc/input/layer_selection_bound.h +++ b/chromium/cc/input/layer_selection_bound.h @@ -19,8 +19,8 @@ struct CC_EXPORT LayerSelectionBound { ~LayerSelectionBound(); gfx::SelectionBound::Type type; - gfx::Point edge_top; - gfx::Point edge_bottom; + gfx::Point edge_start; + gfx::Point edge_end; int layer_id; // Whether this bound is hidden (clipped out/occluded) within the painted // content of the layer (as opposed to being outside of the layer's bounds). diff --git a/chromium/cc/input/main_thread_scrolling_reason.cc b/chromium/cc/input/main_thread_scrolling_reason.cc index 4b5cac239f0..172249f5bb3 100644 --- a/chromium/cc/input/main_thread_scrolling_reason.cc +++ b/chromium/cc/input/main_thread_scrolling_reason.cc @@ -5,12 +5,13 @@ #include "cc/input/main_thread_scrolling_reason.h" #include "base/stl_util.h" +#include "base/strings/string_util.h" #include "base/trace_event/traced_value.h" namespace cc { std::string MainThreadScrollingReason::AsText(uint32_t reasons) { - base::trace_event::TracedValue traced_value; + base::trace_event::TracedValue traced_value(0, /*force_json=*/true); AddToTracedValue(reasons, traced_value); std::string result = traced_value.ToString(); // Remove '{main_thread_scrolling_reasons:[', ']}', and any '"' chars. @@ -19,6 +20,8 @@ std::string MainThreadScrollingReason::AsText(uint32_t reasons) { result = result.substr(array_start_pos + 1, array_end_pos - array_start_pos - 1); base::Erase(result, '\"'); + // Add spaces after all commas. + base::ReplaceChars(result, ",", ", ", &result); return result; } diff --git a/chromium/cc/input/main_thread_scrolling_reason_unittest.cc b/chromium/cc/input/main_thread_scrolling_reason_unittest.cc index 3970af2eade..8744d643907 100644 --- a/chromium/cc/input/main_thread_scrolling_reason_unittest.cc +++ b/chromium/cc/input/main_thread_scrolling_reason_unittest.cc @@ -13,26 +13,26 @@ using MainThreadScrollingReasonTest = testing::Test; TEST_F(MainThreadScrollingReasonTest, AsText) { EXPECT_EQ("", MainThreadScrollingReason::AsText(0)); EXPECT_EQ( - "Has background-attachment:fixed," - "Has non-layer viewport-constrained objects," - "Threaded scrolling is disabled," - "Scrollbar scrolling," - "Frame overlay," - "Handling scroll from main thread," - "Has opacity and LCD text," - "Has transform and LCD text," - "Background is not opaque in rect and LCD text," - "Has clip related property," - "Has box shadow from non-root layer," - "Is not stacking context and LCD text," - "Non fast scrollable region," - "Failed hit test," - "No scrolling layer," - "Not scrollable," - "Continuing main thread scroll," - "Non-invertible transform," - "Page-based scrolling," - "Wheel event handler region," + "Has background-attachment:fixed, " + "Has non-layer viewport-constrained objects, " + "Threaded scrolling is disabled, " + "Scrollbar scrolling, " + "Frame overlay, " + "Handling scroll from main thread, " + "Has opacity and LCD text, " + "Has transform and LCD text, " + "Background is not opaque in rect and LCD text, " + "Has clip related property, " + "Has box shadow from non-root layer, " + "Is not stacking context and LCD text, " + "Non fast scrollable region, " + "Failed hit test, " + "No scrolling layer, " + "Not scrollable, " + "Continuing main thread scroll, " + "Non-invertible transform, " + "Page-based scrolling, " + "Wheel event handler region, " "Touch event handler region", MainThreadScrollingReason::AsText(0xffffffffu)); } diff --git a/chromium/cc/input/scroll_snap_data.cc b/chromium/cc/input/scroll_snap_data.cc index 2121d1ca658..730326a36b9 100644 --- a/chromium/cc/input/scroll_snap_data.cc +++ b/chromium/cc/input/scroll_snap_data.cc @@ -111,7 +111,9 @@ void SnapContainerData::AddSnapAreaData(SnapAreaData snap_area_data) { bool SnapContainerData::FindSnapPosition( const SnapSelectionStrategy& strategy, - gfx::ScrollOffset* snap_position) const { + gfx::ScrollOffset* snap_position, + TargetSnapAreaElementIds* target_element_ids) const { + *target_element_ids = TargetSnapAreaElementIds(); if (scroll_snap_type_.is_none) return false; @@ -124,54 +126,113 @@ bool SnapContainerData::FindSnapPosition( if (!should_snap_on_x && !should_snap_on_y) return false; - base::Optional<SnapSearchResult> closest_x, closest_y; - // A region that includes every reachable scroll position. - gfx::RectF scrollable_region(0, 0, max_position_.x(), max_position_.y()); + bool should_prioritize_x_target = + strategy.ShouldPrioritizeSnapTargets() && + target_snap_area_element_ids_.x != ElementId(); + bool should_prioritize_y_target = + strategy.ShouldPrioritizeSnapTargets() && + target_snap_area_element_ids_.y != ElementId(); + + base::Optional<SnapSearchResult> selected_x, selected_y; if (should_snap_on_x) { - // Start from current position in the cross axis. The search algorithm - // expects the cross axis position to be inside scroller bounds. But since - // we cannot always assume that the incoming value fits this criteria we - // clamp it to the bounds to ensure this variant. - SnapSearchResult initial_snap_position_y = { - base::ClampToRange(base_position.y(), 0.f, max_position_.y()), - gfx::RangeF(0, max_position_.x())}; - closest_x = - FindClosestValidArea(SearchAxis::kX, strategy, initial_snap_position_y); + if (should_prioritize_x_target) { + // TODO(http://crbug.com/866127): If the target snap area is covering the + // snapport then we should fallback to the default "closest-area" method + // instead. + selected_x = GetTargetSnapAreaSearchResult(SearchAxis::kX); + DCHECK(selected_x.has_value()); + } else { + // Start from current position in the cross axis. The search algorithm + // expects the cross axis position to be inside scroller bounds. But since + // we cannot always assume that the incoming value fits this criteria we + // clamp it to the bounds to ensure this variant. + 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); + } } if (should_snap_on_y) { - SnapSearchResult initial_snap_position_x = { - base::ClampToRange(base_position.x(), 0.f, max_position_.x()), - gfx::RangeF(0, max_position_.y())}; - closest_y = - FindClosestValidArea(SearchAxis::kY, strategy, initial_snap_position_x); + if (should_prioritize_y_target) { + selected_y = GetTargetSnapAreaSearchResult(SearchAxis::kY); + DCHECK(selected_y.has_value()); + } else { + SnapSearchResult initial_snap_position_x = { + base::ClampToRange(base_position.x(), 0.f, max_position_.x()), + gfx::RangeF(0, max_position_.y())}; + selected_y = FindClosestValidArea(SearchAxis::kY, strategy, + initial_snap_position_x); + } } - if (!closest_x.has_value() && !closest_y.has_value()) + if (!selected_x.has_value() && !selected_y.has_value()) 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 - // In this case, we choose the axis whose snap area is closer, and find a - // mutual visible snap area on the other axis. - if (closest_x.has_value() && closest_y.has_value() && - !IsMutualVisible(closest_x.value(), closest_y.value())) { - bool candidate_on_x_axis_is_closer = - std::abs(closest_x.value().snap_offset() - base_position.x()) <= - std::abs(closest_y.value().snap_offset() - base_position.y()); - if (candidate_on_x_axis_is_closer) { - closest_y = - FindClosestValidArea(SearchAxis::kY, strategy, closest_x.value()); + // In this case, first check if we need to prioritize the snap area from + // one axis over the other and select that axis, or if we don't prioritize an + // axis over the other, we choose the axis whose snap area is closer. + // Then find a new snap area on the other axis that is mutually visible with + // the selected axis' snap area. + if (selected_x.has_value() && selected_y.has_value() && + !IsMutualVisible(selected_x.value(), selected_y.value())) { + bool keep_candidate_on_x = should_prioritize_x_target; + if (should_prioritize_x_target == should_prioritize_y_target) { + keep_candidate_on_x = + std::abs(selected_x.value().snap_offset() - base_position.x()) <= + std::abs(selected_y.value().snap_offset() - base_position.y()); + } + if (keep_candidate_on_x) { + selected_y = + FindClosestValidArea(SearchAxis::kY, strategy, selected_x.value()); } else { - closest_x = - FindClosestValidArea(SearchAxis::kX, strategy, closest_y.value()); + selected_x = + FindClosestValidArea(SearchAxis::kX, strategy, selected_y.value()); } } *snap_position = strategy.current_position(); - if (closest_x.has_value()) - snap_position->set_x(closest_x.value().snap_offset()); - if (closest_y.has_value()) - snap_position->set_y(closest_y.value().snap_offset()); + if (selected_x.has_value()) { + snap_position->set_x(selected_x.value().snap_offset()); + target_element_ids->x = selected_x.value().element_id(); + } + + if (selected_y.has_value()) { + snap_position->set_y(selected_y.value().snap_offset()); + target_element_ids->y = selected_y.value().element_id(); + } + + return true; +} + +base::Optional<SnapSearchResult> +SnapContainerData::GetTargetSnapAreaSearchResult(SearchAxis axis) const { + ElementId target_id = axis == SearchAxis::kX + ? target_snap_area_element_ids_.x + : target_snap_area_element_ids_.y; + if (target_id == ElementId()) + return base::nullopt; + for (const SnapAreaData& area : snap_area_list_) { + if (area.element_id == target_id) + return GetSnapSearchResult(axis, area); + } + return base::nullopt; +} + +const TargetSnapAreaElementIds& SnapContainerData::GetTargetSnapAreaElementIds() + const { + return target_snap_area_element_ids_; +} + +bool SnapContainerData::SetTargetSnapAreaElementIds( + TargetSnapAreaElementIds ids) { + if (target_snap_area_element_ids_ == ids) + return false; + + target_snap_area_element_ids_ = ids; return true; } @@ -354,6 +415,7 @@ SnapSearchResult SnapContainerData::GetSnapSearchResult( } result.Clip(max_position_.y(), max_position_.x()); } + result.set_element_id(area.element_id); return result; } diff --git a/chromium/cc/input/scroll_snap_data.h b/chromium/cc/input/scroll_snap_data.h index 998d314ce14..52f5acd1457 100644 --- a/chromium/cc/input/scroll_snap_data.h +++ b/chromium/cc/input/scroll_snap_data.h @@ -9,6 +9,7 @@ #include "base/optional.h" #include "cc/cc_export.h" +#include "cc/paint/element_id.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/range/range_f.h" @@ -97,6 +98,8 @@ class SnapSearchResult { // Union the visible_range of the two SnapSearchResult if they represent two // snap areas that are both covering the snapport at the current offset. + // The |element_id_| of this is arbitrarily chosen because both snap areas + // cover the snapport and are therefore both valid. void Union(const SnapSearchResult& other); float snap_offset() const { return snap_offset_; } @@ -105,12 +108,18 @@ class SnapSearchResult { gfx::RangeF visible_range() const { return visible_range_; } void set_visible_range(const gfx::RangeF& range); + ElementId element_id() const { return element_id_; } + void set_element_id(ElementId id) { element_id_ = id; } + private: float snap_offset_; // This is the range on the cross axis, within which the SnapArea generating // this |snap_offset| is visible. We expect the range to be in order (as // opposed to reversed), i.e., start() < end(). gfx::RangeF visible_range_; + + // The ElementId of the snap area that corresponds to this SnapSearchResult. + ElementId element_id_; }; // Snap area is a bounding box that could be snapped to when a scroll happens in @@ -125,11 +134,15 @@ struct SnapAreaData { SnapAreaData() {} - SnapAreaData(const ScrollSnapAlign& align, const gfx::RectF& rec, bool msnap) - : scroll_snap_align(align), rect(rec), must_snap(msnap) {} + SnapAreaData(const ScrollSnapAlign& align, + const gfx::RectF& rec, + bool msnap, + ElementId id) + : scroll_snap_align(align), rect(rec), must_snap(msnap), element_id(id) {} bool operator==(const SnapAreaData& other) const { - return (other.scroll_snap_align == scroll_snap_align) && + return (other.element_id == element_id) && + (other.scroll_snap_align == scroll_snap_align) && (other.rect == rect) && (other.must_snap == must_snap); } @@ -146,6 +159,21 @@ struct SnapAreaData { // Whether this area has scroll-snap-stop: always. // See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-stop bool must_snap; + + // ElementId of the corresponding snap area. + ElementId element_id; +}; + +struct TargetSnapAreaElementIds { + TargetSnapAreaElementIds() = default; + TargetSnapAreaElementIds(ElementId x_id, ElementId y_id) : x(x_id), y(y_id) {} + bool operator==(const TargetSnapAreaElementIds& other) const { + return (other.x == x) && (other.y == y); + } + + // Note that the same element can be snapped to on both the x and y axes. + ElementId x; + ElementId y; }; typedef std::vector<SnapAreaData> SnapAreaList; @@ -177,15 +205,23 @@ class CC_EXPORT SnapContainerData { return (other.scroll_snap_type_ == scroll_snap_type_) && (other.rect_ == rect_) && (other.max_position_ == max_position_) && (other.proximity_range_ == proximity_range_) && - (other.snap_area_list_ == snap_area_list_); + (other.snap_area_list_ == snap_area_list_) && + (other.target_snap_area_element_ids_ == + target_snap_area_element_ids_); } bool operator!=(const SnapContainerData& other) const { return !(*this == other); } + // Returns true if a snap position was found. bool FindSnapPosition(const SnapSelectionStrategy& strategy, - gfx::ScrollOffset* snap_position) const; + gfx::ScrollOffset* snap_position, + TargetSnapAreaElementIds* target_element_ids) const; + + const TargetSnapAreaElementIds& GetTargetSnapAreaElementIds() const; + // Returns true if the target snap area element ids were changed. + bool SetTargetSnapAreaElementIds(TargetSnapAreaElementIds ids); void AddSnapAreaData(SnapAreaData snap_area_data); size_t size() const { return snap_area_list_.size(); } @@ -235,6 +271,11 @@ class CC_EXPORT SnapContainerData { const SnapSelectionStrategy& strategy, const SnapSearchResult& cross_axis_snap_result) const; + // Finds the snap area associated with the target snap area element id for the + // given axis. + base::Optional<SnapSearchResult> GetTargetSnapAreaSearchResult( + SearchAxis axis) const; + // Returns all the info needed to snap at this area on the given axis, // including: // - The offset at which the snap area and the snap container meet the @@ -268,6 +309,11 @@ class CC_EXPORT SnapContainerData { // happens, we iterate through the snap_area_list to find the best snap // position. std::vector<SnapAreaData> snap_area_list_; + + // Represents the ElementId(s) of the latest targeted snap areas. + // ElementId(s) will be invalid (ElementId::kInvalidElementId) if the snap + // container is not snapped to a position. + TargetSnapAreaElementIds target_snap_area_element_ids_; }; CC_EXPORT std::ostream& operator<<(std::ostream&, const SnapAreaData&); diff --git a/chromium/cc/input/scroll_snap_data_unittest.cc b/chromium/cc/input/scroll_snap_data_unittest.cc index 704b47e81e8..8335957864c 100644 --- a/chromium/cc/input/scroll_snap_data_unittest.cc +++ b/chromium/cc/input/scroll_snap_data_unittest.cc @@ -10,23 +10,30 @@ namespace cc { -class ScrollSnapDataTest : public testing::Test {}; +class ScrollSnapDataTest : public testing::Test { + public: + TargetSnapAreaElementIds target_elements; +}; TEST_F(ScrollSnapDataTest, StartAlignmentCalculation) { SnapContainerData container( ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(10, 10, 200, 300), gfx::ScrollOffset(600, 800)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(100, 150, 100, 100), false); + gfx::RectF(100, 150, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(90, snap_position.x()); EXPECT_EQ(140, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + target_elements); } TEST_F(ScrollSnapDataTest, CenterAlignmentCalculation) { @@ -34,16 +41,19 @@ TEST_F(ScrollSnapDataTest, CenterAlignmentCalculation) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(10, 10, 200, 300), gfx::ScrollOffset(600, 800)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kCenter), - gfx::RectF(100, 150, 100, 100), false); + gfx::RectF(100, 150, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(40, snap_position.x()); EXPECT_EQ(40, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + target_elements); } TEST_F(ScrollSnapDataTest, EndAlignmentCalculation) { @@ -51,16 +61,19 @@ TEST_F(ScrollSnapDataTest, EndAlignmentCalculation) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(10, 10, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd), - gfx::RectF(150, 200, 100, 100), false); + gfx::RectF(150, 200, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(40, snap_position.x()); EXPECT_EQ(90, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + target_elements); } TEST_F(ScrollSnapDataTest, UnreachableSnapPositionCalculation) { @@ -68,19 +81,22 @@ TEST_F(ScrollSnapDataTest, UnreachableSnapPositionCalculation) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(100, 100)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd, SnapAlignment::kStart), - gfx::RectF(200, 0, 100, 100), false); + gfx::RectF(200, 0, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(50, 50), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); // Aligning to start on x would lead the scroll offset larger than max, and // aligning to end on y would lead the scroll offset smaller than zero. So // we expect these are clamped. EXPECT_EQ(100, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + target_elements); } TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionIndependently) { @@ -89,12 +105,13 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionIndependently) { gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), - gfx::RectF(80, 0, 150, 150), false); + gfx::RectF(80, 0, 150, 150), false, ElementId(10)); SnapAreaData snap_y_only( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), - gfx::RectF(0, 70, 150, 150), false); + gfx::RectF(0, 70, 150, 150), false, ElementId(20)); SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(50, 150, 150, 150), false); + gfx::RectF(50, 150, 150, 150), false, + ElementId(30)); container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); container.AddSnapAreaData(snap_on_both); @@ -103,9 +120,12 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionIndependently) { std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(80, snap_position.x()); EXPECT_EQ(70, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(20)), + target_elements); } TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionOnAxisValueBoth) { @@ -114,12 +134,13 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionOnAxisValueBoth) { gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), - gfx::RectF(80, 0, 150, 150), false); + gfx::RectF(80, 0, 150, 150), false, ElementId(10)); SnapAreaData snap_y_only( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), - gfx::RectF(0, 70, 150, 150), false); + gfx::RectF(0, 70, 150, 150), false, ElementId(20)); SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(50, 150, 150, 150), false); + gfx::RectF(50, 150, 150, 150), false, + ElementId(30)); container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); @@ -128,9 +149,12 @@ TEST_F(ScrollSnapDataTest, FindsClosestSnapPositionOnAxisValueBoth) { std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(40, 120), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(50, snap_position.x()); EXPECT_EQ(150, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(30), ElementId(30)), + target_elements); } TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonScrolledAxis) { @@ -139,10 +163,10 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonScrolledAxis) { gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), - gfx::RectF(80, 0, 150, 150), false); + gfx::RectF(80, 0, 150, 150), false, ElementId(10)); SnapAreaData snap_y_only( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), - gfx::RectF(0, 70, 150, 150), false); + gfx::RectF(0, 70, 150, 150), false, ElementId(20)); container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); @@ -150,9 +174,12 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonScrolledAxis) { std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100), true, false); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(80, snap_position.x()); EXPECT_EQ(100, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); } TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonVisibleAreas) { @@ -161,10 +188,10 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonVisibleAreas) { gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), - gfx::RectF(300, 400, 100, 100), false); + gfx::RectF(300, 400, 100, 100), false, ElementId(10)); SnapAreaData snap_y_only( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), - gfx::RectF(400, 300, 100, 100), false); + gfx::RectF(400, 300, 100, 100), false, ElementId(20)); container.AddSnapAreaData(snap_x_only); container.AddSnapAreaData(snap_y_only); @@ -172,7 +199,9 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapOnNonVisibleAreas) { std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, true); - EXPECT_FALSE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_FALSE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); + EXPECT_EQ(TargetSnapAreaElementIds(), target_elements); } TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) { @@ -187,13 +216,13 @@ TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) { // conflict with the snap point on x. SnapAreaData snap_x( ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), - gfx::RectF(150, 0, 100, 100), false); + gfx::RectF(150, 0, 100, 100), false, ElementId(10)); SnapAreaData snap_y1( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), - gfx::RectF(0, 180, 100, 100), false); + gfx::RectF(0, 180, 100, 100), false, ElementId(20)); SnapAreaData snap_y2( ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), - gfx::RectF(250, 80, 100, 100), false); + gfx::RectF(250, 80, 100, 100), false, ElementId(30)); container.AddSnapAreaData(snap_x); container.AddSnapAreaData(snap_y1); container.AddSnapAreaData(snap_y2); @@ -202,9 +231,12 @@ TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) { std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(150, snap_position.x()); EXPECT_EQ(80, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(30)), + target_elements); } TEST_F(ScrollSnapDataTest, DoesNotSnapToPositionsOutsideProximityRange) { @@ -214,20 +246,23 @@ TEST_F(ScrollSnapDataTest, DoesNotSnapToPositionsOutsideProximityRange) { container.set_proximity_range(gfx::ScrollOffset(50, 50)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(80, 160, 100, 100), false); + gfx::RectF(80, 160, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100), true, true); - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); // The snap position on x, 80, is within the proximity range of [50, 150]. // However, the snap position on y, 160, is outside the proximity range of // [50, 150], so we should only snap on x. EXPECT_EQ(80, snap_position.x()); EXPECT_EQ(100, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); } TEST_F(ScrollSnapDataTest, MandatoryReturnsToCurrentIfNoValidAreaForward) { @@ -235,38 +270,45 @@ TEST_F(ScrollSnapDataTest, MandatoryReturnsToCurrentIfNoValidAreaForward) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(2000, 2000)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(600, 0, 100, 100), false); + gfx::RectF(600, 0, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> direction_strategy = SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset(600, 0), gfx::ScrollOffset(5, 0)); - EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position)); + EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position, + &target_elements)); // The snap direction is right. However, there is no valid snap position on // that direction. So we have to stay at the current snap position of 600 as // the snap type is mandatory. EXPECT_EQ(600, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); std::unique_ptr<SnapSelectionStrategy> end_direction_strategy = SnapSelectionStrategy::CreateForEndAndDirection( gfx::ScrollOffset(600, 0), gfx::ScrollOffset(15, 15)); - EXPECT_TRUE( - container.FindSnapPosition(*end_direction_strategy, &snap_position)); + EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy, + &snap_position, &target_elements)); // The snap direction is down and right. However, there is no valid snap // position on that direction. So we have to stay at the current snap position // of (600, 0) as the snap type is mandatory. EXPECT_EQ(600, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + target_elements); // If the scroll-snap-type is proximity, we wouldn't consider the current // snap area valid even if there is no snap area forward. container.set_scroll_snap_type( ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kProximity)); - EXPECT_FALSE(container.FindSnapPosition(*direction_strategy, &snap_position)); - EXPECT_FALSE( - container.FindSnapPosition(*end_direction_strategy, &snap_position)); + EXPECT_FALSE(container.FindSnapPosition(*direction_strategy, &snap_position, + &target_elements)); + EXPECT_FALSE(container.FindSnapPosition(*end_direction_strategy, + &snap_position, &target_elements)); + EXPECT_EQ(TargetSnapAreaElementIds(), target_elements); } TEST_F(ScrollSnapDataTest, MandatorySnapsBackwardIfNoValidAreaForward) { @@ -274,38 +316,45 @@ TEST_F(ScrollSnapDataTest, MandatorySnapsBackwardIfNoValidAreaForward) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(2000, 2000)); SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(600, 0, 100, 100), false); + gfx::RectF(600, 0, 100, 100), false, ElementId(10)); container.AddSnapAreaData(area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> direction_strategy = SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset(650, 0), gfx::ScrollOffset(5, 0)); - EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position)); + EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position, + &target_elements)); // The snap direction is right. However, there is no valid snap position on // that direction. So we have to scroll back to the snap position of 600 as // the snap type is mandatory. EXPECT_EQ(600, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); std::unique_ptr<SnapSelectionStrategy> end_direction_strategy = SnapSelectionStrategy::CreateForEndAndDirection( gfx::ScrollOffset(650, 10), gfx::ScrollOffset(15, 15)); - EXPECT_TRUE( - container.FindSnapPosition(*end_direction_strategy, &snap_position)); + EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy, + &snap_position, &target_elements)); // The snap direction is down and right. However, there is no valid snap // position on that direction. So we have to scroll back to the snap position // of (600, 0) as the snap type is mandatory. EXPECT_EQ(600, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + target_elements); // If the scroll-snap-type is proximity, we wouldn't consider the backward // snap area valid even if there is no snap area forward. container.set_scroll_snap_type( ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kProximity)); - EXPECT_FALSE(container.FindSnapPosition(*direction_strategy, &snap_position)); - EXPECT_FALSE( - container.FindSnapPosition(*end_direction_strategy, &snap_position)); + EXPECT_FALSE(container.FindSnapPosition(*direction_strategy, &snap_position, + &target_elements)); + EXPECT_FALSE(container.FindSnapPosition(*end_direction_strategy, + &snap_position, &target_elements)); + EXPECT_EQ(TargetSnapAreaElementIds(), target_elements); } TEST_F(ScrollSnapDataTest, ShouldNotPassScrollSnapStopAlwaysElement) { @@ -313,11 +362,12 @@ TEST_F(ScrollSnapDataTest, ShouldNotPassScrollSnapStopAlwaysElement) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(2000, 2000)); SnapAreaData must_snap_1(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(200, 0, 100, 100), true); + gfx::RectF(200, 0, 100, 100), true, ElementId(10)); SnapAreaData must_snap_2(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(400, 0, 100, 100), true); + gfx::RectF(400, 0, 100, 100), true, ElementId(20)); SnapAreaData closer_to_target(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(600, 0, 100, 100), false); + gfx::RectF(600, 0, 100, 100), false, + ElementId(30)); container.AddSnapAreaData(must_snap_1); container.AddSnapAreaData(must_snap_2); container.AddSnapAreaData(closer_to_target); @@ -326,14 +376,17 @@ TEST_F(ScrollSnapDataTest, ShouldNotPassScrollSnapStopAlwaysElement) { std::unique_ptr<SnapSelectionStrategy> end_direction_strategy = SnapSelectionStrategy::CreateForEndAndDirection( gfx::ScrollOffset(0, 0), gfx::ScrollOffset(600, 0)); - EXPECT_TRUE( - container.FindSnapPosition(*end_direction_strategy, &snap_position)); + + EXPECT_TRUE(container.FindSnapPosition(*end_direction_strategy, + &snap_position, &target_elements)); // Even though closer_to_target and must_snap_2 are closer to the target // position of the scroll, the must_snap_1 which is closer to the start // shouldn't be passed. EXPECT_EQ(200, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); } TEST_F(ScrollSnapDataTest, SnapStopAlwaysOverridesCoveringSnapArea) { @@ -341,9 +394,10 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysOverridesCoveringSnapArea) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData stop_area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(100, 0, 100, 100), true); + gfx::RectF(100, 0, 100, 100), true, ElementId(10)); SnapAreaData covering_area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(250, 0, 600, 600), false); + gfx::RectF(250, 0, 600, 600), false, + ElementId(20)); container.AddSnapAreaData(stop_area); container.AddSnapAreaData(covering_area); @@ -351,13 +405,17 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysOverridesCoveringSnapArea) { std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndAndDirection( gfx::ScrollOffset(0, 0), gfx::ScrollOffset(300, 0)); + // The fling is from (0, 0) to (300, 0), and the destination would make // the |covering_area| perfectly cover the snapport. However, another area // with snap-stop:always precedes this |covering_area| so we snap at // (100, 100). - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(100, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); } TEST_F(ScrollSnapDataTest, SnapStopAlwaysInReverseDirection) { @@ -365,19 +423,23 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysInReverseDirection) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 300), gfx::ScrollOffset(600, 800)); SnapAreaData stop_area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(100, 0, 100, 100), true); + gfx::RectF(100, 0, 100, 100), true, ElementId(10)); container.AddSnapAreaData(stop_area); gfx::ScrollOffset snap_position; std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndAndDirection( gfx::ScrollOffset(150, 0), gfx::ScrollOffset(200, 0)); + // The fling is from (150, 0) to (350, 0), but the snap position is in the // reverse direction at (100, 0). Since the container has mandatory for // snapstrictness, we should go back to snap at (100, 0). - EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position)); + EXPECT_TRUE( + container.FindSnapPosition(*strategy, &snap_position, &target_elements)); EXPECT_EQ(100, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); } TEST_F(ScrollSnapDataTest, SnapStopAlwaysNotInterferingWithDirectionStrategy) { @@ -385,9 +447,9 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysNotInterferingWithDirectionStrategy) { ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 300), gfx::ScrollOffset(600, 800)); SnapAreaData closer_area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(100, 0, 1, 1), false); + gfx::RectF(100, 0, 1, 1), false, ElementId(10)); SnapAreaData stop_area(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(120, 0, 1, 1), true); + gfx::RectF(120, 0, 1, 1), true, ElementId(20)); container.AddSnapAreaData(closer_area); container.AddSnapAreaData(stop_area); @@ -398,9 +460,148 @@ TEST_F(ScrollSnapDataTest, SnapStopAlwaysNotInterferingWithDirectionStrategy) { SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset(90, 0), gfx::ScrollOffset(50, 0)); snap_position = gfx::ScrollOffset(); - EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position)); + EXPECT_TRUE(container.FindSnapPosition(*direction_strategy, &snap_position, + &target_elements)); EXPECT_EQ(100, snap_position.x()); EXPECT_EQ(0, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + target_elements); +} + +TEST_F(ScrollSnapDataTest, SnapToOneTargetElementOnX) { + SnapContainerData container( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 200, 300), gfx::ScrollOffset(600, 800)); + + SnapAreaData closer_area_x(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(100, 0, 1, 1), false, ElementId(10)); + SnapAreaData target_area_x(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(200, 100, 1, 1), false, ElementId(20)); + SnapAreaData closer_area_y(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(300, 50, 1, 1), false, ElementId(30)); + + container.AddSnapAreaData(closer_area_x); + container.AddSnapAreaData(target_area_x); + container.AddSnapAreaData(closer_area_y); + container.SetTargetSnapAreaElementIds( + TargetSnapAreaElementIds(ElementId(20), ElementId())); + + // Even though closer_area_x is closer to the scroll offset, the container + // should snap to the target for the x-axis. However, since the target is not + // set for the y-axis, the target on the y-axis should be closer_area_y. + std::unique_ptr<SnapSelectionStrategy> target_element_strategy = + SnapSelectionStrategy::CreateForTargetElement(gfx::ScrollOffset(0, 0)); + + gfx::ScrollOffset snap_position = gfx::ScrollOffset(); + EXPECT_TRUE(container.FindSnapPosition(*target_element_strategy, + &snap_position, &target_elements)); + + EXPECT_EQ(200, snap_position.x()); + EXPECT_EQ(50, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(20), ElementId(30)), + target_elements); +} + +TEST_F(ScrollSnapDataTest, SnapToOneTargetElementOnY) { + SnapContainerData container( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 200, 300), gfx::ScrollOffset(600, 800)); + + SnapAreaData closer_area_y(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(0, 100, 1, 1), false, ElementId(10)); + SnapAreaData target_area_y(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(100, 200, 1, 1), false, ElementId(20)); + SnapAreaData closer_area_x(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(50, 300, 1, 1), false, ElementId(30)); + + container.AddSnapAreaData(closer_area_y); + container.AddSnapAreaData(target_area_y); + container.AddSnapAreaData(closer_area_x); + container.SetTargetSnapAreaElementIds( + TargetSnapAreaElementIds(ElementId(), ElementId(20))); + + // Even though closer_area_y is closer to the scroll offset, the container + // should snap to the target for the y-axis. However, since the target is not + // set for the x-axis, the target on the x-axis should be closer_area_x. + std::unique_ptr<SnapSelectionStrategy> target_element_strategy = + SnapSelectionStrategy::CreateForTargetElement(gfx::ScrollOffset(0, 0)); + + gfx::ScrollOffset snap_position = gfx::ScrollOffset(); + EXPECT_TRUE(container.FindSnapPosition(*target_element_strategy, + &snap_position, &target_elements)); + + EXPECT_EQ(50, snap_position.x()); + EXPECT_EQ(200, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(30), ElementId(20)), + target_elements); +} + +TEST_F(ScrollSnapDataTest, SnapToTwoTargetElementsMutualVisible) { + SnapContainerData container( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 300, 300), gfx::ScrollOffset(600, 800)); + + SnapAreaData target_area_x(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(100, 200, 1, 1), false, ElementId(10)); + SnapAreaData target_area_y(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(200, 100, 1, 1), false, ElementId(20)); + SnapAreaData closer_area_both(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(0, 0, 1, 1), false, ElementId(30)); + + container.AddSnapAreaData(target_area_x); + container.AddSnapAreaData(target_area_y); + container.AddSnapAreaData(closer_area_both); + container.SetTargetSnapAreaElementIds( + TargetSnapAreaElementIds(ElementId(10), ElementId(20))); + + // The container should snap to both target areas since they are mutually + // visible, while ignoring the snap area that is closest to the scroll offset. + std::unique_ptr<SnapSelectionStrategy> target_element_strategy = + SnapSelectionStrategy::CreateForTargetElement(gfx::ScrollOffset(0, 0)); + + gfx::ScrollOffset snap_position = gfx::ScrollOffset(); + EXPECT_TRUE(container.FindSnapPosition(*target_element_strategy, + &snap_position, &target_elements)); + + EXPECT_EQ(100, snap_position.x()); + EXPECT_EQ(100, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(20)), + target_elements); +} + +TEST_F(ScrollSnapDataTest, SnapToTwoTargetElementsNotMutualVisible) { + SnapContainerData container( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 300, 300), gfx::ScrollOffset(600, 800)); + + SnapAreaData target_area_x(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(100, 500, 1, 1), false, ElementId(10)); + SnapAreaData target_area_y(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(500, 100, 1, 1), false, ElementId(20)); + SnapAreaData area_mutually_visible_to_targets( + ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(350, 350, 1, 1), false, + ElementId(30)); + + container.AddSnapAreaData(target_area_x); + container.AddSnapAreaData(target_area_y); + container.AddSnapAreaData(area_mutually_visible_to_targets); + container.SetTargetSnapAreaElementIds( + TargetSnapAreaElementIds(ElementId(10), ElementId(20))); + + // The container cannot snap to both targets, so it should snap to the one + // closer to the scroll offset, and then snap to the closest mutually visible + // snap area on the other axis. + std::unique_ptr<SnapSelectionStrategy> target_element_strategy = + SnapSelectionStrategy::CreateForTargetElement(gfx::ScrollOffset(10, 0)); + + gfx::ScrollOffset snap_position = gfx::ScrollOffset(); + EXPECT_TRUE(container.FindSnapPosition(*target_element_strategy, + &snap_position, &target_elements)); + + EXPECT_EQ(100, snap_position.x()); + EXPECT_EQ(350, snap_position.y()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(30)), + target_elements); } } // namespace cc diff --git a/chromium/cc/input/scroll_state.cc b/chromium/cc/input/scroll_state.cc index e578c325352..521882a0636 100644 --- a/chromium/cc/input/scroll_state.cc +++ b/chromium/cc/input/scroll_state.cc @@ -6,13 +6,11 @@ #include <utility> -#include "cc/trees/layer_tree_impl.h" #include "cc/trees/scroll_node.h" namespace cc { -ScrollState::ScrollState(ScrollStateData data) - : data_(data), layer_tree_impl_(nullptr) {} +ScrollState::ScrollState(ScrollStateData data) : data_(data) {} ScrollState::ScrollState(const ScrollState& other) = default; @@ -26,14 +24,4 @@ void ScrollState::ConsumeDelta(double x, double y) { data_.delta_consumed_for_scroll_sequence = true; } -void ScrollState::DistributeToScrollChainDescendant() { - if (!scroll_chain_.empty()) { - ScrollNode* next = scroll_chain_.front(); - scroll_chain_.pop_front(); - - ScrollTree& scroll_tree = layer_tree_impl_->property_trees()->scroll_tree; - scroll_tree.DistributeScroll(next, this); - } -} - } // namespace cc diff --git a/chromium/cc/input/scroll_state.h b/chromium/cc/input/scroll_state.h index 658d356dc91..ff68e3cdcac 100644 --- a/chromium/cc/input/scroll_state.h +++ b/chromium/cc/input/scroll_state.h @@ -15,8 +15,6 @@ namespace cc { -class LayerTreeImpl; - // ScrollState is based on the proposal for scroll customization in blink, found // here: https://goo.gl/1ipTpP. class CC_EXPORT ScrollState { @@ -27,9 +25,6 @@ class CC_EXPORT ScrollState { // Reduce deltas by x, y. void ConsumeDelta(double x, double y); - // Pops the first layer off of |scroll_chain_| and calls - // |DistributeScroll| on it. - void DistributeToScrollChainDescendant(); // Positive when scrolling right. double delta_x() const { return data_.delta_x; } // Positive when scrolling down. @@ -63,13 +58,6 @@ class CC_EXPORT ScrollState { data_.is_direct_manipulation = is_direct_manipulation; } - void set_scroll_chain_and_layer_tree( - const std::list<ScrollNode*>& scroll_chain, - LayerTreeImpl* layer_tree_impl) { - layer_tree_impl_ = layer_tree_impl; - scroll_chain_ = scroll_chain; - } - void set_current_native_scrolling_node(ScrollNode* scroll_node) { data_.set_current_native_scrolling_node(scroll_node); } @@ -85,8 +73,6 @@ class CC_EXPORT ScrollState { data_.delta_consumed_for_scroll_sequence = delta_consumed; } - bool FullyConsumed() const { return !data_.delta_x && !data_.delta_y; } - void set_caused_scroll(bool x, bool y) { data_.caused_scroll_x |= x; data_.caused_scroll_y |= y; @@ -101,13 +87,10 @@ class CC_EXPORT ScrollState { double delta_granularity() const { return data_.delta_granularity; } - LayerTreeImpl* layer_tree_impl() { return layer_tree_impl_; } ScrollStateData* data() { return &data_; } private: ScrollStateData data_; - LayerTreeImpl* layer_tree_impl_; - std::list<ScrollNode*> scroll_chain_; }; } // namespace cc diff --git a/chromium/cc/input/scroll_state_data.h b/chromium/cc/input/scroll_state_data.h index c3f2e1c5f1e..3a325134bb4 100644 --- a/chromium/cc/input/scroll_state_data.h +++ b/chromium/cc/input/scroll_state_data.h @@ -77,9 +77,13 @@ class CC_EXPORT ScrollStateData { // possible, we should store the scroll node. // The last scroll node to respond to a scroll, or null if none exists. + // TODO(bokan): This is redundant with the member below. ScrollNode* current_native_scrolling_node_; // The id of the last native element to respond to a scroll, or 0 if none // exists. + // TODO(bokan): In the compositor, this is now only used as an override to + // scroller targeting, i.e. we'll latch scrolling to the specified + // element_id. It will be renamed when the main thread is also converted. ElementId current_native_scrolling_element_; }; diff --git a/chromium/cc/input/scroll_state_unittest.cc b/chromium/cc/input/scroll_state_unittest.cc index b0ce86ac9b1..730d635bd19 100644 --- a/chromium/cc/input/scroll_state_unittest.cc +++ b/chromium/cc/input/scroll_state_unittest.cc @@ -32,29 +32,24 @@ TEST_F(ScrollStateTest, ConsumeDeltaNative) { EXPECT_FLOAT_EQ(delta_x, scroll_state.delta_x()); EXPECT_FLOAT_EQ(delta_y, scroll_state.delta_y()); EXPECT_FALSE(scroll_state.delta_consumed_for_scroll_sequence()); - EXPECT_FALSE(scroll_state.FullyConsumed()); scroll_state.ConsumeDelta(0, 0); EXPECT_FLOAT_EQ(delta_x, scroll_state.delta_x()); EXPECT_FLOAT_EQ(delta_y, scroll_state.delta_y()); EXPECT_FALSE(scroll_state.delta_consumed_for_scroll_sequence()); - EXPECT_FALSE(scroll_state.FullyConsumed()); scroll_state.ConsumeDelta(delta_x_to_consume, 0); EXPECT_FLOAT_EQ(delta_x - delta_x_to_consume, scroll_state.delta_x()); EXPECT_FLOAT_EQ(delta_y, scroll_state.delta_y()); EXPECT_TRUE(scroll_state.delta_consumed_for_scroll_sequence()); - EXPECT_FALSE(scroll_state.FullyConsumed()); scroll_state.ConsumeDelta(0, delta_y_to_consume); EXPECT_FLOAT_EQ(delta_x - delta_x_to_consume, scroll_state.delta_x()); EXPECT_FLOAT_EQ(delta_y - delta_y_to_consume, scroll_state.delta_y()); EXPECT_TRUE(scroll_state.delta_consumed_for_scroll_sequence()); - EXPECT_FALSE(scroll_state.FullyConsumed()); scroll_state.ConsumeDelta(scroll_state.delta_x(), scroll_state.delta_y()); EXPECT_TRUE(scroll_state.delta_consumed_for_scroll_sequence()); - EXPECT_TRUE(scroll_state.FullyConsumed()); } TEST_F(ScrollStateTest, CurrentNativeScrollingScrollable) { @@ -73,15 +68,4 @@ TEST_F(ScrollStateTest, CurrentNativeScrollingScrollable) { scroll_state.set_current_native_scrolling_node(scroll_node); EXPECT_EQ(scroll_node, scroll_state.current_native_scrolling_node()); } - -TEST_F(ScrollStateTest, FullyConsumed) { - ScrollStateData scroll_state_data; - scroll_state_data.delta_x = 1; - scroll_state_data.delta_y = 3; - ScrollState scroll_state(scroll_state_data); - - EXPECT_FALSE(scroll_state.FullyConsumed()); - scroll_state.ConsumeDelta(1, 3); - EXPECT_TRUE(scroll_state.FullyConsumed()); -} } // namespace cc diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h index 4c739c69dba..2a5e6cb571e 100644 --- a/chromium/cc/input/scrollbar.h +++ b/chromium/cc/input/scrollbar.h @@ -5,6 +5,7 @@ #ifndef CC_INPUT_SCROLLBAR_H_ #define CC_INPUT_SCROLLBAR_H_ +#include "base/memory/ref_counted.h" #include "cc/cc_export.h" #include "cc/paint/paint_canvas.h" #include "ui/gfx/geometry/point.h" @@ -33,8 +34,7 @@ enum ScrollbarOrientation { HORIZONTAL, VERTICAL }; enum ScrollbarPart { THUMB, - TRACK, - TICKMARKS, + TRACK_BUTTONS_TICKMARKS, // for PartNeedsRepaint() and PaintPart() only. BACK_BUTTON, FORWARD_BUTTON, BACK_TRACK, @@ -42,41 +42,45 @@ enum ScrollbarPart { NO_PART, }; -class Scrollbar { +class Scrollbar : public base::RefCounted<Scrollbar> { public: - virtual ~Scrollbar() {} - virtual ScrollbarOrientation Orientation() const = 0; virtual bool IsLeftSideVerticalScrollbar() const = 0; - virtual gfx::Point Location() const = 0; + virtual bool IsSolidColor() const = 0; virtual bool IsOverlay() const = 0; virtual bool HasThumb() const = 0; virtual bool SupportsDragSnapBack() const = 0; - virtual int ThumbThickness() const = 0; - virtual int ThumbLength() const = 0; - // Returns the track rect relative to the scrollbar's origin. + // The following rects are all relative to the scrollbar's origin. + // The location of ThumbRect reflects scroll offset, but cc will ignore it + // because the compositor thread will compute thumb location from scroll + // offset. + virtual gfx::Rect ThumbRect() const = 0; virtual gfx::Rect TrackRect() const = 0; - // Returns the back button rect relative to the scrollbar's origin. virtual gfx::Rect BackButtonRect() const = 0; - // Returns the forward button rect relative to the scrollbar's origin. virtual gfx::Rect ForwardButtonRect() const = 0; virtual float ThumbOpacity() const = 0; virtual bool HasTickmarks() const = 0; - // Whether we need to repaint the part. Only THUMB and TRACK are supported. - // For TRACK, the return value means that the track, any buttons or tickmarks - // need repaint. - virtual bool NeedsPaintPart(ScrollbarPart part) const = 0; - // Paints the part. Only THUMB, TRACK and TICKMARKS are supported. When TRACK - // is specified, track, buttons and tickmarks will be painted. The canvas's - // coordinate space is relative to the part's origin. - virtual void PaintPart(PaintCanvas* canvas, ScrollbarPart part) = 0; + // Whether we need to repaint the part. Only THUMB and TRACK_BUTTONS_TICKMARKS + // are supported. + virtual bool NeedsRepaintPart(ScrollbarPart part) const = 0; + + // Paints the part in the given rect. The implementation should paint + // relative to the rect, and doesn't need to know the current coordinate + // space of |canvas|. Only THUMB, TRACK_BUTTONS_TICKMARKS are supported. + virtual void PaintPart(PaintCanvas* canvas, + ScrollbarPart part, + const gfx::Rect& rect) = 0; virtual bool UsesNinePatchThumbResource() const = 0; virtual gfx::Size NinePatchThumbCanvasSize() const = 0; virtual gfx::Rect NinePatchThumbAperture() const = 0; + + protected: + friend class base::RefCounted<Scrollbar>; + virtual ~Scrollbar() {} }; } // namespace cc diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc index 2f4221e3d59..62f433c9440 100644 --- a/chromium/cc/input/scrollbar_controller.cc +++ b/chromium/cc/input/scrollbar_controller.cc @@ -25,7 +25,6 @@ ScrollbarController::ScrollbarController( LayerTreeHostImpl* layer_tree_host_impl) : layer_tree_host_impl_(layer_tree_host_impl), scrollbar_scroll_is_active_(false), - currently_captured_scrollbar_(nullptr), last_known_pointer_position_(gfx::PointF(0, 0)), drag_processed_for_current_frame_(false), cancelable_autoscroll_task_(nullptr) {} @@ -36,20 +35,34 @@ void ScrollbarController::WillBeginImplFrame() { } gfx::Vector2dF ScrollbarController::GetThumbRelativePoint( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF position_in_widget) { bool clipped; const gfx::PointF position_in_layer = - GetScrollbarRelativePosition(position_in_widget, &clipped); + GetScrollbarRelativePosition(scrollbar, position_in_widget, &clipped); if (clipped) return gfx::Vector2d(0, 0); - const gfx::RectF thumb_rect( - currently_captured_scrollbar_->ComputeThumbQuadRect()); + const gfx::RectF thumb_rect(scrollbar->ComputeThumbQuadRect()); DCHECK(thumb_rect.Contains(position_in_layer)); return position_in_layer - gfx::PointF(thumb_rect.origin()); } +// Retrieves the ScrollbarLayerImplBase corresponding to the stashed ElementId. +ScrollbarLayerImplBase* ScrollbarController::ScrollbarLayer() { + if (!captured_scrollbar_metadata_.has_value()) + return nullptr; + + const ScrollbarSet scrollbars = layer_tree_host_impl_->ScrollbarsFor( + captured_scrollbar_metadata_->scroll_element_id); + for (ScrollbarLayerImplBase* scrollbar : scrollbars) { + if (captured_scrollbar_metadata_->orientation == scrollbar->orientation()) + return scrollbar; + } + return nullptr; +} + // Performs hit test and prepares scroll deltas that will be used by GSB and // GSU. InputHandlerPointerResult ScrollbarController::HandlePointerDown( @@ -65,30 +78,32 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown( if (!(layer_impl && layer_impl->ToScrollbarLayer())) return InputHandlerPointerResult(); - currently_captured_scrollbar_ = layer_impl->ToScrollbarLayer(); + const ScrollbarLayerImplBase* scrollbar = layer_impl->ToScrollbarLayer(); + captured_scrollbar_metadata_ = CapturedScrollbarMetadata(); + captured_scrollbar_metadata_->scroll_element_id = + scrollbar->scroll_element_id(); + captured_scrollbar_metadata_->orientation = scrollbar->orientation(); + InputHandlerPointerResult scroll_result; - scroll_result.target_scroller = - currently_captured_scrollbar_->scroll_element_id(); + scroll_result.target_scroller = scrollbar->scroll_element_id(); scroll_result.type = PointerResultType::kScrollbarScroll; layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); const ScrollbarPart scrollbar_part = - GetScrollbarPartFromPointerDown(position_in_widget); + GetScrollbarPartFromPointerDown(scrollbar, position_in_widget); scroll_result.scroll_offset = GetScrollOffsetForScrollbarPart( - scrollbar_part, currently_captured_scrollbar_->orientation(), - shift_modifier); + scrollbar, scrollbar_part, shift_modifier); last_known_pointer_position_ = position_in_widget; scrollbar_scroll_is_active_ = true; scroll_result.scroll_units = Granularity(scrollbar_part, shift_modifier); if (scrollbar_part == ScrollbarPart::THUMB) { drag_state_ = DragState(); drag_state_->anchor_relative_to_thumb_ = - GetThumbRelativePoint(position_in_widget); + GetThumbRelativePoint(scrollbar, position_in_widget); // Record the current scroller offset. This will be needed to snap the // thumb back to its original position if the pointer moves too far away // from the track during a thumb drag. - drag_state_->scroll_position_at_start_ = - currently_captured_scrollbar_->current_pos(); + drag_state_->scroll_position_at_start_ = scrollbar->current_pos(); } if (!scroll_result.scroll_offset.IsZero()) { @@ -97,13 +112,12 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown( // have the potential of initiating an autoscroll (if held down for long // enough). DCHECK(scrollbar_part != ScrollbarPart::THUMB); - cancelable_autoscroll_task_ = - std::make_unique<base::CancelableClosure>(base::Bind( - &ScrollbarController::StartAutoScrollAnimation, - base::Unretained(this), - InitialDeltaToAutoscrollVelocity(scroll_result.scroll_offset), - currently_captured_scrollbar_->scroll_element_id(), - scrollbar_part)); + cancelable_autoscroll_task_ = std::make_unique<base::CancelableOnceClosure>( + base::BindOnce(&ScrollbarController::StartAutoScrollAnimation, + base::Unretained(this), + InitialDeltaToAutoscrollVelocity( + scrollbar, scroll_result.scroll_offset), + scrollbar, scrollbar_part)); layer_tree_host_impl_->task_runner_provider() ->ImplThreadTaskRunner() ->PostDelayedTask(FROM_HERE, cancelable_autoscroll_task_->callback(), @@ -113,24 +127,23 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown( } bool ScrollbarController::SnapToDragOrigin( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF pointer_position_in_widget) { // Consult the ScrollbarTheme to check if thumb snapping is supported on the // current platform. - if (!currently_captured_scrollbar_->SupportsDragSnapBack()) + if (!(scrollbar && scrollbar->SupportsDragSnapBack())) return false; bool clipped = false; - const gfx::PointF pointer_position_in_layer = - GetScrollbarRelativePosition(pointer_position_in_widget, &clipped); + const gfx::PointF pointer_position_in_layer = GetScrollbarRelativePosition( + scrollbar, pointer_position_in_widget, &clipped); if (clipped) return false; layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); - const ScrollbarOrientation orientation = - currently_captured_scrollbar_->orientation(); - const gfx::Rect forward_track_rect = - currently_captured_scrollbar_->ForwardTrackRect(); + const ScrollbarOrientation orientation = scrollbar->orientation(); + const gfx::Rect forward_track_rect = scrollbar->ForwardTrackRect(); // When dragging the thumb, there needs to exist "gutters" on either side of // the track. The thickness of these gutters is a multiple of the track (or @@ -146,7 +159,7 @@ bool ScrollbarController::SnapToDragOrigin( if (!track_thickness) { // For overlay scrollbars (or for tests that do not set up a track // thickness), use the thumb_thickness instead to determine the gutters. - const int thumb_thickness = currently_captured_scrollbar_->ThumbThickness(); + const int thumb_thickness = scrollbar->ThumbThickness(); // If the thumb doesn't have thickness, the gutters can't be determined. // Snapping shouldn't occur in this case. @@ -188,62 +201,60 @@ ui::input_types::ScrollGranularity ScrollbarController::Granularity( return ui::input_types::ScrollGranularity::kScrollByPixel; } -float ScrollbarController::GetScrollDeltaForShiftClick() { +float ScrollbarController::GetScrollDeltaForAbsoluteJump( + const ScrollbarLayerImplBase* scrollbar) { layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); bool clipped = false; - const gfx::PointF pointer_position_in_layer = - GetScrollbarRelativePosition(last_known_pointer_position_, &clipped); + const gfx::PointF pointer_position_in_layer = GetScrollbarRelativePosition( + scrollbar, last_known_pointer_position_, &clipped); if (clipped) return 0; - const ScrollbarOrientation orientation = - currently_captured_scrollbar_->orientation(); - const float pointer_location = orientation == ScrollbarOrientation::VERTICAL - ? pointer_position_in_layer.y() - : pointer_position_in_layer.x(); + const float pointer_location = + scrollbar->orientation() == ScrollbarOrientation::VERTICAL + ? pointer_position_in_layer.y() + : pointer_position_in_layer.x(); // During a shift + click, the pointers current location (on the track) needs // to be considered as the center of the thumb and the thumb origin needs to // be calculated based on that. This will ensure that when shift + click is // processed, the thumb will be centered on the pointer. - const int thumb_length = currently_captured_scrollbar_->ThumbLength(); + const int thumb_length = scrollbar->ThumbLength(); const float desired_thumb_origin = pointer_location - thumb_length / 2.f; - const gfx::Rect thumb_rect( - currently_captured_scrollbar_->ComputeThumbQuadRect()); + const gfx::Rect thumb_rect(scrollbar->ComputeThumbQuadRect()); const float current_thumb_origin = - orientation == ScrollbarOrientation::VERTICAL ? thumb_rect.y() - : thumb_rect.x(); + scrollbar->orientation() == ScrollbarOrientation::VERTICAL + ? thumb_rect.y() + : thumb_rect.x(); const float delta = round(std::abs(desired_thumb_origin - current_thumb_origin)); - return delta * GetScrollerToScrollbarRatio(); + return delta * GetScrollerToScrollbarRatio(scrollbar); } gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF pointer_position_in_widget) { layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); - const ScrollbarOrientation orientation = - currently_captured_scrollbar_->orientation(); - if (SnapToDragOrigin(pointer_position_in_widget)) { - const float delta = currently_captured_scrollbar_->current_pos() - - drag_state_->scroll_position_at_start_; - return orientation == ScrollbarOrientation::VERTICAL + if (SnapToDragOrigin(scrollbar, pointer_position_in_widget)) { + const float delta = + scrollbar->current_pos() - drag_state_->scroll_position_at_start_; + return scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::ScrollOffset(0, -delta) : gfx::ScrollOffset(-delta, 0); } - const gfx::Rect thumb_rect( - currently_captured_scrollbar_->ComputeThumbQuadRect()); + const gfx::Rect thumb_rect(scrollbar->ComputeThumbQuadRect()); const gfx::PointF drag_position_relative_to_layer = gfx::PointF(thumb_rect.origin()) + drag_state_->anchor_relative_to_thumb_; bool clipped = false; - const gfx::PointF pointer_position_in_layer = - GetScrollbarRelativePosition(pointer_position_in_widget, &clipped); + const gfx::PointF pointer_position_in_layer = GetScrollbarRelativePosition( + scrollbar, pointer_position_in_widget, &clipped); if (clipped) return gfx::ScrollOffset(0, 0); @@ -252,8 +263,9 @@ gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition( const gfx::Vector2dF pointer_delta = pointer_position_in_layer - drag_position_relative_to_layer; - float scaled_scroller_to_scrollbar_ratio = GetScrollerToScrollbarRatio(); - float current_scroll_position = currently_captured_scrollbar_->current_pos(); + float scaled_scroller_to_scrollbar_ratio = + GetScrollerToScrollbarRatio(scrollbar); + float current_scroll_position = scrollbar->current_pos(); // Thumb position needs to be floored and Values between 0 and 1 are rounded // to one to match main thread per pixel behavior. Corresponding main thread @@ -264,9 +276,10 @@ gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition( ? 1.0 : floorf(thumb_position); - float delta_in_orientation = orientation == ScrollbarOrientation::VERTICAL - ? pointer_delta.y() - : pointer_delta.x(); + float delta_in_orientation = + scrollbar->orientation() == ScrollbarOrientation::VERTICAL + ? pointer_delta.y() + : pointer_delta.x(); // This is effectively equal to delta_in_orientation * // scaled_scroller_to_scrollbar_ratio but is necessary due to truncated delta @@ -280,7 +293,7 @@ gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition( gfx::ScrollOffset scaled_thumb_drag_delta; // Scroll delta floored to match main thread per pixel behavior - orientation == ScrollbarOrientation::VERTICAL + scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? scaled_thumb_drag_delta.set_y(floorf(scroll_delta)) : scaled_thumb_drag_delta.set_x(floorf(scroll_delta)); @@ -297,7 +310,9 @@ InputHandlerPointerResult ScrollbarController::HandlePointerMove( // If a thumb drag is not in progress or if a GSU was already produced for a // thumb drag in this frame, there's no point in continuing on. Please see the // header file for details. - if (!drag_state_.has_value() || drag_processed_for_current_frame_) + const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer(); + if (!scrollbar || !drag_state_.has_value() || + drag_processed_for_current_frame_) return scroll_result; const ScrollNode* currently_scrolling_node = @@ -312,7 +327,7 @@ InputHandlerPointerResult ScrollbarController::HandlePointerMove( // If scroll_offset can't be consumed, there's no point in continuing on. const gfx::ScrollOffset scroll_offset( - GetScrollOffsetForDragPosition(position_in_widget)); + GetScrollOffsetForDragPosition(scrollbar, position_in_widget)); const gfx::Vector2dF clamped_scroll_offset( layer_tree_host_impl_->ComputeScrollDelta( *currently_scrolling_node, ScrollOffsetToVector2dF(scroll_offset))); @@ -331,14 +346,14 @@ InputHandlerPointerResult ScrollbarController::HandlePointerMove( return scroll_result; } -float ScrollbarController::GetScrollerToScrollbarRatio() { +float ScrollbarController::GetScrollerToScrollbarRatio( + const ScrollbarLayerImplBase* scrollbar) { // Calculating the delta by which the scroller layer should move when // dragging the thumb depends on the following factors: // - scrollbar_track_length // - scrollbar_thumb_length // - scroll_layer_length // - viewport_length - // - device_scale_factor // - position_in_widget // // When a thumb drag is in progress, for every pixel that the pointer moves, @@ -348,6 +363,8 @@ float ScrollbarController::GetScrollerToScrollbarRatio() { // (scroll_layer_length - viewport_length) / // (scrollbar_track_length - scrollbar_thumb_length) // + // PS: Note that since this is a "ratio", it need not be scaled by the DSF. + // // |<--------------------- scroll_layer_length -------------------------->| // // +------------------------------------------------+...................... @@ -371,50 +388,51 @@ float ScrollbarController::GetScrollerToScrollbarRatio() { // |<- scrollbar_thumb_length ->| // layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); - float scroll_layer_length = - currently_captured_scrollbar_->scroll_layer_length(); - float scrollbar_track_length = currently_captured_scrollbar_->TrackLength(); - gfx::Rect thumb_rect(currently_captured_scrollbar_->ComputeThumbQuadRect()); - const ScrollbarOrientation orientation = - currently_captured_scrollbar_->orientation(); - float scrollbar_thumb_length = orientation == ScrollbarOrientation::VERTICAL - ? thumb_rect.height() - : thumb_rect.width(); + float scroll_layer_length = scrollbar->scroll_layer_length(); + float scrollbar_track_length = scrollbar->TrackLength(); + gfx::Rect thumb_rect(scrollbar->ComputeThumbQuadRect()); + float scrollbar_thumb_length = + scrollbar->orientation() == ScrollbarOrientation::VERTICAL + ? thumb_rect.height() + : thumb_rect.width(); const LayerImpl* owner_scroll_layer = layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId( - currently_captured_scrollbar_->scroll_element_id()); + scrollbar->scroll_element_id()); const float viewport_length = - orientation == ScrollbarOrientation::VERTICAL + scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? owner_scroll_layer->scroll_container_bounds().height() : (owner_scroll_layer->scroll_container_bounds().width()); - // For platforms which have use_zoom_for_dsf set to false (like Mac), the - // device_scale_factor should not be used while determining the - // scaled_scroller_to_scrollbar_ratio as thumb drag would appear jittery due - // to constant over and under corrections. - // (See ScrollbarController::ScreenSpaceScaleFactor()). - float scaled_scroller_to_scrollbar_ratio = - ((scroll_layer_length - viewport_length) / - (scrollbar_track_length - scrollbar_thumb_length)) * - ScreenSpaceScaleFactor(); + return ((scroll_layer_length - viewport_length) / + (scrollbar_track_length - scrollbar_thumb_length)); +} - return scaled_scroller_to_scrollbar_ratio; +void ScrollbarController::ResetState() { + drag_processed_for_current_frame_ = false; + drag_state_ = base::nullopt; + autoscroll_state_ = base::nullopt; + captured_scrollbar_metadata_ = base::nullopt; +} + +void ScrollbarController::DidUnregisterScrollbar(ElementId element_id) { + if (captured_scrollbar_metadata_.has_value() && + captured_scrollbar_metadata_->scroll_element_id == element_id) + ResetState(); } void ScrollbarController::RecomputeAutoscrollStateIfNeeded() { - if (!autoscroll_state_.has_value()) + if (!autoscroll_state_.has_value() || + !captured_scrollbar_metadata_.has_value()) return; layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); - const ScrollbarOrientation orientation = - currently_captured_scrollbar_->orientation(); - const gfx::Rect thumb_quad = - currently_captured_scrollbar_->ComputeThumbQuadRect(); + const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer(); + const gfx::Rect thumb_quad = scrollbar->ComputeThumbQuadRect(); bool clipped; - gfx::PointF scroller_relative_position( - GetScrollbarRelativePosition(last_known_pointer_position_, &clipped)); + gfx::PointF scroller_relative_position(GetScrollbarRelativePosition( + scrollbar, last_known_pointer_position_, &clipped)); if (clipped) return; @@ -425,7 +443,7 @@ void ScrollbarController::RecomputeAutoscrollStateIfNeeded() { int thumb_start = 0; int thumb_end = 0; int pointer_position = 0; - if (orientation == ScrollbarOrientation::VERTICAL) { + if (scrollbar->orientation() == ScrollbarOrientation::VERTICAL) { thumb_start = thumb_quad.y(); thumb_end = thumb_quad.y() + thumb_quad.height(); pointer_position = scroller_relative_position.y(); @@ -451,48 +469,45 @@ void ScrollbarController::RecomputeAutoscrollStateIfNeeded() { // always has a constant value to animate to (which is '0'. See the function // ScrollbarController::StartAutoScrollAnimation). if (autoscroll_state_->direction == AutoScrollDirection::AUTOSCROLL_FORWARD) { - const float scroll_layer_length = - currently_captured_scrollbar_->scroll_layer_length(); + const float scroll_layer_length = scrollbar->scroll_layer_length(); if (autoscroll_state_->scroll_layer_length != scroll_layer_length) { layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); - StartAutoScrollAnimation( - autoscroll_state_->velocity, - currently_captured_scrollbar_->scroll_element_id(), - autoscroll_state_->pressed_scrollbar_part); + StartAutoScrollAnimation(autoscroll_state_->velocity, scrollbar, + autoscroll_state_->pressed_scrollbar_part); } } // The animations need to be aborted/restarted based on the pointer location // (i.e leaving/entering the track/arrows, reaching the track end etc). The // autoscroll_state_ however, needs to be reset on pointer changes. - const gfx::RectF scrollbar_part_rect( - GetRectForScrollbarPart(autoscroll_state_->pressed_scrollbar_part)); + const gfx::RectF scrollbar_part_rect(GetRectForScrollbarPart( + scrollbar, autoscroll_state_->pressed_scrollbar_part)); if (!scrollbar_part_rect.Contains(scroller_relative_position)) { // Stop animating if pointer moves outside the rect bounds. layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort(); } else if (scrollbar_part_rect.Contains(scroller_relative_position) && !layer_tree_host_impl_->mutator_host()->IsElementAnimating( - currently_captured_scrollbar_->scroll_element_id())) { + scrollbar->scroll_element_id())) { // Start animating if pointer re-enters the bounds. - StartAutoScrollAnimation(autoscroll_state_->velocity, - currently_captured_scrollbar_->scroll_element_id(), + StartAutoScrollAnimation(autoscroll_state_->velocity, scrollbar, autoscroll_state_->pressed_scrollbar_part); } } // Helper to calculate the autoscroll velocity. float ScrollbarController::InitialDeltaToAutoscrollVelocity( + const ScrollbarLayerImplBase* scrollbar, gfx::ScrollOffset scroll_offset) const { - const float scroll_delta = currently_captured_scrollbar_->orientation() == - ScrollbarOrientation::VERTICAL - ? scroll_offset.y() - : scroll_offset.x(); + const float scroll_delta = + scrollbar->orientation() == ScrollbarOrientation::VERTICAL + ? scroll_offset.y() + : scroll_offset.x(); return scroll_delta * kAutoscrollMultiplier; } void ScrollbarController::StartAutoScrollAnimation( const float velocity, - ElementId element_id, + const ScrollbarLayerImplBase* scrollbar, ScrollbarPart pressed_scrollbar_part) { // Autoscroll and thumb drag are mutually exclusive. Both can't be active at // the same time. @@ -503,17 +518,14 @@ void ScrollbarController::StartAutoScrollAnimation( // don't need to create any animation for it. ScrollTree& scroll_tree = layer_tree_host_impl_->active_tree()->property_trees()->scroll_tree; - ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id); + ScrollNode* scroll_node = + scroll_tree.FindNodeFromElementId(scrollbar->scroll_element_id()); if (!(scroll_node && scrollbar_scroll_is_active_)) return; layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); - - // TODO(arakeri): The animation needs to be readjusted if the scroller length - // changes. Tracked here: crbug.com/972485 - float scroll_layer_length = - currently_captured_scrollbar_->scroll_layer_length(); + float scroll_layer_length = scrollbar->scroll_layer_length(); gfx::ScrollOffset current_offset = scroll_tree.current_scroll_offset(scroll_node->element_id); @@ -523,8 +535,7 @@ void ScrollbarController::StartAutoScrollAnimation( // value indicates forwards scrolling. const float target_offset = velocity < 0 ? 0 : scroll_layer_length; const gfx::Vector2dF target_offset_vector = - currently_captured_scrollbar_->orientation() == - ScrollbarOrientation::VERTICAL + scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::Vector2dF(current_offset.x(), target_offset) : gfx::Vector2dF(target_offset, current_offset.y()); @@ -560,8 +571,7 @@ InputHandlerPointerResult ScrollbarController::HandlePointerUp( cancelable_autoscroll_task_.reset(); } - drag_state_ = base::nullopt; - autoscroll_state_ = base::nullopt; + ResetState(); return scroll_result; } @@ -580,6 +590,7 @@ LayerImpl* ScrollbarController::GetLayerHitByPoint( } int ScrollbarController::GetScrollDeltaForScrollbarPart( + const ScrollbarLayerImplBase* scrollbar, const ScrollbarPart scrollbar_part, const bool shift_modifier) { int scroll_delta = 0; @@ -589,20 +600,19 @@ int ScrollbarController::GetScrollDeltaForScrollbarPart( switch (scrollbar_part) { case ScrollbarPart::BACK_BUTTON: case ScrollbarPart::FORWARD_BUTTON: - scroll_delta = kPixelsPerLineStep; + scroll_delta = kPixelsPerLineStep * ScreenSpaceScaleFactor(); break; case ScrollbarPart::BACK_TRACK: case ScrollbarPart::FORWARD_TRACK: if (shift_modifier) { - scroll_delta = GetScrollDeltaForShiftClick(); + scroll_delta = GetScrollDeltaForAbsoluteJump(scrollbar); break; } owner_scroll_layer = layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId( - currently_captured_scrollbar_->scroll_element_id()); + scrollbar->scroll_element_id()); viewport_length = - currently_captured_scrollbar_->orientation() == - ScrollbarOrientation::VERTICAL + scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? owner_scroll_layer->scroll_container_bounds().height() : (owner_scroll_layer->scroll_container_bounds().width()); scroll_delta = viewport_length * kMinFractionToStepWhenPaging; @@ -611,7 +621,7 @@ int ScrollbarController::GetScrollDeltaForScrollbarPart( scroll_delta = 0; } - return scroll_delta * ScreenSpaceScaleFactor(); + return scroll_delta; } float ScrollbarController::ScreenSpaceScaleFactor() const { @@ -622,11 +632,13 @@ float ScrollbarController::ScreenSpaceScaleFactor() const { // on arrows would be incorrectly calculated as 80px instead of 40px. This is // also necessary to ensure that hit testing works as intended. return layer_tree_host_impl_->settings().use_zoom_for_dsf - ? layer_tree_host_impl_->active_tree()->device_scale_factor() + ? layer_tree_host_impl_->active_tree() + ->painted_device_scale_factor() : 1.f; } gfx::PointF ScrollbarController::GetScrollbarRelativePosition( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF position_in_widget, bool* clipped) { gfx::Transform inverse_screen_space_transform( @@ -639,7 +651,7 @@ gfx::PointF ScrollbarController::GetScrollbarRelativePosition( ? 1.f / layer_tree_host_impl_->active_tree()->device_scale_factor() : 1.f; gfx::Transform scaled_screen_space_transform( - currently_captured_scrollbar_->ScreenSpaceTransform()); + scrollbar->ScreenSpaceTransform()); scaled_screen_space_transform.PostScale(scale, scale); if (!scaled_screen_space_transform.GetInverse( &inverse_screen_space_transform)) @@ -651,60 +663,61 @@ gfx::PointF ScrollbarController::GetScrollbarRelativePosition( // Determines the ScrollbarPart based on the position_in_widget. ScrollbarPart ScrollbarController::GetScrollbarPartFromPointerDown( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF position_in_widget) { // position_in_widget needs to be transformed and made relative to the // scrollbar layer because hit testing assumes layer relative coordinates. bool clipped = false; const gfx::PointF scroller_relative_position( - GetScrollbarRelativePosition(position_in_widget, &clipped)); + GetScrollbarRelativePosition(scrollbar, position_in_widget, &clipped)); if (clipped) return ScrollbarPart::NO_PART; - return currently_captured_scrollbar_->IdentifyScrollbarPart( - scroller_relative_position); + return scrollbar->IdentifyScrollbarPart(scroller_relative_position); } // Determines the corresponding rect for the given scrollbar part. gfx::Rect ScrollbarController::GetRectForScrollbarPart( + const ScrollbarLayerImplBase* scrollbar, const ScrollbarPart scrollbar_part) { if (scrollbar_part == ScrollbarPart::BACK_BUTTON) - return currently_captured_scrollbar_->BackButtonRect(); + return scrollbar->BackButtonRect(); if (scrollbar_part == ScrollbarPart::FORWARD_BUTTON) - return currently_captured_scrollbar_->ForwardButtonRect(); + return scrollbar->ForwardButtonRect(); if (scrollbar_part == ScrollbarPart::BACK_TRACK) - return currently_captured_scrollbar_->BackTrackRect(); + return scrollbar->BackTrackRect(); if (scrollbar_part == ScrollbarPart::FORWARD_TRACK) - return currently_captured_scrollbar_->ForwardTrackRect(); + return scrollbar->ForwardTrackRect(); return gfx::Rect(0, 0); } // Determines the scroll offsets based on the ScrollbarPart and the scrollbar // orientation. gfx::ScrollOffset ScrollbarController::GetScrollOffsetForScrollbarPart( + const ScrollbarLayerImplBase* scrollbar, const ScrollbarPart scrollbar_part, - const ScrollbarOrientation orientation, const bool shift_modifier) { float scroll_delta = - GetScrollDeltaForScrollbarPart(scrollbar_part, shift_modifier); + GetScrollDeltaForScrollbarPart(scrollbar, scrollbar_part, shift_modifier); // See CreateScrollStateForGesture for more information on how these values // will be interpreted. if (scrollbar_part == ScrollbarPart::BACK_BUTTON) { - return orientation == ScrollbarOrientation::VERTICAL + return scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::ScrollOffset(0, -scroll_delta) // Up arrow : gfx::ScrollOffset(-scroll_delta, 0); // Left arrow } else if (scrollbar_part == ScrollbarPart::FORWARD_BUTTON) { - return orientation == ScrollbarOrientation::VERTICAL + return scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::ScrollOffset(0, scroll_delta) // Down arrow : gfx::ScrollOffset(scroll_delta, 0); // Right arrow } else if (scrollbar_part == ScrollbarPart::BACK_TRACK) { - return orientation == ScrollbarOrientation::VERTICAL + return scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::ScrollOffset(0, -scroll_delta) // Track click up : gfx::ScrollOffset(-scroll_delta, 0); // Track click left } else if (scrollbar_part == ScrollbarPart::FORWARD_TRACK) { - return orientation == ScrollbarOrientation::VERTICAL + return scrollbar->orientation() == ScrollbarOrientation::VERTICAL ? gfx::ScrollOffset(0, scroll_delta) // Track click down : gfx::ScrollOffset(scroll_delta, 0); // Track click right } diff --git a/chromium/cc/input/scrollbar_controller.h b/chromium/cc/input/scrollbar_controller.h index e1b13dc2e03..80a49f3f424 100644 --- a/chromium/cc/input/scrollbar_controller.h +++ b/chromium/cc/input/scrollbar_controller.h @@ -32,13 +32,11 @@ class CC_EXPORT ScrollbarController { // needed to determine whether we should set up the autoscrolling in the // forwards or the backwards direction. void StartAutoScrollAnimation(float velocity, - ElementId element_id, + const ScrollbarLayerImplBase* scrollbar, ScrollbarPart pressed_scrollbar_part); bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; } - ScrollbarOrientation orientation() { - return currently_captured_scrollbar_->orientation(); - } - + void DidUnregisterScrollbar(ElementId element_id); + ScrollbarLayerImplBase* ScrollbarLayer(); void WillBeginImplFrame(); private: @@ -74,44 +72,62 @@ class CC_EXPORT ScrollbarController { float scroll_position_at_start_; }; + struct CC_EXPORT CapturedScrollbarMetadata { + // Needed to retrieve the ScrollbarSet for a particular ElementId. + ElementId scroll_element_id; + + // Needed to identify the correct scrollbar from the ScrollbarSet. + ScrollbarOrientation orientation; + }; + // Returns the DSF based on whether use-zoom-for-dsf is enabled. float ScreenSpaceScaleFactor() const; // Helper to convert scroll offset to autoscroll velocity. - float InitialDeltaToAutoscrollVelocity(gfx::ScrollOffset scroll_offset) const; + float InitialDeltaToAutoscrollVelocity( + const ScrollbarLayerImplBase* scrollbar, + gfx::ScrollOffset scroll_offset) const; // Returns the hit tested ScrollbarPart based on the position_in_widget. ScrollbarPart GetScrollbarPartFromPointerDown( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF position_in_widget); // Returns scroll offsets based on which ScrollbarPart was hit tested. gfx::ScrollOffset GetScrollOffsetForScrollbarPart( + const ScrollbarLayerImplBase* scrollbar, const ScrollbarPart scrollbar_part, - const ScrollbarOrientation orientation, const bool shift_modifier); // Returns the rect for the ScrollbarPart. - gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part); + gfx::Rect GetRectForScrollbarPart(const ScrollbarLayerImplBase* scrollbar, + const ScrollbarPart scrollbar_part); LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget); - int GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part, + int GetScrollDeltaForScrollbarPart(const ScrollbarLayerImplBase* scrollbar, + const ScrollbarPart scrollbar_part, const bool shift_modifier); // Makes position_in_widget relative to the scrollbar. - gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget, - bool* clipped); + gfx::PointF GetScrollbarRelativePosition( + const ScrollbarLayerImplBase* scrollbar, + const gfx::PointF position_in_widget, + bool* clipped); // Decides if the scroller should snap to the offset that it was originally at // (i.e the offset before the thumb drag). - bool SnapToDragOrigin(const gfx::PointF pointer_position_in_widget); + bool SnapToDragOrigin(const ScrollbarLayerImplBase* scrollbar, + const gfx::PointF pointer_position_in_widget); // Decides whether a track autoscroll should be aborted (or restarted) due to // the thumb reaching the pointer or the pointer leaving (or re-entering) the // bounds. void RecomputeAutoscrollStateIfNeeded(); + void ResetState(); - // Shift + click is expected to do a non-animated jump to a certain offset. - float GetScrollDeltaForShiftClick(); + // Shift (or "Option" in case of Mac) + click is expected to do a non-animated + // jump to a certain offset. + float GetScrollDeltaForAbsoluteJump(const ScrollbarLayerImplBase* scrollbar); // Determines if the delta needs to be animated. ui::input_types::ScrollGranularity Granularity( @@ -121,25 +137,29 @@ class CC_EXPORT ScrollbarController { // Calculates the scroll_offset based on position_in_widget and // drag_anchor_relative_to_thumb_. gfx::ScrollOffset GetScrollOffsetForDragPosition( + const ScrollbarLayerImplBase* scrollbar, const gfx::PointF pointer_position_in_widget); // Returns a Vector2dF for position_in_widget relative to the scrollbar thumb. - gfx::Vector2dF GetThumbRelativePoint(const gfx::PointF position_in_widget); + gfx::Vector2dF GetThumbRelativePoint(const ScrollbarLayerImplBase* scrollbar, + const gfx::PointF position_in_widget); // Returns the ratio of the scroller length to the scrollbar length. This is // needed to scale the scroll delta for thumb drag. - float GetScrollerToScrollbarRatio(); + float GetScrollerToScrollbarRatio(const ScrollbarLayerImplBase* scrollbar); LayerTreeHostImpl* layer_tree_host_impl_; // Used to safeguard against firing GSE without firing GSB and GSU. For // example, if mouse is pressed outside the scrollbar but released after // moving inside the scrollbar, a GSE will get queued up without this flag. bool scrollbar_scroll_is_active_; - const ScrollbarLayerImplBase* currently_captured_scrollbar_; // This is relative to the RenderWidget's origin. gfx::PointF last_known_pointer_position_; + // Set only while interacting with the scrollbar (eg: drag, click etc). + base::Optional<CapturedScrollbarMetadata> captured_scrollbar_metadata_; + // Holds information pertaining to autoscrolling. This member is empty if and // only if an autoscroll is *not* in progress. base::Optional<AutoScrollState> autoscroll_state_; @@ -157,7 +177,7 @@ class CC_EXPORT ScrollbarController { // pointermoves are not VSync aligned). bool drag_processed_for_current_frame_; - std::unique_ptr<base::CancelableClosure> cancelable_autoscroll_task_; + std::unique_ptr<base::CancelableOnceClosure> cancelable_autoscroll_task_; }; } // namespace cc diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc index d01e1ac2bcd..8988bf72e65 100644 --- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc +++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc @@ -173,8 +173,9 @@ void SingleScrollbarAnimationControllerThinning::DidMouseMove( if (!scrollbar) return; - float distance_to_scrollbar_track = DistanceToScrollbarPart( - device_viewport_point, *scrollbar, ScrollbarPart::TRACK); + float distance_to_scrollbar_track = + DistanceToScrollbarPart(device_viewport_point, *scrollbar, + ScrollbarPart::TRACK_BUTTONS_TICKMARKS); float distance_to_scrollbar_thumb = DistanceToScrollbarPart( device_viewport_point, *scrollbar, ScrollbarPart::THUMB); diff --git a/chromium/cc/input/snap_fling_controller.cc b/chromium/cc/input/snap_fling_controller.cc index 4c8e485bcff..eba05d722a6 100644 --- a/chromium/cc/input/snap_fling_controller.cc +++ b/chromium/cc/input/snap_fling_controller.cc @@ -50,8 +50,8 @@ bool SnapFlingController::HandleGestureScrollUpdate( SnapFlingCurve::EstimateDisplacement(info.delta); gfx::Vector2dF target_offset, start_offset; - if (!client_->GetSnapFlingInfo(ending_displacement, &start_offset, - &target_offset)) { + if (!client_->GetSnapFlingInfoAndSetSnapTarget( + ending_displacement, &start_offset, &target_offset)) { state_ = State::kIgnored; return false; } diff --git a/chromium/cc/input/snap_fling_controller.h b/chromium/cc/input/snap_fling_controller.h index c5ad511d91c..184d9045d8a 100644 --- a/chromium/cc/input/snap_fling_controller.h +++ b/chromium/cc/input/snap_fling_controller.h @@ -23,9 +23,10 @@ class SnapFlingCurve; // are in the same coordinate space. class SnapFlingClient { public: - virtual bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement, - gfx::Vector2dF* out_initial_position, - gfx::Vector2dF* out_target_position) const = 0; + virtual bool GetSnapFlingInfoAndSetSnapTarget( + const gfx::Vector2dF& natural_displacement, + gfx::Vector2dF* out_initial_position, + gfx::Vector2dF* out_target_position) const = 0; virtual gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) = 0; virtual void ScrollEndForSnapFling() = 0; virtual void RequestAnimationForSnapFling() = 0; diff --git a/chromium/cc/input/snap_fling_controller_unittest.cc b/chromium/cc/input/snap_fling_controller_unittest.cc index ebbf5b18cfd..aca8075efb5 100644 --- a/chromium/cc/input/snap_fling_controller_unittest.cc +++ b/chromium/cc/input/snap_fling_controller_unittest.cc @@ -14,7 +14,7 @@ namespace { class MockSnapFlingClient : public SnapFlingClient { public: - MOCK_CONST_METHOD3(GetSnapFlingInfo, + MOCK_CONST_METHOD3(GetSnapFlingInfoAndSetSnapTarget, bool(const gfx::Vector2dF& natural_displacement, gfx::Vector2dF* initial_offset, gfx::Vector2dF* target_offset)); @@ -75,8 +75,8 @@ TEST_F(SnapFlingControllerTest, CreatesAndAnimatesCurveOnFirstInertialGSU) { gsu.delta = gfx::Vector2dF(0, -10); gsu.is_in_inertial_phase = true; - EXPECT_CALL(mock_client_, - GetSnapFlingInfo(testing::_, testing::_, testing::_)) + EXPECT_CALL(mock_client_, GetSnapFlingInfoAndSetSnapTarget( + testing::_, testing::_, testing::_)) .WillOnce( testing::DoAll(testing::SetArgPointee<1>(gfx::Vector2dF(0, 0)), testing::SetArgPointee<2>(gfx::Vector2dF(0, 100)), @@ -92,8 +92,8 @@ TEST_F(SnapFlingControllerTest, DoesNotHandleNonInertialGSU) { gsu.delta = gfx::Vector2dF(0, -10); gsu.is_in_inertial_phase = false; - EXPECT_CALL(mock_client_, - GetSnapFlingInfo(testing::_, testing::_, testing::_)) + EXPECT_CALL(mock_client_, GetSnapFlingInfoAndSetSnapTarget( + testing::_, testing::_, testing::_)) .Times(0); EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(0); EXPECT_CALL(mock_client_, ScrollByForSnapFling(testing::_)).Times(0); diff --git a/chromium/cc/input/snap_selection_strategy.cc b/chromium/cc/input/snap_selection_strategy.cc index 7ea5fe4d431..e2df143a220 100644 --- a/chromium/cc/input/snap_selection_strategy.cc +++ b/chromium/cc/input/snap_selection_strategy.cc @@ -10,9 +10,10 @@ std::unique_ptr<SnapSelectionStrategy> SnapSelectionStrategy::CreateForEndPosition( const gfx::ScrollOffset& current_position, bool scrolled_x, - bool scrolled_y) { + bool scrolled_y, + SnapTargetsPrioritization prioritization) { return std::make_unique<EndPositionStrategy>(current_position, scrolled_x, - scrolled_y); + scrolled_y, prioritization); } std::unique_ptr<SnapSelectionStrategy> @@ -30,6 +31,14 @@ SnapSelectionStrategy::CreateForEndAndDirection( displacement); } +std::unique_ptr<SnapSelectionStrategy> +SnapSelectionStrategy::CreateForTargetElement( + gfx::ScrollOffset current_position) { + return std::make_unique<EndPositionStrategy>( + current_position, true /* scrolled_x */, true /* scrolled_y */, + SnapTargetsPrioritization::kRequire); +} + bool SnapSelectionStrategy::HasIntendedDirection() const { return true; } @@ -45,6 +54,10 @@ bool SnapSelectionStrategy::IsValidSnapArea(SearchAxis axis, : area.scroll_snap_align.alignment_block != SnapAlignment::kNone; } +bool SnapSelectionStrategy::ShouldPrioritizeSnapTargets() const { + return false; +} + bool EndPositionStrategy::ShouldSnapOnX() const { return scrolled_x_; } @@ -72,6 +85,10 @@ bool EndPositionStrategy::HasIntendedDirection() const { return false; } +bool EndPositionStrategy::ShouldPrioritizeSnapTargets() const { + return snap_targets_prioritization_ == SnapTargetsPrioritization::kRequire; +} + const base::Optional<SnapSearchResult>& EndPositionStrategy::PickBestResult( const base::Optional<SnapSearchResult>& closest, const base::Optional<SnapSearchResult>& covering) const { diff --git a/chromium/cc/input/snap_selection_strategy.h b/chromium/cc/input/snap_selection_strategy.h index 4b2fc2e38e4..f3dca1fc47f 100644 --- a/chromium/cc/input/snap_selection_strategy.h +++ b/chromium/cc/input/snap_selection_strategy.h @@ -12,6 +12,7 @@ namespace cc { enum class SnapStopAlwaysFilter { kIgnore, kRequire }; +enum class SnapTargetsPrioritization { kIgnore, kRequire }; // This class represents an abstract strategy that decide which snap selection // should be considered valid. There are concrete implementations for three core @@ -24,7 +25,9 @@ class CC_EXPORT SnapSelectionStrategy { static std::unique_ptr<SnapSelectionStrategy> CreateForEndPosition( const gfx::ScrollOffset& current_position, bool scrolled_x, - bool scrolled_y); + bool scrolled_y, + SnapTargetsPrioritization prioritization = + SnapTargetsPrioritization::kIgnore); static std::unique_ptr<SnapSelectionStrategy> CreateForDirection( gfx::ScrollOffset current_position, gfx::ScrollOffset step, @@ -33,10 +36,20 @@ class CC_EXPORT SnapSelectionStrategy { gfx::ScrollOffset current_position, gfx::ScrollOffset displacement); + // Creates a selection strategy that attempts to snap to previously snapped + // targets if possible, but defaults to finding the closest snap point if + // the target no longer exists. + static std::unique_ptr<SnapSelectionStrategy> CreateForTargetElement( + gfx::ScrollOffset current_position); + // Returns whether it's snappable on x or y depending on the scroll performed. virtual bool ShouldSnapOnX() const = 0; virtual bool ShouldSnapOnY() const = 0; + // Returns whether snapping should attempt to snap to the previously snapped + // area if possible. + virtual bool ShouldPrioritizeSnapTargets() const; + // Returns the end position of the scroll if no snap interferes. virtual gfx::ScrollOffset intended_position() const = 0; // Returns the scroll position from which the snap position should minimize @@ -88,10 +101,12 @@ class EndPositionStrategy : public SnapSelectionStrategy { public: EndPositionStrategy(const gfx::ScrollOffset& current_position, bool scrolled_x, - bool scrolled_y) + bool scrolled_y, + SnapTargetsPrioritization snap_targets_prioritization) : SnapSelectionStrategy(current_position), scrolled_x_(scrolled_x), - scrolled_y_(scrolled_y) {} + scrolled_y_(scrolled_y), + snap_targets_prioritization_(snap_targets_prioritization) {} ~EndPositionStrategy() override = default; bool ShouldSnapOnX() const override; @@ -102,6 +117,7 @@ class EndPositionStrategy : public SnapSelectionStrategy { bool IsValidSnapPosition(SearchAxis axis, float position) const override; bool HasIntendedDirection() const override; + bool ShouldPrioritizeSnapTargets() const override; const base::Optional<SnapSearchResult>& PickBestResult( const base::Optional<SnapSearchResult>& closest, @@ -111,6 +127,7 @@ class EndPositionStrategy : public SnapSelectionStrategy { // Whether the x axis and y axis have been scrolled in this scroll gesture. const bool scrolled_x_; const bool scrolled_y_; + SnapTargetsPrioritization snap_targets_prioritization_; }; // Examples for intended direction scrolls include diff --git a/chromium/cc/ipc/BUILD.gn b/chromium/cc/ipc/BUILD.gn new file mode 100644 index 00000000000..8bcef572b7b --- /dev/null +++ b/chromium/cc/ipc/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright 2019 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. + +import("//cc/cc.gni") + +cc_component("ipc") { + output_name = "cc_ipc" + + sources = [ + "cc_param_traits.cc", + "cc_param_traits_macros.h", + ] + + defines = [ "IS_CC_IPC_IMPL" ] + + public_deps = [ + "//base", + "//cc", + "//ipc", + ] +} diff --git a/chromium/cc/ipc/OWNERS b/chromium/cc/ipc/OWNERS new file mode 100644 index 00000000000..146c3c3cd62 --- /dev/null +++ b/chromium/cc/ipc/OWNERS @@ -0,0 +1,2 @@ +per-file *_param_traits*.*=set noparent +per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS diff --git a/chromium/cc/ipc/README.md b/chromium/cc/ipc/README.md new file mode 100644 index 00000000000..0e3e14f1012 --- /dev/null +++ b/chromium/cc/ipc/README.md @@ -0,0 +1,12 @@ +# cc/ipc + +[TOC] + +## Overview + +cc/ipc provides Chrome IPC legacy param trait validators. cc based +structures that are defined in C++ and have mojo based NativeEnum +definitions require validators. See cc/mojom for the mojo definitions. +Eventually all cc based structures should be defined solely in +mojo and then this directory can be removed. However, this will +not happen until all structures are sent via mojo only. diff --git a/chromium/cc/ipc/cc_param_traits.cc b/chromium/cc/ipc/cc_param_traits.cc new file mode 100644 index 00000000000..14560bf0620 --- /dev/null +++ b/chromium/cc/ipc/cc_param_traits.cc @@ -0,0 +1,25 @@ +// Copyright 2019 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. + +#include "cc/ipc/cc_param_traits_macros.h" +#include "ipc/param_traits_write_macros.h" + +namespace IPC { +#undef CC_IPC_CC_PARAM_TRAITS_MACROS_H_ +#include "cc/ipc/cc_param_traits_macros.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#undef CC_IPC_CC_PARAM_TRAITS_MACROS_H_ +#include "cc/ipc/cc_param_traits_macros.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#undef CC_IPC_CC_PARAM_TRAITS_MACROS_H_ +#include "cc/ipc/cc_param_traits_macros.h" +} // namespace IPC diff --git a/chromium/cc/ipc/cc_param_traits_macros.h b/chromium/cc/ipc/cc_param_traits_macros.h new file mode 100644 index 00000000000..2e76c288790 --- /dev/null +++ b/chromium/cc/ipc/cc_param_traits_macros.h @@ -0,0 +1,17 @@ +// Copyright 2019 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_IPC_CC_PARAM_TRAITS_MACROS_H_ +#define CC_IPC_CC_PARAM_TRAITS_MACROS_H_ + +#include "base/component_export.h" +#include "cc/input/touch_action.h" +#include "ipc/ipc_message_macros.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT COMPONENT_EXPORT(CC_IPC) + +IPC_ENUM_TRAITS_MAX_VALUE(cc::TouchAction, cc::TouchAction::kTouchActionMax) + +#endif // CC_IPC_CC_PARAM_TRAITS_MACROS_H_ diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc index 4d82dfede6c..e2863170ba2 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl.cc @@ -37,6 +37,7 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/resources/bitmap_allocation.h" #include "components/viz/common/resources/platform_color.h" +#include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/raster_interface.h" @@ -370,7 +371,9 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( } else { auto* gl = context_provider->ContextGL(); GLuint mailbox_texture_id = - gl->CreateAndConsumeTextureCHROMIUM(backing->mailbox.name); + gl->CreateAndTexStorage2DSharedImageCHROMIUM(backing->mailbox.name); + gl->BeginSharedImageAccessDirectCHROMIUM( + mailbox_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); { ScopedGpuRaster scoped_gpu_raster(context_provider); @@ -389,6 +392,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( DrawHudContents(&canvas); } + gl->EndSharedImageAccessDirectCHROMIUM(mailbox_texture_id); gl->DeleteTextures(1, &mailbox_texture_id); backing->mailbox_sync_token = viz::ClientResourceProvider::GenerateSyncTokenHelper(gl); @@ -414,8 +418,12 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( TRACE_EVENT0("cc", "UploadHudTexture"); SkPixmap pixmap; staging_surface_->peekPixels(&pixmap); + GLuint mailbox_texture_id = - gl->CreateAndConsumeTextureCHROMIUM(backing->mailbox.name); + gl->CreateAndTexStorage2DSharedImageCHROMIUM(backing->mailbox.name); + gl->BeginSharedImageAccessDirectCHROMIUM( + mailbox_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); + gl->BindTexture(backing->texture_target, mailbox_texture_id); DCHECK(GLSupportsFormat(pool_resource.format())); // We should use gl compatible format for skia SW rasterization. @@ -424,6 +432,8 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( gl->TexSubImage2D( backing->texture_target, 0, 0, 0, pool_resource.size().width(), pool_resource.size().height(), format, type, pixmap.addr()); + + gl->EndSharedImageAccessDirectCHROMIUM(mailbox_texture_id); gl->DeleteTextures(1, &mailbox_texture_id); backing->mailbox_sync_token = viz::ClientResourceProvider::GenerateSyncTokenHelper(gl); @@ -884,10 +894,6 @@ SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(PaintCanvas* canvas, status = "off (device)"; color = SK_ColorRED; break; - case GpuRasterizationStatus::MSAA_CONTENT: - status = "MSAA (content)"; - color = SK_ColorCYAN; - break; } if (status.empty()) @@ -1031,6 +1037,14 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( stroke_width = DebugColors::NonFastScrollableRectBorderWidth(); label_text = "repaints on scroll"; break; + case MAIN_THREAD_SCROLLING_REASON_RECT_TYPE: + stroke_color = DebugColors::MainThreadScrollingReasonRectBorderColor(); + fill_color = DebugColors::MainThreadScrollingReasonRectFillColor(); + stroke_width = DebugColors::MainThreadScrollingReasonRectBorderWidth(); + label_text = "main thread scrolling: "; + label_text.append(base::ToLowerASCII(MainThreadScrollingReason::AsText( + debug_rects[i].main_thread_scrolling_reasons))); + break; case ANIMATION_BOUNDS_RECT_TYPE: stroke_color = DebugColors::LayerAnimationBoundsBorderColor(); fill_color = DebugColors::LayerAnimationBoundsFillColor(); diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc index 063e39f34f7..6abcee0e961 100644 --- a/chromium/cc/layers/layer.cc +++ b/chromium/cc/layers/layer.cc @@ -18,10 +18,8 @@ #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "cc/base/simple_enclosed_region.h" -#include "cc/layers/layer_client.h" #include "cc/layers/layer_impl.h" #include "cc/layers/picture_layer.h" -#include "cc/tiles/frame_viewer_instrumentation.h" #include "cc/trees/clip_node.h" #include "cc/trees/draw_property_utils.h" #include "cc/trees/layer_tree_host.h" @@ -69,17 +67,14 @@ struct SameSizeAsLayer : public base::RefCounted<SameSizeAsLayer> { Region non_fast_scrollable_region; TouchActionRegion touch_action_region; ElementId element_id; - base::WeakPtr<LayerClient> client; - std::unique_ptr<base::trace_event::TracedValue> debug_info; base::RepeatingCallback<void()> did_scroll_callback; std::vector<std::unique_ptr<viz::CopyOutputRequest>> copy_requests; } inputs; - int int_fields[7]; + int int_fields[6]; gfx::Vector2dF offset; unsigned bitfields; SkColor safe_opaque_background_color; - int owner_node_id; - uint64_t compositing_reasons; + void* debug_info; }; static_assert(sizeof(Layer) == sizeof(SameSizeAsLayer), @@ -87,6 +82,10 @@ static_assert(sizeof(Layer) == sizeof(SameSizeAsLayer), base::AtomicSequenceNumber g_next_layer_id; +LayerDebugInfo::LayerDebugInfo() = default; +LayerDebugInfo::LayerDebugInfo(const LayerDebugInfo&) = default; +LayerDebugInfo::~LayerDebugInfo() = default; + Layer::Inputs::Inputs(int layer_id) : mask_layer(nullptr), layer_id(layer_id), @@ -122,7 +121,6 @@ Layer::Layer() layer_tree_host_(nullptr), // Layer IDs start from 1. inputs_(g_next_layer_id.GetNext() + 1), - paint_count_(0), num_descendants_that_draw_content_(0), transform_tree_index_(TransformTree::kInvalidNodeId), effect_tree_index_(EffectTree::kInvalidNodeId), @@ -140,9 +138,7 @@ Layer::Layer() has_transform_node_(false), has_clip_node_(false), subtree_has_copy_request_(false), - safe_opaque_background_color_(0), - owner_node_id_(0), - compositing_reasons_(0) {} + safe_opaque_background_color_(0) {} Layer::~Layer() { // Our parent should be holding a reference to us so there should be no @@ -977,6 +973,13 @@ void Layer::UpdateScrollOffset(const gfx::ScrollOffset& scroll_offset) { property_trees.transform_tree.set_needs_update(true); } +void Layer::SetDidScrollCallback( + base::RepeatingCallback<void(const gfx::ScrollOffset&, const ElementId&)> + callback) { + DCHECK(!layer_tree_host_ || !layer_tree_host_->IsUsingLayerLists()); + inputs_.did_scroll_callback = std::move(callback); +} + void Layer::SetScrollable(const gfx::Size& bounds) { DCHECK(IsPropertyChangeAllowed()); if (inputs_.scrollable && inputs_.scroll_container_bounds == bounds) @@ -1213,18 +1216,33 @@ void Layer::SetPropertyTreesNeedRebuild() { layer_tree_host_->property_trees()->needs_rebuild = true; } -#if DCHECK_IS_ON() +LayerDebugInfo& Layer::EnsureDebugInfo() { + if (!debug_info_) { + debug_info_ = std::make_unique<LayerDebugInfo>(); + // We just enabled debug info collection. Force PushPropertiesTo() to ensure + // the first layer tree snapshot contains the debug info. Otherwise we will + // push debug_info when we have other changes to push. + SetNeedsPushProperties(); + } + return *debug_info_; +} + +void Layer::ClearDebugInfo() { + if (!debug_info_) + return; + + debug_info_.reset(); + SetNeedsPushProperties(); +} + std::string Layer::DebugName() const { - return inputs_.client ? inputs_.client->LayerDebugName(this) : ""; + return debug_info_ ? debug_info_->name : ""; } -#endif std::string Layer::ToString() const { return base::StringPrintf( "layer_id: %d\n" -#if DCHECK_IS_ON() " name: %s\n" -#endif " Bounds: %s\n" " ElementId: %s\n" " OffsetToTransformParent: %s\n" @@ -1235,9 +1253,7 @@ std::string Layer::ToString() const { " scroll_tree_index: %d\n" " transform_tree_index: %d\n", id(), -#if DCHECK_IS_ON() DebugName().c_str(), -#endif bounds().ToString().c_str(), element_id().ToString().c_str(), offset_to_transform_parent().ToString().c_str(), position().ToString().c_str(), scrollable(), clip_tree_index(), @@ -1291,11 +1307,6 @@ void Layer::SetNeedsDisplayRect(const gfx::Rect& dirty_rect) { layer_tree_host_->SetNeedsUpdateLayers(); } -void Layer::SetLayerClient(base::WeakPtr<LayerClient> client) { - inputs_.client = std::move(client); - inputs_.debug_info = nullptr; -} - bool Layer::IsSnappedToPixelGridInTarget() { return false; } @@ -1318,7 +1329,6 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->SetBackgroundColor(inputs_.background_color); layer->SetSafeOpaqueBackgroundColor(safe_opaque_background_color_); layer->SetBounds(inputs_.bounds); - layer->SetDebugInfo(std::move(inputs_.debug_info)); layer->SetTransformTreeIndex(transform_tree_index()); layer->SetEffectTreeIndex(effect_tree_index()); layer->SetClipTreeIndex(clip_tree_index()); @@ -1372,16 +1382,13 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { if (needs_show_scrollbars_) layer->set_needs_show_scrollbars(true); - // If the main thread commits multiple times before the impl thread actually - // draws, then damage tracking will become incorrect if we simply clobber the - // update_rect here. The LayerImpl's update_rect needs to accumulate (i.e. - // union) any update changes that have occurred on the main thread. - inputs_.update_rect.Union(layer->update_rect()); - layer->SetUpdateRect(inputs_.update_rect); - + layer->UnionUpdateRect(inputs_.update_rect); layer->SetHasWillChangeTransformHint(has_will_change_transform_hint()); layer->SetNeedsPushProperties(); + // debug_info_->invalidations, if exist, will be cleared in the function. + layer->UpdateDebugInfo(debug_info_.get()); + // Reset any state that should be cleared for the next update. needs_show_scrollbars_ = false; subtree_property_changed_ = false; @@ -1442,20 +1449,6 @@ bool Layer::Update() { return false; } -bool Layer::HasSlowPaths() const { - return false; -} - -bool Layer::HasNonAAPaint() const { - return false; -} - -void Layer::UpdateDebugInfo() { - DCHECK(frame_viewer_instrumentation::IsTracingLayerTreeSnapshots()); - if (inputs_.client) - inputs_.debug_info = inputs_.client->TakeDebugInfo(this); -} - void Layer::SetSubtreePropertyChanged() { if (subtree_property_changed_) return; @@ -1470,11 +1463,6 @@ void Layer::SetMayContainVideo(bool yes) { SetNeedsPushProperties(); } -void Layer::SetScrollbarsHiddenFromImplSide(bool hidden) { - if (inputs_.client) - inputs_.client->DidChangeScrollbarsHiddenIfOverlay(hidden); -} - // On<Property>Animated is called due to an ongoing accelerated animation. // Since this animation is also being run on the compositor thread, there // is no need to request a commit to push this value over, so the value is diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h index 054f3884a38..223ace706af 100644 --- a/chromium/cc/layers/layer.h +++ b/chromium/cc/layers/layer.h @@ -39,25 +39,37 @@ #include "ui/gfx/rrect_f.h" #include "ui/gfx/transform.h" -namespace base { -namespace trace_event { -class TracedValue; -} -} - namespace viz { class CopyOutputRequest; } namespace cc { -class LayerClient; class LayerImpl; class LayerTreeHost; class LayerTreeHostCommon; class LayerTreeImpl; class PictureLayer; +// For tracing and debugging. The info will be attached to this layer's tracing +// output. +struct LayerDebugInfo { + LayerDebugInfo(); + LayerDebugInfo(const LayerDebugInfo&); + ~LayerDebugInfo(); + + std::string name; + NodeId owner_node_id = kInvalidNodeId; + int paint_count = 0; + std::vector<const char*> compositing_reasons; + struct Invalidation { + gfx::Rect rect; + const char* reason; + std::string client; + }; + std::vector<Invalidation> invalidations; +}; + // Base class for composited layers. Special layer types are derived from // this class. Each layer is an independent unit in the compositor, be that // for transforming or for content. If a layer has content it can be @@ -79,12 +91,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { Layer(const Layer&) = delete; Layer& operator=(const Layer&) = delete; - // Sets an optional client on this layer, that will be called when relevant - // events happen. The client is a WeakPtr so it can be destroyed without - // unsetting itself as the client. - void SetLayerClient(base::WeakPtr<LayerClient> client); - LayerClient* GetLayerClientForTesting() const { return inputs_.client.get(); } - // A unique and stable id for the Layer. Ids are always positive. int id() const { return inputs_.layer_id; } @@ -219,6 +225,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // SetNeedsDisplay() that have not been committed to the compositor thread. const gfx::Rect& update_rect() const { return inputs_.update_rect; } + void ResetUpdateRectForTesting() { inputs_.update_rect = gfx::Rect(); } + // Set or get the rounded corner radii which is applied to the layer and its // subtree (as if they are together as a single composited entity) when // blitting into their target. Setting this makes the layer masked to bounds. @@ -391,12 +399,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // asked to prepare content with Update(), if the scroll offset for the layer // was changed by the InputHandlerClient, on the compositor thread (or on the // main thread in single-thread mode). It may be set to a null callback, in - // which case nothing is called. - void set_did_scroll_callback( - base::RepeatingCallback<void(const gfx::ScrollOffset&, const ElementId&)> - callback) { - inputs_.did_scroll_callback = std::move(callback); - } + // which case nothing is called. This is for layer tree mode only. Should use + // ScrollTree::SetScrollCallbacks() in layer list mode. + void SetDidScrollCallback(base::RepeatingCallback< + void(const gfx::ScrollOffset&, const ElementId&)>); // Set or get if the layer and its subtree should be cached as a texture in // the display compositor. This is used as an optimization when it is known @@ -545,9 +551,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // display. virtual sk_sp<SkPicture> GetPicture() const; - // For tracing. Calls out to the LayerClient to get tracing data that will - // be attached to this layer's tracing outputs under the 'debug_info' key. - void UpdateDebugInfo(); + const LayerDebugInfo* debug_info() const { return debug_info_.get(); } + LayerDebugInfo& EnsureDebugInfo(); + void ClearDebugInfo(); // For telemetry testing. Runs a given test behaviour implemented in // |benchmark| for this layer. The base class does nothing as benchmarks @@ -574,23 +580,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // if there is anything new to commit. If all layers return false, the commit // may be aborted. virtual bool Update(); - // Internal method to be overriden by Layer subclasses that override Update() - // and require rasterization. After Update() is called, this is immediately - // called, and should return whether the layer will require rasterization of - // paths that will be difficult/slow to raster. Only layers that do - // rasterization via TileManager need to override this, other layers that have - // content generated in other ways may leave it as the default. - virtual bool HasSlowPaths() const; - // Internal method to be overriden by Layer subclasses that override Update() - // and require rasterization. After Update() is called, this is immediately - // called, and should return whether the layer will require rasterization of a - // drawing operation that must not be anti-aliased. In this case using MSAA to - // antialias the entire layer's content would produce an incorrect result. - // This result is considered sticky, once a layer returns true, so false - // positives should be avoided. Only layers that do rasterization via - // TileManager need to override this, other layers that have content generated - // in other ways may leave it as the default. - virtual bool HasNonAAPaint() const; // Internal to property tree construction. This allows a layer to request that // its transform should be snapped such that the layer aligns with the pixel @@ -618,11 +607,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // was called before it. void SetNeedsPushProperties(); - // Internal method to call the LayerClient, if there is one, to inform it when - // overlay scrollbars have been completely hidden (due to lack of scrolling by - // the user). - void SetScrollbarsHiddenFromImplSide(bool hidden); - // Internal to property tree construction. A generation number for the // property trees, to verify the layer's indices are pointers into the trees // currently held by the LayerTreeHost. The number is updated when property @@ -689,10 +673,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { return should_check_backface_visibility_; } -#if DCHECK_IS_ON() // For debugging, containing information about the associated DOM, etc. std::string DebugName() const; -#endif std::string ToString() const; @@ -703,25 +685,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // in PropertyTreeManager when handling scroll offsets. void SetNeedsCommit(); - // The following data are for profiling and debugging. They will be displayed - // e.g. in the Layers panel of DevTools. - - // The compositing reasons of the layer. The values are defined in - // third_party/blink/renderer/platform/graphics/compositing_reasons.h. - void set_compositing_reasons(uint64_t compositing_reasons) { - compositing_reasons_ = compositing_reasons; - } - uint64_t compositing_reasons() const { return compositing_reasons_; } - - // The id of the DOM node that owns this layer. - void set_owner_node_id(int node_id) { owner_node_id_ = node_id; } - int owner_node_id() const { return owner_node_id_; } - - // How many times this layer has been repainted. - int paint_count() const { return paint_count_; } - - // End of data for profiling and debugging. - protected: friend class LayerImpl; friend class TreeSynchronizer; @@ -760,7 +723,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // be changed while the frame is being generated for commit. bool IsPropertyChangeAllowed() const; - void IncreasePaintCount() { ++paint_count_; } + void IncreasePaintCount() { + if (debug_info_) + ++debug_info_->paint_count; + } base::AutoReset<bool> IgnoreSetNeedsCommit() { return base::AutoReset<bool>(&ignore_set_needs_commit_, true); @@ -885,10 +851,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { ElementId element_id; - // The following elements can not and are not serialized. - base::WeakPtr<LayerClient> client; - std::unique_ptr<base::trace_event::TracedValue> debug_info; - + // These for for layer tree mode (ui compositor) only. base::RepeatingCallback<void(const gfx::ScrollOffset&, const ElementId&)> did_scroll_callback; std::vector<std::unique_ptr<viz::CopyOutputRequest>> copy_requests; @@ -903,7 +866,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { Inputs inputs_; - int paint_count_; int num_descendants_that_draw_content_; int transform_tree_index_; int effect_tree_index_; @@ -931,8 +893,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { bool subtree_has_copy_request_ : 1; SkColor safe_opaque_background_color_; - int owner_node_id_; - uint64_t compositing_reasons_; + + std::unique_ptr<LayerDebugInfo> debug_info_; }; } // namespace cc diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h deleted file mode 100644 index 75aeff13ab6..00000000000 --- a/chromium/cc/layers/layer_client.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 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_LAYERS_LAYER_CLIENT_H_ -#define CC_LAYERS_LAYER_CLIENT_H_ - -#include <memory> -#include <string> - -#include "cc/cc_export.h" - -namespace base { -namespace trace_event { -class TracedValue; -} -} - -namespace cc { - -class Layer; - -class CC_EXPORT LayerClient { - public: - // Returns a pointer to a debug info object, if one has been computed. - // If not, returns nullptr. - // If the returned pointer is non-nullptr, the caller takes - // ownership of the pointer. - // - // A pointer to the layer is provided for the convenience of layer clients - // which service multiple layers. - virtual std::unique_ptr<base::trace_event::TracedValue> TakeDebugInfo( - const Layer* layer) = 0; - - virtual std::string LayerDebugName(const Layer* layer) const = 0; - - virtual void DidChangeScrollbarsHiddenIfOverlay(bool) = 0; - - protected: - virtual ~LayerClient() {} -}; - -} // namespace cc - -#endif // CC_LAYERS_LAYER_CLIENT_H_ diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc index 6653d2cfc24..0b8ae026330 100644 --- a/chromium/cc/layers/layer_impl.cc +++ b/chromium/cc/layers/layer_impl.cc @@ -69,7 +69,6 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, clip_tree_index_(ClipTree::kInvalidNodeId), scroll_tree_index_(ScrollTree::kInvalidNodeId), current_draw_mode_(DRAW_MODE_NONE), - debug_info_(nullptr), has_will_change_transform_hint_(false), needs_push_properties_(false), is_scrollbar_(false), @@ -102,10 +101,24 @@ ElementListType LayerImpl::GetElementTypeForAnimation() const { return IsActive() ? ElementListType::ACTIVE : ElementListType::PENDING; } -void LayerImpl::SetDebugInfo( - std::unique_ptr<base::trace_event::TracedValue> debug_info) { - owned_debug_info_ = std::move(debug_info); - debug_info_ = owned_debug_info_.get(); +void LayerImpl::UpdateDebugInfo(LayerDebugInfo* debug_info) { + // nullptr means we have stopped collecting debug info. + if (!debug_info) { + debug_info_.reset(); + return; + } + auto new_invalidations = std::move(debug_info->invalidations); + if (!debug_info_) { + debug_info_ = std::make_unique<LayerDebugInfo>(*debug_info); + debug_info_->invalidations = std::move(new_invalidations); + return; + } + // Accumulate invalidations until we draw the layer. + auto existing_invalidations = std::move(debug_info_->invalidations); + *debug_info_ = *debug_info; + debug_info_->invalidations.insert(debug_info_->invalidations.begin(), + existing_invalidations.begin(), + existing_invalidations.end()); } void LayerImpl::SetTransformTreeIndex(int index) { @@ -392,22 +405,13 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->set_is_scrollbar(is_scrollbar_); - // If the main thread commits multiple times before the impl thread actually - // draws, then damage tracking will become incorrect if we simply clobber the - // update_rect here. The LayerImpl's update_rect needs to accumulate (i.e. - // union) any update changes that have occurred on the main thread. - update_rect_.Union(layer->update_rect()); - layer->SetUpdateRect(update_rect_); + layer->UnionUpdateRect(update_rect_); - if (owned_debug_info_) - layer->SetDebugInfo(std::move(owned_debug_info_)); + layer->UpdateDebugInfo(debug_info_.get()); // Reset any state that should be cleared for the next update. needs_show_scrollbars_ = false; - layer_property_changed_not_from_property_trees_ = false; - layer_property_changed_from_property_trees_ = false; - needs_push_properties_ = false; - update_rect_ = gfx::Rect(); + ResetChangeTracking(); } bool LayerImpl::IsAffectedByPageScale() const { @@ -521,6 +525,8 @@ void LayerImpl::ResetChangeTracking() { needs_push_properties_ = false; update_rect_.SetRect(0, 0, 0, 0); + if (debug_info_) + debug_info_->invalidations.clear(); } bool LayerImpl::IsActive() const { @@ -641,8 +647,8 @@ void LayerImpl::SetMirrorCount(int mirror_count) { mirror_count_ = mirror_count; } -void LayerImpl::SetUpdateRect(const gfx::Rect& update_rect) { - update_rect_ = update_rect; +void LayerImpl::UnionUpdateRect(const gfx::Rect& update_rect) { + update_rect_.Union(update_rect); } gfx::Rect LayerImpl::GetDamageRect() const { @@ -713,6 +719,18 @@ void LayerImpl::GetAllPrioritizedTilesForTracing( } void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const { + // The output is consumed at least by + // 1. DevTools for showing layer tree information for frame snapshots in + // performance timeline (third_party/devtools_frontend/src/front_end/ + // timeline_model/TracingLayerTree.js), + // 2. trace_viewer + // (third_party/catapult/tracing/tracing/extras/chrome/cc/layer_impl.html) + // Note that trace_viewer uses "namingStyle" style instead of + // "naming_style". The difference is intentional and the names are + // converted automatically, but we need to keep this in mind when we + // search trace_viewer code for the usage of the names here. + // When making changes here, we need to make sure we won't break these + // consumers. viz::TracedValue::MakeDictIntoImplicitSnapshotWithCategory( TRACE_DISABLED_BY_DEFAULT("cc.debug"), state, "cc::LayerImpl", LayerTypeAsString(), this); @@ -769,8 +787,30 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const { state->SetBoolean("has_will_change_transform_hint", has_will_change_transform_hint()); - if (debug_info_) - state->SetValue("debug_info", debug_info_); + if (debug_info_) { + state->SetString("layer_name", debug_info_->name); + if (debug_info_->owner_node_id) + state->SetInteger("owner_node", debug_info_->owner_node_id); + + if (debug_info_->compositing_reasons.size()) { + state->BeginArray("compositing_reasons"); + for (const char* reason : debug_info_->compositing_reasons) + state->AppendString(reason); + state->EndArray(); + } + + if (debug_info_->invalidations.size()) { + state->BeginArray("annotated_invalidation_rects"); + for (auto& invalidation : debug_info_->invalidations) { + state->BeginDictionary(); + MathUtil::AddToTracedValue("geometry_rect", invalidation.rect, state); + state->SetString("reason", invalidation.reason); + state->SetString("client", invalidation.client); + state->EndDictionary(); + } + state->EndArray(); + } + } } std::string LayerImpl::ToString() const { diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h index b054f7f196e..a25b86bee09 100644 --- a/chromium/cc/layers/layer_impl.h +++ b/chromium/cc/layers/layer_impl.h @@ -40,9 +40,6 @@ #include "ui/gfx/transform.h" namespace base { -namespace trace_event { -class TracedValue; -} class DictionaryValue; } @@ -54,6 +51,7 @@ class RenderPass; namespace cc { class AppendQuadsData; +struct LayerDebugInfo; class LayerTreeImpl; class MicroBenchmarkImpl; class PrioritizedTile; @@ -300,8 +298,11 @@ class CC_EXPORT LayerImpl { return wheel_event_handler_region_; } + // The main thread may commit multiple times before the impl thread actually + // draws, so we need to accumulate (i.e. union) any update changes that have + // occurred on the main thread until we draw. // Note this rect is in layer space (not content space). - void SetUpdateRect(const gfx::Rect& update_rect); + void UnionUpdateRect(const gfx::Rect& update_rect); const gfx::Rect& update_rect() const { return update_rect_; } // Denotes an area that is damaged and needs redraw. This is in the layer's @@ -370,7 +371,7 @@ class CC_EXPORT LayerImpl { virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark); - void SetDebugInfo(std::unique_ptr<base::trace_event::TracedValue> debug_info); + void UpdateDebugInfo(LayerDebugInfo* debug_info); void set_contributes_to_drawn_render_surface(bool is_member) { contributes_to_drawn_render_surface_ = is_member; @@ -536,8 +537,7 @@ class CC_EXPORT LayerImpl { DrawProperties draw_properties_; PerformanceProperties<LayerImpl> performance_properties_; - std::unique_ptr<base::trace_event::TracedValue> owned_debug_info_; - base::trace_event::TracedValue* debug_info_; + std::unique_ptr<LayerDebugInfo> debug_info_; // Cache of all regions represented by any touch action from // |touch_action_region_|. diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc index 8de7247dd7b..3bc3298f95c 100644 --- a/chromium/cc/layers/layer_impl_unittest.cc +++ b/chromium/cc/layers/layer_impl_unittest.cc @@ -119,7 +119,7 @@ TEST_F(LayerImplTest, VerifyPendingLayerChangesAreTrackedProperly) { // These properties are internal, and should not be considered "change" when // they are used. EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE( - root->SetUpdateRect(arbitrary_rect)); + root->UnionUpdateRect(arbitrary_rect)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetBounds(arbitrary_size)); UpdatePendingTreeDrawProperties(); diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc index d46146ef57d..1b1c4476ba6 100644 --- a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc +++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc @@ -26,21 +26,20 @@ namespace cc { std::unique_ptr<LayerImpl> PaintedOverlayScrollbarLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) { return PaintedOverlayScrollbarLayerImpl::Create( - tree_impl, id(), scrollbar_->Orientation(), - scrollbar_->IsLeftSideVerticalScrollbar()); + tree_impl, id(), orientation(), is_left_side_vertical_scrollbar()); } scoped_refptr<PaintedOverlayScrollbarLayer> -PaintedOverlayScrollbarLayer::Create(std::unique_ptr<Scrollbar> scrollbar) { +PaintedOverlayScrollbarLayer::Create(scoped_refptr<Scrollbar> scrollbar) { return base::WrapRefCounted( new PaintedOverlayScrollbarLayer(std::move(scrollbar))); } PaintedOverlayScrollbarLayer::PaintedOverlayScrollbarLayer( - std::unique_ptr<Scrollbar> scrollbar) - : scrollbar_(std::move(scrollbar)), - thumb_thickness_(scrollbar_->ThumbThickness()), - thumb_length_(scrollbar_->ThumbLength()) { + scoped_refptr<Scrollbar> scrollbar) + : ScrollbarLayerBase(scrollbar->Orientation(), + scrollbar->IsLeftSideVerticalScrollbar()), + scrollbar_(std::move(scrollbar)) { DCHECK(scrollbar_->HasThumb()); DCHECK(scrollbar_->IsOverlay()); DCHECK(scrollbar_->UsesNinePatchThumbResource()); @@ -49,7 +48,7 @@ PaintedOverlayScrollbarLayer::PaintedOverlayScrollbarLayer( PaintedOverlayScrollbarLayer::~PaintedOverlayScrollbarLayer() = default; bool PaintedOverlayScrollbarLayer::OpacityCanAnimateOnImplThread() const { - return scrollbar_->IsOverlay(); + return true; } void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { @@ -58,12 +57,14 @@ void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { PaintedOverlayScrollbarLayerImpl* scrollbar_layer = static_cast<PaintedOverlayScrollbarLayerImpl*>(layer); - scrollbar_layer->SetThumbThickness(thumb_thickness_); - scrollbar_layer->SetThumbLength(thumb_length_); - if (scrollbar_->Orientation() == HORIZONTAL) { + if (orientation() == HORIZONTAL) { + scrollbar_layer->SetThumbThickness(thumb_size_.height()); + scrollbar_layer->SetThumbLength(thumb_size_.width()); scrollbar_layer->SetTrackStart(track_rect_.x()); scrollbar_layer->SetTrackLength(track_rect_.width()); } else { + scrollbar_layer->SetThumbThickness(thumb_size_.width()); + scrollbar_layer->SetThumbLength(thumb_size_.height()); scrollbar_layer->SetTrackStart(track_rect_.y()); scrollbar_layer->SetTrackLength(track_rect_.height()); } @@ -97,18 +98,22 @@ void PaintedOverlayScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) { ScrollbarLayerBase::SetLayerTreeHost(host); } -gfx::Rect PaintedOverlayScrollbarLayer::OriginThumbRectForPainting() const { - return gfx::Rect(gfx::Point(), scrollbar_->NinePatchThumbCanvasSize()); -} - bool PaintedOverlayScrollbarLayer::Update() { + // These properties should never change. + DCHECK_EQ(orientation(), scrollbar_->Orientation()); + DCHECK_EQ(is_left_side_vertical_scrollbar(), + scrollbar_->IsLeftSideVerticalScrollbar()); + DCHECK(scrollbar_->HasThumb()); + DCHECK(scrollbar_->IsOverlay()); + DCHECK(scrollbar_->UsesNinePatchThumbResource()); + bool updated = false; updated |= Layer::Update(); updated |= UpdateProperty(scrollbar_->TrackRect(), &track_rect_); - updated |= UpdateProperty(scrollbar_->Location(), &location_); - updated |= UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_); - updated |= UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_); + // Ignore ThumbRect's location because the PaintedOverlayScrollbarLayerImpl + // will compute it from scroll offset. + updated |= UpdateProperty(scrollbar_->ThumbRect().size(), &thumb_size_); updated |= PaintThumbIfNeeded(); updated |= PaintTickmarks(); @@ -116,21 +121,19 @@ bool PaintedOverlayScrollbarLayer::Update() { } bool PaintedOverlayScrollbarLayer::PaintThumbIfNeeded() { - if (!scrollbar_->NeedsPaintPart(THUMB) && thumb_resource_) + if (!scrollbar_->NeedsRepaintPart(THUMB) && thumb_resource_) return false; - gfx::Rect paint_rect = OriginThumbRectForPainting(); + gfx::Size paint_size = scrollbar_->NinePatchThumbCanvasSize(); + DCHECK(!paint_size.IsEmpty()); aperture_ = scrollbar_->NinePatchThumbAperture(); - DCHECK(!paint_rect.size().IsEmpty()); - DCHECK(paint_rect.origin().IsOrigin()); - SkBitmap skbitmap; - skbitmap.allocN32Pixels(paint_rect.width(), paint_rect.height()); + skbitmap.allocN32Pixels(paint_size.width(), paint_size.height()); SkiaPaintCanvas canvas(skbitmap); canvas.clear(SK_ColorTRANSPARENT); - scrollbar_->PaintPart(&canvas, THUMB); + scrollbar_->PaintPart(&canvas, THUMB, gfx::Rect(paint_size)); // Make sure that the pixels are no longer mutable to unavoid unnecessary // allocation and copying. skbitmap.setImmutable(); @@ -155,16 +158,16 @@ bool PaintedOverlayScrollbarLayer::PaintTickmarks() { } } - gfx::Rect paint_rect = gfx::Rect(gfx::Point(), track_rect_.size()); - - DCHECK(!paint_rect.size().IsEmpty()); + gfx::Size paint_size = track_rect_.size(); + DCHECK(!paint_size.IsEmpty()); SkBitmap skbitmap; - skbitmap.allocN32Pixels(paint_rect.width(), paint_rect.height()); + skbitmap.allocN32Pixels(paint_size.width(), paint_size.height()); SkiaPaintCanvas canvas(skbitmap); canvas.clear(SK_ColorTRANSPARENT); - scrollbar_->PaintPart(&canvas, TICKMARKS); + scrollbar_->PaintPart(&canvas, TRACK_BUTTONS_TICKMARKS, + gfx::Rect(paint_size)); // Make sure that the pixels are no longer mutable to unavoid unnecessary // allocation and copying. skbitmap.setImmutable(); diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.h b/chromium/cc/layers/painted_overlay_scrollbar_layer.h index 4838fb89452..9b0191d627a 100644 --- a/chromium/cc/layers/painted_overlay_scrollbar_layer.h +++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.h @@ -23,7 +23,7 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerBase { PaintedOverlayScrollbarLayer& operator=(const PaintedOverlayScrollbarLayer&) = delete; static scoped_refptr<PaintedOverlayScrollbarLayer> Create( - std::unique_ptr<Scrollbar> scrollbar); + scoped_refptr<Scrollbar> scrollbar); bool OpacityCanAnimateOnImplThread() const override; bool Update() override; @@ -31,12 +31,10 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerBase { void PushPropertiesTo(LayerImpl* layer) override; protected: - explicit PaintedOverlayScrollbarLayer(std::unique_ptr<Scrollbar> scrollbar); + explicit PaintedOverlayScrollbarLayer(scoped_refptr<Scrollbar> scrollbar); ~PaintedOverlayScrollbarLayer() override; private: - gfx::Rect OriginThumbRectForPainting() const; - template <typename T> bool UpdateProperty(T value, T* prop) { if (*prop == value) @@ -49,13 +47,10 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerBase { bool PaintThumbIfNeeded(); bool PaintTickmarks(); - std::unique_ptr<Scrollbar> scrollbar_; + scoped_refptr<Scrollbar> scrollbar_; - int thumb_thickness_; - int thumb_length_; - gfx::Point location_; + gfx::Size thumb_size_; gfx::Rect track_rect_; - gfx::Rect aperture_; std::unique_ptr<ScopedUIResource> thumb_resource_; diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc index e1a77c3adf2..7940c7bbd0d 100644 --- a/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_unittest.cc @@ -19,8 +19,8 @@ class MockScrollbar : public FakeScrollbar { public: MockScrollbar() : FakeScrollbar(true, true, true) {} - void PaintPart(PaintCanvas* canvas, ScrollbarPart part) override { - if (part == TICKMARKS) + void PaintPart(PaintCanvas*, ScrollbarPart part, const gfx::Rect&) override { + if (part == TRACK_BUTTONS_TICKMARKS) paint_tickmarks_called_ = true; } @@ -37,6 +37,8 @@ class MockScrollbar : public FakeScrollbar { } private: + ~MockScrollbar() override = default; + bool paint_tickmarks_called_ = false; }; @@ -48,12 +50,11 @@ TEST(PaintedOverlayScrollbarLayerTest, PaintTickmarks) { auto layer_tree_host = FakeLayerTreeHost::Create( &fake_client_, &task_graph_runner_, animation_host.get()); - MockScrollbar* scrollbar = new MockScrollbar(); + auto scrollbar = base::MakeRefCounted<MockScrollbar>(); scrollbar->set_has_tickmarks(false); scoped_refptr<PaintedOverlayScrollbarLayer> scrollbar_layer = - PaintedOverlayScrollbarLayer::Create( - std::unique_ptr<Scrollbar>(scrollbar)); + PaintedOverlayScrollbarLayer::Create(scrollbar); scrollbar_layer->SetIsDrawable(true); scrollbar_layer->SetBounds(gfx::Size(100, 100)); diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc index eca1517e8a1..2306ae30f56 100644 --- a/chromium/cc/layers/painted_scrollbar_layer.cc +++ b/chromium/cc/layers/painted_scrollbar_layer.cc @@ -15,31 +15,30 @@ namespace cc { std::unique_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) { - return PaintedScrollbarLayerImpl::Create( - tree_impl, id(), scrollbar_->Orientation(), - scrollbar_->IsLeftSideVerticalScrollbar(), scrollbar_->IsOverlay()); + return PaintedScrollbarLayerImpl::Create(tree_impl, id(), orientation(), + is_left_side_vertical_scrollbar(), + is_overlay_); } scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create( - std::unique_ptr<Scrollbar> scrollbar) { + scoped_refptr<Scrollbar> scrollbar) { return base::WrapRefCounted(new PaintedScrollbarLayer(std::move(scrollbar))); } -PaintedScrollbarLayer::PaintedScrollbarLayer( - std::unique_ptr<Scrollbar> scrollbar) - : scrollbar_(std::move(scrollbar)), +PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_refptr<Scrollbar> scrollbar) + : ScrollbarLayerBase(scrollbar->Orientation(), + scrollbar->IsLeftSideVerticalScrollbar()), + scrollbar_(std::move(scrollbar)), internal_contents_scale_(1.f), - supports_drag_snap_back_(false), - thumb_thickness_(scrollbar_->ThumbThickness()), - thumb_length_(scrollbar_->ThumbLength()), - is_overlay_(scrollbar_->IsOverlay()), + thumb_opacity_(scrollbar_->ThumbOpacity()), has_thumb_(scrollbar_->HasThumb()), - thumb_opacity_(scrollbar_->ThumbOpacity()) {} + supports_drag_snap_back_(scrollbar_->SupportsDragSnapBack()), + is_overlay_(scrollbar_->IsOverlay()) {} PaintedScrollbarLayer::~PaintedScrollbarLayer() = default; bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const { - return scrollbar_->IsOverlay(); + return is_overlay_; } void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { @@ -52,16 +51,15 @@ void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { internal_contents_scale_, internal_content_bounds_); scrollbar_layer->SetSupportsDragSnapBack(supports_drag_snap_back_); - scrollbar_layer->SetThumbThickness(thumb_thickness_); scrollbar_layer->SetBackButtonRect(back_button_rect_); scrollbar_layer->SetForwardButtonRect(forward_button_rect_); - scrollbar_layer->SetThumbLength(thumb_length_); - if (scrollbar_->Orientation() == HORIZONTAL) { - scrollbar_layer->SetTrackStart(track_rect_.x()); - scrollbar_layer->SetTrackLength(track_rect_.width()); + scrollbar_layer->SetTrackRect(track_rect_); + if (orientation() == HORIZONTAL) { + scrollbar_layer->SetThumbThickness(thumb_size_.height()); + scrollbar_layer->SetThumbLength(thumb_size_.width()); } else { - scrollbar_layer->SetTrackStart(track_rect_.y()); - scrollbar_layer->SetTrackLength(track_rect_.height()); + scrollbar_layer->SetThumbThickness(thumb_size_.width()); + scrollbar_layer->SetThumbLength(thumb_size_.height()); } if (track_resource_.get()) @@ -89,45 +87,33 @@ void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) { ScrollbarLayerBase::SetLayerTreeHost(host); } -gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect( - const gfx::Rect& layer_rect) const { - // Don't intersect with the bounds as in LayerRectToContentRect() because - // layer_rect here might be in coordinates of the containing layer. - gfx::Rect expanded_rect = gfx::ScaleToEnclosingRectSafe( - layer_rect, internal_contents_scale_, internal_contents_scale_); +gfx::Size PaintedScrollbarLayer::LayerSizeToContentSize( + const gfx::Size& layer_size) const { + gfx::Size content_size = + gfx::ScaleToCeiledSize(layer_size, internal_contents_scale_); // We should never return a rect bigger than the content bounds. - gfx::Size clamped_size = expanded_rect.size(); - clamped_size.SetToMin(internal_content_bounds_); - expanded_rect.set_size(clamped_size); - return expanded_rect; -} - -gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const { - gfx::Size thumb_size; - if (scrollbar_->Orientation() == HORIZONTAL) { - thumb_size = - gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness()); - } else { - thumb_size = - gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength()); - } - return gfx::Rect(thumb_size); + content_size.SetToMin(internal_content_bounds_); + return content_size; } void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() { - UpdateProperty(scrollbar_->SupportsDragSnapBack(), &supports_drag_snap_back_); + // These properties should never change. + DCHECK_EQ(supports_drag_snap_back_, scrollbar_->SupportsDragSnapBack()); + DCHECK_EQ(is_left_side_vertical_scrollbar(), + scrollbar_->IsLeftSideVerticalScrollbar()); + DCHECK_EQ(is_overlay_, scrollbar_->IsOverlay()); + DCHECK_EQ(orientation(), scrollbar_->Orientation()); + UpdateProperty(scrollbar_->TrackRect(), &track_rect_); UpdateProperty(scrollbar_->BackButtonRect(), &back_button_rect_); UpdateProperty(scrollbar_->ForwardButtonRect(), &forward_button_rect_); - UpdateProperty(scrollbar_->Location(), &location_); - UpdateProperty(scrollbar_->IsOverlay(), &is_overlay_); UpdateProperty(scrollbar_->HasThumb(), &has_thumb_); if (has_thumb_) { - UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_); - UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_); + // Ignore ThumbRect's location because the PaintedScrollbarLayerImpl will + // compute it from scroll offset. + UpdateProperty(scrollbar_->ThumbRect().size(), &thumb_size_); } else { - UpdateProperty(0, &thumb_thickness_); - UpdateProperty(0, &thumb_length_); + UpdateProperty(gfx::Size(), &thumb_size_); } } @@ -160,13 +146,12 @@ bool PaintedScrollbarLayer::Update() { UpdateThumbAndTrackGeometry(); - gfx::Rect track_layer_rect = gfx::Rect(location_, bounds()); - gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect( - track_layer_rect); + gfx::Size size = bounds(); + gfx::Size scaled_size = internal_content_bounds_; bool updated = false; - if (scaled_track_rect.IsEmpty()) { + if (scaled_size.IsEmpty()) { if (track_resource_) { track_resource_ = nullptr; thumb_resource_ = nullptr; @@ -185,22 +170,20 @@ bool PaintedScrollbarLayer::Update() { if (update_rect().IsEmpty() && track_resource_) return updated; - if (!track_resource_ || scrollbar_->NeedsPaintPart(TRACK)) { + if (!track_resource_ || + scrollbar_->NeedsRepaintPart(TRACK_BUTTONS_TICKMARKS)) { track_resource_ = ScopedUIResource::Create( layer_tree_host()->GetUIResourceManager(), - RasterizeScrollbarPart(track_layer_rect, scaled_track_rect, TRACK)); + RasterizeScrollbarPart(size, scaled_size, TRACK_BUTTONS_TICKMARKS)); } - gfx::Rect thumb_layer_rect = OriginThumbRect(); - gfx::Rect scaled_thumb_rect = - ScrollbarLayerRectToContentRect(thumb_layer_rect); - if (has_thumb_ && !scaled_thumb_rect.IsEmpty()) { - if (!thumb_resource_ || scrollbar_->NeedsPaintPart(THUMB) || - scaled_thumb_rect.size() != - thumb_resource_->GetBitmap(0, false).GetSize()) { + gfx::Size scaled_thumb_size = LayerSizeToContentSize(thumb_size_); + if (has_thumb_ && !scaled_thumb_size.IsEmpty()) { + if (!thumb_resource_ || scrollbar_->NeedsRepaintPart(THUMB) || + scaled_thumb_size != thumb_resource_->GetBitmap(0, false).GetSize()) { thumb_resource_ = ScopedUIResource::Create( layer_tree_host()->GetUIResourceManager(), - RasterizeScrollbarPart(thumb_layer_rect, scaled_thumb_rect, THUMB)); + RasterizeScrollbarPart(thumb_size_, scaled_thumb_size, THUMB)); } thumb_opacity_ = scrollbar_->ThumbOpacity(); } @@ -212,28 +195,26 @@ bool PaintedScrollbarLayer::Update() { } UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart( - const gfx::Rect& layer_rect, - const gfx::Rect& requested_content_rect, + const gfx::Size& size, + const gfx::Size& requested_content_size, ScrollbarPart part) { - DCHECK(!requested_content_rect.size().IsEmpty()); - DCHECK(!layer_rect.size().IsEmpty()); + DCHECK(!requested_content_size.IsEmpty()); + DCHECK(!size.IsEmpty()); - gfx::Rect content_rect = requested_content_rect; + gfx::Size content_size = requested_content_size; // Pages can end up requesting arbitrarily large scrollbars. Prevent this // from crashing due to OOM and try something smaller. SkBitmap skbitmap; bool allocation_succeeded = - skbitmap.tryAllocN32Pixels(content_rect.width(), content_rect.height()); + skbitmap.tryAllocN32Pixels(content_size.width(), content_size.height()); // Assuming 4bpp, caps at 4M. constexpr int kMinScrollbarDimension = 1024; - int dimension = std::max(content_rect.width(), content_rect.height()) / 2; + int dimension = std::max(content_size.width(), content_size.height()) / 2; while (!allocation_succeeded && dimension >= kMinScrollbarDimension) { - content_rect.Intersect(gfx::Rect(requested_content_rect.x(), - requested_content_rect.y(), dimension, - dimension)); + content_size.SetToMin(gfx::Size(dimension, dimension)); allocation_succeeded = - skbitmap.tryAllocN32Pixels(content_rect.width(), content_rect.height()); + skbitmap.tryAllocN32Pixels(content_size.width(), content_size.height()); if (!allocation_succeeded) dimension = dimension / 2; } @@ -243,13 +224,11 @@ UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart( SkiaPaintCanvas canvas(skbitmap); canvas.clear(SK_ColorTRANSPARENT); - float scale_x = - content_rect.width() / static_cast<float>(layer_rect.width()); - float scale_y = - content_rect.height() / static_cast<float>(layer_rect.height()); + float scale_x = content_size.width() / static_cast<float>(size.width()); + float scale_y = content_size.height() / static_cast<float>(size.height()); canvas.scale(SkFloatToScalar(scale_x), SkFloatToScalar(scale_y)); - scrollbar_->PaintPart(&canvas, part); + scrollbar_->PaintPart(&canvas, part, gfx::Rect(size)); // Make sure that the pixels are no longer mutable to unavoid unnecessary // allocation and copying. skbitmap.setImmutable(); diff --git a/chromium/cc/layers/painted_scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h index 444c042d0d3..444a3531263 100644 --- a/chromium/cc/layers/painted_scrollbar_layer.h +++ b/chromium/cc/layers/painted_scrollbar_layer.h @@ -18,7 +18,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerBase { std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; static scoped_refptr<PaintedScrollbarLayer> Create( - std::unique_ptr<Scrollbar> scrollbar); + scoped_refptr<Scrollbar> scrollbar); PaintedScrollbarLayer(const PaintedScrollbarLayer&) = delete; PaintedScrollbarLayer& operator=(const PaintedScrollbarLayer&) = delete; @@ -33,7 +33,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerBase { } protected: - explicit PaintedScrollbarLayer(std::unique_ptr<Scrollbar> scrollbar); + explicit PaintedScrollbarLayer(scoped_refptr<Scrollbar> scrollbar); ~PaintedScrollbarLayer() override; // For unit tests @@ -47,8 +47,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerBase { void UpdateThumbAndTrackGeometry(); private: - gfx::Rect ScrollbarLayerRectToContentRect(const gfx::Rect& layer_rect) const; - gfx::Rect OriginThumbRect() const; + gfx::Size LayerSizeToContentSize(const gfx::Size& layer_size) const; template <typename T> bool UpdateProperty(T value, T* prop) { @@ -59,11 +58,12 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerBase { return true; } - UIResourceBitmap RasterizeScrollbarPart(const gfx::Rect& layer_rect, - const gfx::Rect& content_rect, - ScrollbarPart part); + UIResourceBitmap RasterizeScrollbarPart( + const gfx::Size& size, + const gfx::Size& requested_content_size, + ScrollbarPart part); - std::unique_ptr<Scrollbar> scrollbar_; + scoped_refptr<Scrollbar> scrollbar_; ElementId scroll_element_id_; float internal_contents_scale_; @@ -71,20 +71,18 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerBase { // Snapshot of properties taken in UpdateThumbAndTrackGeometry and used in // PushPropertiesTo. - bool supports_drag_snap_back_; - int thumb_thickness_; - int thumb_length_; - gfx::Point location_; + gfx::Size thumb_size_; gfx::Rect track_rect_; gfx::Rect back_button_rect_; gfx::Rect forward_button_rect_; - bool is_overlay_; + float thumb_opacity_; bool has_thumb_; + const bool supports_drag_snap_back_; + const bool is_overlay_; + std::unique_ptr<ScopedUIResource> track_resource_; std::unique_ptr<ScopedUIResource> thumb_resource_; - - float thumb_opacity_; }; } // namespace cc diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc index 6b9d5829ba5..45400bfac2d 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc @@ -45,11 +45,7 @@ PaintedScrollbarLayerImpl::PaintedScrollbarLayerImpl( internal_contents_scale_(1.f), supports_drag_snap_back_(false), thumb_thickness_(0), - thumb_length_(0), - track_start_(0), - track_length_(0), - back_button_rect_(gfx::Rect(0, 0)), - forward_button_rect_(gfx::Rect(0, 0)) {} + thumb_length_(0) {} PaintedScrollbarLayerImpl::~PaintedScrollbarLayerImpl() = default; @@ -72,10 +68,9 @@ void PaintedScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) { scrollbar_layer->SetSupportsDragSnapBack(supports_drag_snap_back_); scrollbar_layer->SetThumbThickness(thumb_thickness_); scrollbar_layer->SetThumbLength(thumb_length_); - scrollbar_layer->SetTrackStart(track_start_); - scrollbar_layer->SetTrackLength(track_length_); scrollbar_layer->SetBackButtonRect(back_button_rect_); scrollbar_layer->SetForwardButtonRect(forward_button_rect_); + scrollbar_layer->SetTrackRect(track_rect_); scrollbar_layer->set_track_ui_resource_id(track_ui_resource_id_); scrollbar_layer->set_thumb_ui_resource_id(thumb_ui_resource_id_); @@ -197,15 +192,8 @@ int PaintedScrollbarLayerImpl::ThumbLength() const { return thumb_length_; } -void PaintedScrollbarLayerImpl::SetTrackStart(int track_start) { - if (track_start_ == track_start) - return; - track_start_ = track_start; - NoteLayerPropertyChanged(); -} - int PaintedScrollbarLayerImpl::TrackStart() const { - return track_start_; + return orientation() == VERTICAL ? track_rect_.y() : track_rect_.x(); } void PaintedScrollbarLayerImpl::SetBackButtonRect(gfx::Rect back_button_rect) { @@ -232,44 +220,50 @@ gfx::Rect PaintedScrollbarLayerImpl::ForwardButtonRect() const { } gfx::Rect PaintedScrollbarLayerImpl::BackTrackRect() const { - gfx::Rect thumb_rect = ComputeThumbQuadRect(); + const gfx::Rect thumb_rect = ComputeThumbQuadRect(); + const int rect_x = track_rect_.x(); + const int rect_y = track_rect_.y(); if (orientation() == HORIZONTAL) { - int rect_x = back_button_rect_.x() + back_button_rect_.width(); - int rect_y = back_button_rect_.y(); - return gfx::Rect(rect_x, rect_y, thumb_rect.x() - rect_x, - back_button_rect_.height()); + int width = thumb_rect.x() - rect_x; + int height = track_rect_.height(); + return gfx::Rect(rect_x, rect_y, width, height); } else { - int rect_x = back_button_rect_.x(); - int rect_y = back_button_rect_.y() + back_button_rect_.height(); - return gfx::Rect(rect_x, rect_y, back_button_rect_.width(), - thumb_rect.y() - rect_y); + int width = track_rect_.width(); + int height = thumb_rect.y() - rect_y; + return gfx::Rect(rect_x, rect_y, width, height); } } gfx::Rect PaintedScrollbarLayerImpl::ForwardTrackRect() const { - gfx::Rect thumb_rect = ComputeThumbQuadRect(); + const gfx::Rect thumb_rect = ComputeThumbQuadRect(); + const int track_end = TrackStart() + TrackLength(); if (orientation() == HORIZONTAL) { - int rect_x = thumb_rect.x() + thumb_rect.width(); - int rect_y = thumb_rect.y(); - return gfx::Rect(rect_x, rect_y, forward_button_rect_.x() - rect_x, - forward_button_rect_.height()); + int rect_x = thumb_rect.right(); + int rect_y = track_rect_.y(); + int width = track_end - rect_x; + int height = track_rect_.height(); + return gfx::Rect(rect_x, rect_y, width, height); } else { - int rect_x = thumb_rect.x(); - int rect_y = thumb_rect.y() + thumb_rect.height(); - return gfx::Rect(rect_x, rect_y, forward_button_rect_.width(), - forward_button_rect_.y() - rect_y); + int rect_x = track_rect_.x(); + int rect_y = thumb_rect.bottom(); + int width = track_rect_.width(); + int height = track_end - rect_y; + return gfx::Rect(rect_x, rect_y, width, height); } } -void PaintedScrollbarLayerImpl::SetTrackLength(int track_length) { - if (track_length_ == track_length) +void PaintedScrollbarLayerImpl::SetTrackRect(gfx::Rect track_rect) { + if (track_rect_ == track_rect) return; - track_length_ = track_length; + track_rect_ = track_rect; NoteLayerPropertyChanged(); } float PaintedScrollbarLayerImpl::TrackLength() const { - return track_length_ + (orientation() == VERTICAL ? vertical_adjust() : 0); + if (orientation() == VERTICAL) + return track_rect_.height() + vertical_adjust(); + else + return track_rect_.width(); } bool PaintedScrollbarLayerImpl::IsThumbResizable() const { diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h index 75f22053b8e..8c0ffd398ca 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.h +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h @@ -43,8 +43,7 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase { void SetForwardButtonRect(gfx::Rect forward_button_rect); void SetThumbThickness(int thumb_thickness); void SetThumbLength(int thumb_length); - void SetTrackStart(int track_start); - void SetTrackLength(int track_length); + void SetTrackRect(gfx::Rect track_rect); void set_track_ui_resource_id(UIResourceId uid) { track_ui_resource_id_ = uid; @@ -97,10 +96,9 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase { bool supports_drag_snap_back_; int thumb_thickness_; int thumb_length_; - int track_start_; - int track_length_; gfx::Rect back_button_rect_; gfx::Rect forward_button_rect_; + gfx::Rect track_rect_; }; } // namespace cc diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc index 3115841e84d..951126295d0 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc @@ -49,7 +49,7 @@ TEST(PaintedScrollbarLayerImplTest, Occlusion) { scrollbar_layer_impl->SetDrawsContent(true); scrollbar_layer_impl->SetThumbThickness(layer_size.width()); scrollbar_layer_impl->SetThumbLength(500); - scrollbar_layer_impl->SetTrackLength(layer_size.height()); + scrollbar_layer_impl->SetTrackRect(gfx::Rect(0, 0, 15, layer_size.height())); scrollbar_layer_impl->SetCurrentPos(100.f / 4); scrollbar_layer_impl->SetClipLayerLength(100.f); scrollbar_layer_impl->SetScrollLayerLength(200.f); diff --git a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc index 1852f6417f5..1c5684f51b8 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc @@ -25,7 +25,13 @@ class MockScrollbar : public FakeScrollbar { : FakeScrollbar(/*paint*/ true, /*has_thumb*/ true, /*is_overlay*/ false) {} - MOCK_METHOD2(PaintPart, void(PaintCanvas* canvas, ScrollbarPart part)); + MOCK_METHOD3(PaintPart, + void(PaintCanvas* canvas, + ScrollbarPart part, + const gfx::Rect& rect)); + + private: + ~MockScrollbar() override = default; }; TEST(PaintedScrollbarLayerTest, NeedsPaint) { @@ -36,9 +42,9 @@ TEST(PaintedScrollbarLayerTest, NeedsPaint) { auto layer_tree_host = FakeLayerTreeHost::Create( &fake_client_, &task_graph_runner_, animation_host.get()); - MockScrollbar* scrollbar = new MockScrollbar(); + auto scrollbar = base::MakeRefCounted<MockScrollbar>(); scoped_refptr<PaintedScrollbarLayer> scrollbar_layer = - PaintedScrollbarLayer::Create(std::unique_ptr<Scrollbar>(scrollbar)); + PaintedScrollbarLayer::Create(scrollbar); scrollbar_layer->SetIsDrawable(true); scrollbar_layer->SetBounds(gfx::Size(100, 100)); @@ -50,34 +56,34 @@ TEST(PaintedScrollbarLayerTest, NeedsPaint) { // Request no paint, but expect them to be painted because they have not // yet been initialized. - scrollbar->set_needs_paint_thumb(false); - scrollbar->set_needs_paint_track(false); - EXPECT_CALL(*scrollbar, PaintPart(_, THUMB)).Times(1); - EXPECT_CALL(*scrollbar, PaintPart(_, TRACK)).Times(1); + scrollbar->set_needs_repaint_thumb(false); + scrollbar->set_needs_repaint_track(false); + EXPECT_CALL(*scrollbar, PaintPart(_, THUMB, _)).Times(1); + EXPECT_CALL(*scrollbar, PaintPart(_, TRACK_BUTTONS_TICKMARKS, _)).Times(1); scrollbar_layer->Update(); - Mock::VerifyAndClearExpectations(scrollbar); + Mock::VerifyAndClearExpectations(scrollbar.get()); // The next update will paint nothing because the first update caused a paint. - EXPECT_CALL(*scrollbar, PaintPart(_, THUMB)).Times(0); - EXPECT_CALL(*scrollbar, PaintPart(_, TRACK)).Times(0); + EXPECT_CALL(*scrollbar, PaintPart(_, THUMB, _)).Times(0); + EXPECT_CALL(*scrollbar, PaintPart(_, TRACK_BUTTONS_TICKMARKS, _)).Times(0); scrollbar_layer->Update(); - Mock::VerifyAndClearExpectations(scrollbar); + Mock::VerifyAndClearExpectations(scrollbar.get()); // Enable the thumb. - EXPECT_CALL(*scrollbar, PaintPart(_, THUMB)).Times(1); - EXPECT_CALL(*scrollbar, PaintPart(_, TRACK)).Times(0); - scrollbar->set_needs_paint_thumb(true); - scrollbar->set_needs_paint_track(false); + EXPECT_CALL(*scrollbar, PaintPart(_, THUMB, _)).Times(1); + EXPECT_CALL(*scrollbar, PaintPart(_, TRACK_BUTTONS_TICKMARKS, _)).Times(0); + scrollbar->set_needs_repaint_thumb(true); + scrollbar->set_needs_repaint_track(false); scrollbar_layer->Update(); - Mock::VerifyAndClearExpectations(scrollbar); + Mock::VerifyAndClearExpectations(scrollbar.get()); // Enable the track. - EXPECT_CALL(*scrollbar, PaintPart(_, THUMB)).Times(0); - EXPECT_CALL(*scrollbar, PaintPart(_, TRACK)).Times(1); - scrollbar->set_needs_paint_thumb(false); - scrollbar->set_needs_paint_track(true); + EXPECT_CALL(*scrollbar, PaintPart(_, THUMB, _)).Times(0); + EXPECT_CALL(*scrollbar, PaintPart(_, TRACK_BUTTONS_TICKMARKS, _)).Times(1); + scrollbar->set_needs_repaint_thumb(false); + scrollbar->set_needs_repaint_track(true); scrollbar_layer->Update(); - Mock::VerifyAndClearExpectations(scrollbar); + Mock::VerifyAndClearExpectations(scrollbar.get()); } } // namespace diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc index d6c2c095d20..d13ed640807 100644 --- a/chromium/cc/layers/picture_layer.cc +++ b/chromium/cc/layers/picture_layer.cc @@ -17,8 +17,6 @@ #include "cc/trees/transform_node.h" #include "ui/gfx/geometry/rect_conversions.h" -static constexpr int kMaxNumberOfSlowPathsBeforeReporting = 5; - namespace cc { PictureLayer::PictureLayerInputs::PictureLayerInputs() = default; @@ -189,22 +187,6 @@ sk_sp<SkPicture> PictureLayer::GetPicture() const { return raster_source->GetFlattenedPicture(); } -bool PictureLayer::HasSlowPaths() const { - // The display list needs to be created (see: UpdateAndExpandInvalidation) - // before checking for slow paths. There are cases where an update will not - // create a display list (e.g., if the size is empty). We return false in - // these cases because the slow paths bit sticks true. - return picture_layer_inputs_.display_list && - picture_layer_inputs_.display_list->NumSlowPaths() > - kMaxNumberOfSlowPathsBeforeReporting; -} - -bool PictureLayer::HasNonAAPaint() const { - // We return false by default, as this bit sticks true. - return picture_layer_inputs_.display_list && - picture_layer_inputs_.display_list->HasNonAAPaint(); -} - void PictureLayer::ClearClient() { picture_layer_inputs_.client = nullptr; UpdateDrawsContent(HasDrawableContent()); diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h index 8150e1514fc..05e41d7be84 100644 --- a/chromium/cc/layers/picture_layer.h +++ b/chromium/cc/layers/picture_layer.h @@ -49,8 +49,6 @@ class CC_EXPORT PictureLayer : public Layer { void SetNeedsDisplayRect(const gfx::Rect& layer_rect) override; sk_sp<SkPicture> GetPicture() const override; bool Update() override; - bool HasSlowPaths() const override; - bool HasNonAAPaint() const override; void RunMicroBenchmark(MicroBenchmark* benchmark) override; void CaptureContent(const gfx::Rect& rect, std::vector<NodeId>* content) override; diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc index 2369a6610ef..e4c8eb90abd 100644 --- a/chromium/cc/layers/picture_layer_impl.cc +++ b/chromium/cc/layers/picture_layer_impl.cc @@ -680,6 +680,17 @@ void PictureLayerImpl::UpdateRasterSource( SetPaintWorkletInputs({}); } } + + // If the MSAA sample count has changed, we need to re-raster the complete + // layer. + if (raster_source_ && raster_source_->GetDisplayItemList() && + raster_source->GetDisplayItemList() && + layer_tree_impl()->GetMSAASampleCountForRaster( + raster_source_->GetDisplayItemList()) != + layer_tree_impl()->GetMSAASampleCountForRaster( + raster_source->GetDisplayItemList())) { + new_invalidation->Union(gfx::Rect(raster_source->GetSize())); + } } // The |raster_source_| is initially null, so have to check for that for the @@ -747,7 +758,7 @@ bool PictureLayerImpl::UpdateCanUseLCDTextAfterCommit() { gfx::Rect bounds_rect(bounds()); invalidation_ = Region(bounds_rect); tilings_->Invalidate(invalidation_); - SetUpdateRect(bounds_rect); + UnionUpdateRect(bounds_rect); return true; } @@ -1573,14 +1584,9 @@ PictureLayerImpl::InvalidateRegionForImages( if (invalidation.IsEmpty()) return ImageInvalidationResult::kNoInvalidation; - // Make sure to union the rect from this invalidation with the update_rect - // instead of over-writing it. We don't want to reset the update that came - // from the main thread. // Note: We can use a rect here since this is only used to track damage for a // frame and not raster invalidation. - gfx::Rect new_update_rect = invalidation.bounds(); - new_update_rect.Union(update_rect()); - SetUpdateRect(new_update_rect); + UnionUpdateRect(invalidation.bounds()); invalidation_.Union(invalidation); tilings_->Invalidate(invalidation); diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc index 77fb24781a6..67e1df67e5a 100644 --- a/chromium/cc/layers/picture_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_layer_impl_unittest.cc @@ -2491,73 +2491,6 @@ TEST_F(LegacySWPictureLayerImplTest, RecreateInvalidPendingTreeTiles) { EXPECT_NE(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0)); } -class MSAAEnabledPictureLayerImplTest : public PictureLayerImplTest { - public: - LayerTreeSettings CreateSettings() override { - LayerTreeSettings settings = PictureLayerImplTest::CreateSettings(); - settings.gpu_rasterization_msaa_sample_count = 1; - return settings; - } -}; - -TEST_F(MSAAEnabledPictureLayerImplTest, SyncTilingAfterMSAAToggles) { - host_impl()->AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - - gfx::Size layer_bounds(10, 10); - - scoped_refptr<FakeRasterSource> pending_raster_source = - FakeRasterSource::CreateFilled(layer_bounds); - scoped_refptr<FakeRasterSource> active_raster_source = - FakeRasterSource::CreateFilled(layer_bounds); - - SetupTrees(pending_raster_source, active_raster_source); - - EXPECT_TRUE(pending_layer()->tilings()->FindTilingWithScaleKey(1.f)); - EXPECT_TRUE(active_layer()->tilings()->FindTilingWithScaleKey(1.f)); - - // MSAA is disabled by default. - EXPECT_FALSE(host_impl()->use_msaa()); - EXPECT_EQ(0u, pending_layer()->release_tile_resources_count()); - EXPECT_EQ(0u, active_layer()->release_tile_resources_count()); - EXPECT_EQ(0u, pending_layer()->release_resources_count()); - EXPECT_EQ(0u, active_layer()->release_resources_count()); - // Toggling MSAA clears all tilings on both trees. - host_impl()->SetContentHasSlowPaths(true); - host_impl()->CommitComplete(); - EXPECT_TRUE(host_impl()->use_msaa()); - EXPECT_EQ(1u, pending_layer()->release_tile_resources_count()); - EXPECT_EQ(1u, active_layer()->release_tile_resources_count()); - EXPECT_EQ(1u, pending_layer()->release_resources_count()); - EXPECT_EQ(1u, active_layer()->release_resources_count()); - - // But the pending layer gets a tiling back, and can activate it. - EXPECT_TRUE(pending_layer()->tilings()->FindTilingWithScaleKey(1.f)); - EXPECT_EQ(0u, active_layer()->tilings()->num_tilings()); - - host_impl()->NotifyReadyToActivate(); - ActivateTree(); - EXPECT_TRUE(active_layer()->tilings()->FindTilingWithScaleKey(1.f)); - - SetupPendingTree(pending_raster_source); - EXPECT_TRUE(pending_layer()->tilings()->FindTilingWithScaleKey(1.f)); - - // Toggling msaa clears all tilings on both trees. - host_impl()->SetContentHasSlowPaths(false); - EXPECT_TRUE(host_impl()->use_msaa()); - host_impl()->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, - host_impl()->gpu_rasterization_status()); - EXPECT_EQ(2u, pending_layer()->release_tile_resources_count()); - EXPECT_EQ(2u, active_layer()->release_tile_resources_count()); - EXPECT_EQ(2u, pending_layer()->release_resources_count()); - EXPECT_EQ(2u, active_layer()->release_resources_count()); - host_impl()->NotifyReadyToActivate(); - - host_impl()->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, - host_impl()->gpu_rasterization_status()); -} - TEST_F(LegacySWPictureLayerImplTest, HighResCreatedWhenBoundsShrink) { // Put 0.5 as high res. SetInitialDeviceScaleFactor(0.5f); diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc index 9f8feabe10d..daf36769d2b 100644 --- a/chromium/cc/layers/picture_layer_unittest.cc +++ b/chromium/cc/layers/picture_layer_unittest.cc @@ -227,76 +227,6 @@ TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) { host_impl.active_tree()->root_layer()->DidDraw(nullptr); } -TEST(PictureLayerTest, HasSlowPaths) { - std::unique_ptr<FakeRecordingSource> recording_source_owned( - new FakeRecordingSource); - FakeRecordingSource* recording_source = recording_source_owned.get(); - - gfx::Size layer_bounds(200, 200); - gfx::Rect layer_rect(layer_bounds); - Region invalidation(layer_rect); - - FakeContentLayerClient client; - client.set_bounds(layer_bounds); - scoped_refptr<FakePictureLayer> layer = - FakePictureLayer::CreateWithRecordingSource( - &client, std::move(recording_source_owned)); - - FakeLayerTreeHostClient host_client; - TestTaskGraphRunner task_graph_runner; - auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); - std::unique_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create( - &host_client, &task_graph_runner, animation_host.get()); - host->SetRootLayer(layer); - - recording_source->SetNeedsDisplayRect(layer_rect); - layer->Update(); - - // Layer does not have slow paths by default. - EXPECT_FALSE(layer->HasSlowPaths()); - - // Add slow-path content to the client. - client.set_contains_slow_paths(true); - recording_source->SetNeedsDisplayRect(layer_rect); - layer->Update(); - EXPECT_TRUE(layer->HasSlowPaths()); -} - -TEST(PictureLayerTest, HasNonAAPaint) { - std::unique_ptr<FakeRecordingSource> recording_source_owned( - new FakeRecordingSource); - FakeRecordingSource* recording_source = recording_source_owned.get(); - - gfx::Size layer_bounds(200, 200); - gfx::Rect layer_rect(layer_bounds); - Region invalidation(layer_rect); - - FakeContentLayerClient client; - client.set_bounds(layer_bounds); - scoped_refptr<FakePictureLayer> layer = - FakePictureLayer::CreateWithRecordingSource( - &client, std::move(recording_source_owned)); - - FakeLayerTreeHostClient host_client; - TestTaskGraphRunner task_graph_runner; - auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN); - std::unique_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create( - &host_client, &task_graph_runner, animation_host.get()); - host->SetRootLayer(layer); - - recording_source->SetNeedsDisplayRect(layer_rect); - layer->Update(); - - // Layer does not have non-aa paint by default. - EXPECT_FALSE(layer->HasNonAAPaint()); - - // Add non-aa content to the client. - client.add_draw_rect(layer_rect, PaintFlags()); - recording_source->SetNeedsDisplayRect(layer_rect); - layer->Update(); - EXPECT_TRUE(layer->HasNonAAPaint()); -} - // PicturePile uses the source frame number as a unit for measuring invalidation // frequency. When a pile moves between compositors, the frame number increases // non-monotonically. This executes that code path under this scenario allowing diff --git a/chromium/cc/layers/scrollbar_layer_base.cc b/chromium/cc/layers/scrollbar_layer_base.cc index 14c743b9eb9..e676c3eed1e 100644 --- a/chromium/cc/layers/scrollbar_layer_base.cc +++ b/chromium/cc/layers/scrollbar_layer_base.cc @@ -8,7 +8,10 @@ namespace cc { -ScrollbarLayerBase::ScrollbarLayerBase() { +ScrollbarLayerBase::ScrollbarLayerBase(ScrollbarOrientation orientation, + bool is_left_side_vertical_scrollbar) + : orientation_(orientation), + is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar) { SetIsScrollbar(true); } @@ -24,8 +27,12 @@ void ScrollbarLayerBase::SetScrollElementId(ElementId element_id) { void ScrollbarLayerBase::PushPropertiesTo(LayerImpl* layer) { Layer::PushPropertiesTo(layer); - static_cast<ScrollbarLayerImplBase*>(layer)->SetScrollElementId( - scroll_element_id_); + + auto* scrollbar_layer_impl = static_cast<ScrollbarLayerImplBase*>(layer); + DCHECK_EQ(scrollbar_layer_impl->orientation(), orientation_); + DCHECK_EQ(scrollbar_layer_impl->is_left_side_vertical_scrollbar(), + is_left_side_vertical_scrollbar_); + scrollbar_layer_impl->SetScrollElementId(scroll_element_id_); } } // namespace cc diff --git a/chromium/cc/layers/scrollbar_layer_base.h b/chromium/cc/layers/scrollbar_layer_base.h index 00c5dfa3491..ad783c3dd87 100644 --- a/chromium/cc/layers/scrollbar_layer_base.h +++ b/chromium/cc/layers/scrollbar_layer_base.h @@ -13,14 +13,23 @@ namespace cc { class CC_EXPORT ScrollbarLayerBase : public Layer { public: void SetScrollElementId(ElementId element_id); + ElementId scroll_element_id() const { return scroll_element_id_; } + + ScrollbarOrientation orientation() const { return orientation_; } + bool is_left_side_vertical_scrollbar() const { + return is_left_side_vertical_scrollbar_; + } void PushPropertiesTo(LayerImpl* layer) override; protected: - ScrollbarLayerBase(); + ScrollbarLayerBase(ScrollbarOrientation orientation, + bool is_left_side_vertical_scrollbar); ~ScrollbarLayerBase() override; private: + const ScrollbarOrientation orientation_; + const bool is_left_side_vertical_scrollbar_; ElementId scroll_element_id_; }; diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc index 98a5011c0c3..da855d4f9cd 100644 --- a/chromium/cc/layers/scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/scrollbar_layer_unittest.cc @@ -137,7 +137,7 @@ class BaseScrollbarLayerTest : public testing::Test { LayerImpl* LayerImplForScrollAreaAndScrollbar( FakeLayerTreeHost* host, - std::unique_ptr<Scrollbar> scrollbar, + scoped_refptr<Scrollbar> scrollbar, bool reverse_order, bool use_solid_color_scrollbar, int thumb_thickness, @@ -195,6 +195,9 @@ class FakePaintedOverlayScrollbar : public FakeScrollbar { gfx::Rect NinePatchThumbAperture() const override { return gfx::Rect(1, 1, 1, 1); } + + private: + ~FakePaintedOverlayScrollbar() override = default; }; // Test that a painted overlay scrollbar will repaint and recrate its resource @@ -203,11 +206,9 @@ class FakePaintedOverlayScrollbar : public FakeScrollbar { TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) { scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> content_layer = Layer::Create(); - std::unique_ptr<FakePaintedOverlayScrollbar> scrollbar( - new FakePaintedOverlayScrollbar); - FakePaintedOverlayScrollbar* fake_scrollbar = scrollbar.get(); + auto fake_scrollbar = base::MakeRefCounted<FakePaintedOverlayScrollbar>(); scoped_refptr<PaintedOverlayScrollbarLayer> scrollbar_layer = - PaintedOverlayScrollbarLayer::Create(std::move(scrollbar)); + PaintedOverlayScrollbarLayer::Create(fake_scrollbar); scrollbar_layer->SetScrollElementId(layer_tree_root->element_id()); // Setup. @@ -224,7 +225,7 @@ TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) { // First call to update should create a resource. The scrollbar itself thinks // it needs a repaint. { - fake_scrollbar->set_needs_paint_thumb(true); + fake_scrollbar->set_needs_repaint_thumb(true); EXPECT_EQ(0u, fake_ui_resource_manager_->UIResourceCount()); EXPECT_TRUE(scrollbar_layer->Update()); EXPECT_EQ(1u, fake_ui_resource_manager_->UIResourceCount()); @@ -233,7 +234,7 @@ TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) { // Now the scrollbar has been painted and nothing else has changed, calling // Update() shouldn't have an effect. { - fake_scrollbar->set_needs_paint_thumb(false); + fake_scrollbar->set_needs_repaint_thumb(false); EXPECT_FALSE(scrollbar_layer->Update()); EXPECT_EQ(1u, fake_ui_resource_manager_->UIResourceCount()); } @@ -258,11 +259,12 @@ class FakeNinePatchScrollbar : public FakeScrollbar { : FakeScrollbar(/*paint*/ true, /*has_thumb*/ true, /*is_overlay*/ true) { } bool UsesNinePatchThumbResource() const override { return true; } + + private: + ~FakeNinePatchScrollbar() override = default; }; TEST_F(ScrollbarLayerTest, ScrollElementIdPushedAcrossCommit) { - std::unique_ptr<Scrollbar> scrollbar1(new FakeScrollbar); - std::unique_ptr<Scrollbar> scrollbar2(new FakeNinePatchScrollbar); scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> layer_a = Layer::Create(); scoped_refptr<Layer> layer_b = Layer::Create(); @@ -270,10 +272,11 @@ TEST_F(ScrollbarLayerTest, ScrollElementIdPushedAcrossCommit) { layer_b->SetElementId(LayerIdToElementIdForTesting(layer_b->id())); scoped_refptr<PaintedScrollbarLayer> painted_scrollbar_layer = - PaintedScrollbarLayer::Create(std::move(scrollbar1)); + PaintedScrollbarLayer::Create(base::MakeRefCounted<FakeScrollbar>()); painted_scrollbar_layer->SetScrollElementId(layer_a->element_id()); scoped_refptr<PaintedOverlayScrollbarLayer> painted_overlay_scrollbar_layer = - PaintedOverlayScrollbarLayer::Create(std::move(scrollbar2)); + PaintedOverlayScrollbarLayer::Create( + base::MakeRefCounted<FakeNinePatchScrollbar>()); painted_overlay_scrollbar_layer->SetScrollElementId(layer_a->element_id()); scoped_refptr<SolidColorScrollbarLayer> solid_color_scrollbar_layer = SolidColorScrollbarLayer::Create(VERTICAL, 1, 1, false); @@ -331,13 +334,12 @@ TEST_F(ScrollbarLayerTest, ScrollElementIdPushedAcrossCommit) { } TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) { - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar); scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> scroll_layer = Layer::Create(); scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id())); scoped_refptr<Layer> content_layer = Layer::Create(); scoped_refptr<PaintedScrollbarLayer> scrollbar_layer = - PaintedScrollbarLayer::Create(std::move(scrollbar)); + PaintedScrollbarLayer::Create(base::MakeRefCounted<FakeScrollbar>()); scrollbar_layer->SetScrollElementId(scroll_layer->element_id()); // Choose bounds to give max_scroll_offset = (30, 50). @@ -420,10 +422,8 @@ TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) { scrollbar_layer->SetScrollElementId(root_layer->element_id()); // The track_rect should be relative to the scrollbar's origin. - scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10)); - scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); - scrollbar_layer->fake_scrollbar()->set_thumb_length(4); + scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(4, 10)); LayerImpl* root_layer_impl = nullptr; PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr; @@ -461,10 +461,8 @@ TEST_F(ScrollbarLayerTest, ThumbRect) { scrollbar_layer->SetScrollElementId(root_layer->element_id()); // The track_rect should be relative to the scrollbar's origin. - scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10)); - scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); - scrollbar_layer->fake_scrollbar()->set_thumb_length(4); + scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(4, 10)); layer_tree_host_->UpdateLayers(); LayerImpl* root_layer_impl = nullptr; @@ -493,8 +491,7 @@ TEST_F(ScrollbarLayerTest, ThumbRect) { scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); // Change thumb thickness and length. - scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4); - scrollbar_layer->fake_scrollbar()->set_thumb_length(6); + scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(6, 4)); UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(), @@ -502,7 +499,6 @@ TEST_F(ScrollbarLayerTest, ThumbRect) { // Shrink the scrollbar layer to cover only the track. scrollbar_layer->SetBounds(gfx::Size(50, 10)); - scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 10, 50, 10)); UPDATE_AND_EXTRACT_LAYER_POINTERS(); @@ -535,8 +531,7 @@ TEST_F(ScrollbarLayerTest, ThumbRectForOverlayLeftSideVerticalScrollbar) { scrollbar_layer->SetBounds(gfx::Size(10, 20)); scrollbar_layer->SetScrollElementId(root_layer->element_id()); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 10, 20)); - scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); - scrollbar_layer->fake_scrollbar()->set_thumb_length(4); + scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(10, 4)); layer_tree_host_->UpdateLayers(); LayerImpl* root_layer_impl = nullptr; PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr; @@ -557,8 +552,7 @@ TEST_F(ScrollbarLayerTest, ThumbRectForOverlayLeftSideVerticalScrollbar) { scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); // Change thumb thickness and length. - scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4); - scrollbar_layer->fake_scrollbar()->set_thumb_length(6); + scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(4, 6)); UPDATE_AND_EXTRACT_LAYER_POINTERS(); // For left side vertical scrollbars thumb_rect.x = bounds.width() - // thumb_thickness. @@ -571,9 +565,9 @@ TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) { const int kTrackStart = 1; const int kTrackLength = 100; - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( - layer_tree_host_.get(), std::move(scrollbar), false, true, + layer_tree_host_.get(), + base::MakeRefCounted<FakeScrollbar>(false, true, true), false, true, kThumbThickness, kTrackStart); ScrollbarLayerImplBase* scrollbar_layer_impl = static_cast<SolidColorScrollbarLayerImpl*>( @@ -632,16 +626,13 @@ TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) { const int kTrackStart = 0; const int kTrackLength = 10; - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); - scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> scroll_layer = Layer::Create(); scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id())); scoped_refptr<Layer> child1 = Layer::Create(); const bool kIsLeftSideVerticalScrollbar = false; scoped_refptr<SolidColorScrollbarLayer> child2 = - SolidColorScrollbarLayer::Create(scrollbar->Orientation(), - kThumbThickness, kTrackStart, + SolidColorScrollbarLayer::Create(HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar); child2->SetScrollElementId(scroll_layer->element_id()); scroll_layer->AddChild(child1); @@ -689,8 +680,6 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerOpacity) { const int kThumbThickness = 3; const int kTrackStart = 0; - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); - scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> scroll_layer = Layer::Create(); scroll_layer->SetElementId(ElementId(200)); @@ -698,8 +687,7 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerOpacity) { scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer; const bool kIsLeftSideVerticalScrollbar = false; scrollbar_layer = SolidColorScrollbarLayer::Create( - scrollbar->Orientation(), kThumbThickness, kTrackStart, - kIsLeftSideVerticalScrollbar); + HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar); scrollbar_layer->SetScrollElementId(scroll_layer->element_id()); scrollbar_layer->SetElementId(ElementId(300)); scroll_layer->AddChild(child1); @@ -767,7 +755,6 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerPushProperties) { // its properties after scroll layer. const int kThumbThickness = 3; const int kTrackStart = 0; - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> scroll_layer = Layer::Create(); @@ -775,8 +762,7 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerPushProperties) { scoped_refptr<Layer> child1 = Layer::Create(); const bool kIsLeftSideVerticalScrollbar = false; scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer = - SolidColorScrollbarLayer::Create(scrollbar->Orientation(), - kThumbThickness, kTrackStart, + SolidColorScrollbarLayer::Create(HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar); scrollbar_layer->SetScrollElementId(scroll_layer->element_id()); scroll_layer->AddChild(child1); @@ -915,10 +901,8 @@ TEST_F(AuraScrollbarLayerTest, ScrollbarLayerCreateAfterSetScrollable) { layer_tree_host_->CommitAndCreatePendingTree(); host_impl->ActivateSyncTree(); - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer = - SolidColorScrollbarLayer::Create(scrollbar->Orientation(), - kThumbThickness, kTrackStart, + SolidColorScrollbarLayer::Create(HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar); scrollbar_layer->SetScrollElementId(scroll_layer->element_id()); scroll_layer->InsertChild(scrollbar_layer, 1); @@ -1035,7 +1019,6 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest { int expected_created, int expected_deleted, bool use_solid_color_scrollbar) { - std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false)); scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> content_layer = Layer::Create(); scoped_refptr<ScrollbarLayerBase> scrollbar_layer; @@ -1044,10 +1027,11 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest { const int kTrackStart = 0; const bool kIsLeftSideVerticalScrollbar = false; scrollbar_layer = SolidColorScrollbarLayer::Create( - scrollbar->Orientation(), kThumbThickness, kTrackStart, + HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar); } else { - scrollbar_layer = PaintedScrollbarLayer::Create(std::move(scrollbar)); + scrollbar_layer = PaintedScrollbarLayer::Create( + base::MakeRefCounted<FakeScrollbar>(false, true, false)); } scrollbar_layer->SetScrollElementId(layer_tree_root->element_id()); layer_tree_root->AddChild(content_layer); @@ -1349,7 +1333,6 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest { scrollbar_layer->SetBounds(scrollbar_rect.size()); scrollbar_layer->SetPosition(gfx::PointF(scrollbar_rect.origin())); - scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin()); scrollbar_layer->fake_scrollbar()->set_track_rect( gfx::Rect(scrollbar_rect.size())); diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.cc b/chromium/cc/layers/solid_color_scrollbar_layer.cc index 92e321f2d67..caf3a0aee84 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer.cc +++ b/chromium/cc/layers/solid_color_scrollbar_layer.cc @@ -13,9 +13,9 @@ namespace cc { std::unique_ptr<LayerImpl> SolidColorScrollbarLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) { - return SolidColorScrollbarLayerImpl::Create(tree_impl, id(), orientation_, - thumb_thickness_, track_start_, - is_left_side_vertical_scrollbar_); + return SolidColorScrollbarLayerImpl::Create( + tree_impl, id(), orientation(), thumb_thickness_, track_start_, + is_left_side_vertical_scrollbar()); } scoped_refptr<SolidColorScrollbarLayer> SolidColorScrollbarLayer::Create( @@ -33,10 +33,9 @@ SolidColorScrollbarLayer::SolidColorScrollbarLayer( int thumb_thickness, int track_start, bool is_left_side_vertical_scrollbar) - : orientation_(orientation), + : ScrollbarLayerBase(orientation, is_left_side_vertical_scrollbar), thumb_thickness_(thumb_thickness), - track_start_(track_start), - is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar) { + track_start_(track_start) { Layer::SetOpacity(0.f); } diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.h b/chromium/cc/layers/solid_color_scrollbar_layer.h index 8aed2f50026..6bb1615e312 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer.h +++ b/chromium/cc/layers/solid_color_scrollbar_layer.h @@ -37,10 +37,8 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerBase { bool is_left_side_vertical_scrollbar); ~SolidColorScrollbarLayer() override; - ScrollbarOrientation orientation_; int thumb_thickness_; int track_start_; - bool is_left_side_vertical_scrollbar_; }; } // namespace cc diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc index 6ef4249c51e..ea7c454d540 100644 --- a/chromium/cc/layers/surface_layer_impl.cc +++ b/chromium/cc/layers/surface_layer_impl.cc @@ -149,7 +149,7 @@ void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass, auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>(); quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, surface_range_, background_color(), - stretch_content_to_fill_bounds_, has_pointer_events_none_); + stretch_content_to_fill_bounds_); quad->is_reflection = is_reflection_; // Add the primary surface ID as a dependency. append_quads_data->activation_dependencies.push_back(surface_range_.end()); diff --git a/chromium/cc/layers/texture_layer_impl_unittest.cc b/chromium/cc/layers/texture_layer_impl_unittest.cc index dad52054171..0e46ca0ae60 100644 --- a/chromium/cc/layers/texture_layer_impl_unittest.cc +++ b/chromium/cc/layers/texture_layer_impl_unittest.cc @@ -102,41 +102,5 @@ TEST(TextureLayerImplTest, Occlusion) { } } -TEST(TextureLayerImplTest, ResourceNotFreedOnMSAAToggle) { - bool released = false; - LayerTreeImplTestBase impl( - FakeLayerTreeFrameSink::Create3dForGpuRasterization()); - impl.host_impl()->AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - - gfx::Size layer_size(1000, 1000); - gfx::Size viewport_size(1000, 1000); - - viz::TransferableResource resource; - resource.is_software = false; - resource.mailbox_holder.mailbox = gpu::Mailbox::Generate(); - resource.mailbox_holder.sync_token = - gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x234), 0x456); - resource.mailbox_holder.texture_target = GL_TEXTURE_2D; - - TextureLayerImpl* texture_layer_impl = impl.AddLayer<TextureLayerImpl>(); - texture_layer_impl->SetBounds(layer_size); - texture_layer_impl->SetDrawsContent(true); - texture_layer_impl->SetTransferableResource( - resource, viz::SingleReleaseCallback::Create(base::BindOnce( - [](bool* released, const gpu::SyncToken& sync_token, - bool lost) { *released = true; }, - base::Unretained(&released)))); - CopyProperties(impl.root_layer(), texture_layer_impl); - - impl.CalcDrawProps(viewport_size); - - EXPECT_FALSE(released); - // Toggling MSAA clears all tilings on both trees. - impl.host_impl()->SetContentHasSlowPaths(true); - impl.host_impl()->CommitComplete(); - EXPECT_FALSE(released); -} - } // namespace } // namespace cc diff --git a/chromium/cc/layers/tile_size_calculator.cc b/chromium/cc/layers/tile_size_calculator.cc index eacb897a12f..b6397bcaf1b 100644 --- a/chromium/cc/layers/tile_size_calculator.cc +++ b/chromium/cc/layers/tile_size_calculator.cc @@ -10,10 +10,6 @@ namespace cc { namespace { -// Even for really wide viewports, at some point GPU raster should use -// less than 4 tiles to fill the viewport. This is set to 256 as a -// sane minimum for now, but we might want to tune this for low-end. -const int kMinHeightForGpuRasteredTile = 256; // When making odd-sized tiles, round them up to increase the chances // of using the same tile size. @@ -44,7 +40,8 @@ gfx::Size ApplyDsfAdjustment(const gfx::Size& device_pixels_size, float dsf) { // viewport vertically. gfx::Size CalculateGpuTileSize(const gfx::Size& base_tile_size, const gfx::Size& content_bounds, - const gfx::Size& max_tile_size) { + const gfx::Size& max_tile_size, + int min_height_for_gpu_raster_tile) { int tile_width = base_tile_size.width(); // Increase the height proportionally as the width decreases, and pad by our @@ -66,7 +63,7 @@ gfx::Size CalculateGpuTileSize(const gfx::Size& base_tile_size, tile_width = MathUtil::UncheckedRoundUp(tile_width, kGpuDefaultTileRoundUp); tile_height = MathUtil::UncheckedRoundUp(tile_height, kGpuDefaultTileRoundUp); - tile_height = std::max(tile_height, kMinHeightForGpuRasteredTile); + tile_height = std::max(tile_height, min_height_for_gpu_raster_tile); if (!max_tile_size.IsEmpty()) { tile_width = std::min(tile_width, max_tile_size.width()); @@ -111,6 +108,8 @@ TileSizeCalculator::AffectingParams TileSizeCalculator::GetAffectingParams() { params.max_texture_size = layer_tree_impl->max_texture_size(); params.use_gpu_rasterization = layer_tree_impl->use_gpu_rasterization(); params.max_tile_size = layer_tree_impl->settings().max_gpu_raster_tile_size; + params.min_height_for_gpu_raster_tile = + layer_tree_impl->settings().min_height_for_gpu_raster_tile; params.gpu_raster_max_texture_size = layer_impl()->gpu_raster_max_texture_size(); params.device_scale_factor = layer_tree_impl->device_scale_factor(); @@ -153,15 +152,17 @@ gfx::Size TileSizeCalculator::CalculateTileSize() { // Set our initial size assuming a |base_tile_size| equal to our // |viewport_size|. gfx::Size default_tile_size = - CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size); + CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size, + affecting_params_.min_height_for_gpu_raster_tile); // Use half-width GPU tiles when the content_width is greater than our // calculated tile size. if (content_bounds.width() > default_tile_size.width()) { // Divide width by 2 and round up. base_tile_size.set_width((base_tile_size.width() + 1) / 2); - default_tile_size = - CalculateGpuTileSize(base_tile_size, content_bounds, max_tile_size); + default_tile_size = CalculateGpuTileSize( + base_tile_size, content_bounds, max_tile_size, + affecting_params_.min_height_for_gpu_raster_tile); } default_tile_width = default_tile_size.width(); diff --git a/chromium/cc/layers/tile_size_calculator.h b/chromium/cc/layers/tile_size_calculator.h index cd455b922d2..ab00258e193 100644 --- a/chromium/cc/layers/tile_size_calculator.h +++ b/chromium/cc/layers/tile_size_calculator.h @@ -26,6 +26,7 @@ class CC_EXPORT TileSizeCalculator { bool use_gpu_rasterization = false; float device_scale_factor = 0.0f; gfx::Size max_tile_size; + int min_height_for_gpu_raster_tile; gfx::Size gpu_raster_max_texture_size; gfx::Size max_untiled_layer_size; gfx::Size default_tile_size; diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc index b76baeb77e0..905a0a5a024 100644 --- a/chromium/cc/layers/video_layer_impl.cc +++ b/chromium/cc/layers/video_layer_impl.cc @@ -188,7 +188,7 @@ void VideoLayerImpl::ReleaseResources() { } void VideoLayerImpl::SetNeedsRedraw() { - SetUpdateRect(gfx::UnionRects(update_rect(), gfx::Rect(bounds()))); + UnionUpdateRect(gfx::Rect(bounds())); layer_tree_impl()->SetNeedsRedraw(); } diff --git a/chromium/cc/layers/viewport.cc b/chromium/cc/layers/viewport.cc index 5a50ee6b010..635d9996ccd 100644 --- a/chromium/cc/layers/viewport.cc +++ b/chromium/cc/layers/viewport.cc @@ -69,18 +69,19 @@ Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& physical_delta, return result; } -bool Viewport::CanScroll(const ScrollState& scroll_state) const { - auto* outer_node = OuterScrollNode(); +bool Viewport::CanScroll(const ScrollNode& node, + const ScrollState& scroll_state) const { + DCHECK(ShouldScroll(node)); - if (!outer_node) - return false; + bool result = host_impl_->CanConsumeDelta(*InnerScrollNode(), scroll_state); - bool result = false; - if (auto* inner_node = InnerScrollNode()) - result |= host_impl_->CanConsumeDelta(*inner_node, scroll_state); - - result |= host_impl_->CanConsumeDelta(*outer_node, scroll_state); + // If the passed in node is the inner viewport, we're not interested in the + // scrollability of the outer viewport. See LTHI::GetNodeToScroll for how the + // scroll chain is constructed. + if (node.scrolls_inner_viewport) + return result; + result |= host_impl_->CanConsumeDelta(*OuterScrollNode(), scroll_state); return result; } @@ -229,15 +230,20 @@ void Viewport::PinchEnd(const gfx::Point& anchor, bool snap_to_min) { pinch_zoom_active_ = false; } -bool Viewport::ShouldScroll(const ScrollNode& scroll_node) { +bool Viewport::ShouldScroll(const ScrollNode& scroll_node) const { + // Non-main frame renderers and the UI compositor will not have viewport + // scrolling nodes and should thus never scroll with the Viewport object. + if (!InnerScrollNode() || !OuterScrollNode()) { + DCHECK(!InnerScrollNode()); + DCHECK(!OuterScrollNode()); + DCHECK(!scroll_node.scrolls_inner_viewport); + DCHECK(!scroll_node.scrolls_outer_viewport); + return false; + } return scroll_node.scrolls_inner_viewport || scroll_node.scrolls_outer_viewport; } -ScrollNode* Viewport::MainScrollNode() const { - return host_impl_->OuterViewportScrollNode(); -} - gfx::Vector2dF Viewport::ScrollBrowserControls(const gfx::Vector2dF& delta) { gfx::Vector2dF excess_delta = host_impl_->browser_controls_manager()->ScrollBy(delta); diff --git a/chromium/cc/layers/viewport.h b/chromium/cc/layers/viewport.h index ac17140f513..55a64b7ee4e 100644 --- a/chromium/cc/layers/viewport.h +++ b/chromium/cc/layers/viewport.h @@ -21,6 +21,15 @@ struct ScrollNode; // outer viewport (layout) scroll layers. These layers have different scroll // bubbling behavior from the rest of the layer tree which is encoded in this // class. +// +// When performing any kind of scroll operations on either the inner or outer +// scroll node, they must be done using this class. Typically, the outer +// viewport's scroll node will be used in the scroll chain to represent a full +// viewport scroll (i.e. one that will use this class to scroll both inner and +// outer viewports, as appropriate). However, in some situations (see comments +// in LayerTreeHostImpl::GetNodeToScroll) we may wish to scroll only the inner +// viewport. In that case, the inner viewport is used in the scroll chain, but +// we should still scroll using this class. class CC_EXPORT Viewport { public: // If the pinch zoom anchor on the first PinchUpdate is within this length @@ -55,8 +64,6 @@ class CC_EXPORT Viewport { bool affect_browser_controls, bool scroll_outer_viewport); - bool CanScroll(const ScrollState& scroll_state) const; - // TODO(bokan): Callers can now be replaced by ScrollBy. void ScrollByInnerFirst(const gfx::Vector2dF& delta); @@ -71,12 +78,18 @@ class CC_EXPORT Viewport { void PinchEnd(const gfx::Point& anchor, bool snap_to_min); // Returns true if the given scroll node should be scrolled via this class, - // false if it should be scrolled directly. - bool ShouldScroll(const ScrollNode& scroll_node); - - // Returns the "representative" viewport scroll node. That is, the one that's - // set as the currently scrolling node when the viewport scrolls. - ScrollNode* MainScrollNode() const; + // false if it should be scrolled directly. Scrolling either the inner or + // outer viewport nodes must be done using this class. + bool ShouldScroll(const ScrollNode& scroll_node) const; + + // Returns true if the viewport can consume any of the delta for the given + // the |scroll_state|. This method takes a ScrollNode because viewport + // scrolling can occur for either the inner or outer scroll nodes. If it + // outer is used, we do a combined scroll that distributes the scroll among + // the inner and outer viewports. If the inner is used, only the inner + // viewport is scrolled. It is an error to pass any other node to this + // method. + bool CanScroll(const ScrollNode& node, const ScrollState& scroll_state) const; private: explicit Viewport(LayerTreeHostImpl* host_impl); diff --git a/chromium/cc/metrics/begin_main_frame_metrics.cc b/chromium/cc/metrics/begin_main_frame_metrics.cc index d4e83ead0c0..04b6d8bbf3d 100644 --- a/chromium/cc/metrics/begin_main_frame_metrics.cc +++ b/chromium/cc/metrics/begin_main_frame_metrics.cc @@ -8,4 +8,7 @@ namespace cc { BeginMainFrameMetrics::BeginMainFrameMetrics() = default; +BeginMainFrameMetrics::BeginMainFrameMetrics( + const BeginMainFrameMetrics& other) = default; + } // namespace cc diff --git a/chromium/cc/metrics/begin_main_frame_metrics.h b/chromium/cc/metrics/begin_main_frame_metrics.h index 2927360a849..bcd40714215 100644 --- a/chromium/cc/metrics/begin_main_frame_metrics.h +++ b/chromium/cc/metrics/begin_main_frame_metrics.h @@ -28,6 +28,8 @@ struct CC_EXPORT BeginMainFrameMetrics { base::TimeDelta update_layers; BeginMainFrameMetrics(); + + BeginMainFrameMetrics(const BeginMainFrameMetrics& other); }; } // namespace cc diff --git a/chromium/cc/metrics/compositor_frame_reporter.cc b/chromium/cc/metrics/compositor_frame_reporter.cc index cb494e657b7..e6586c87ce2 100644 --- a/chromium/cc/metrics/compositor_frame_reporter.cc +++ b/chromium/cc/metrics/compositor_frame_reporter.cc @@ -16,6 +16,7 @@ namespace cc { namespace { using StageType = CompositorFrameReporter::StageType; +using BlinkBreakdown = CompositorFrameReporter::BlinkBreakdown; using VizBreakdown = CompositorFrameReporter::VizBreakdown; constexpr int kMissedFrameReportTypeCount = @@ -23,7 +24,13 @@ constexpr int kMissedFrameReportTypeCount = kMissedFrameReportTypeCount); constexpr int kStageTypeCount = static_cast<int>(StageType::kStageTypeCount); constexpr int kAllBreakdownCount = - static_cast<int>(VizBreakdown::kBreakdownCount); + static_cast<int>(VizBreakdown::kBreakdownCount) + + static_cast<int>(BlinkBreakdown::kBreakdownCount); + +constexpr int kVizBreakdownInitialIndex = kStageTypeCount; +constexpr int kBlinkBreakdownInitialIndex = + kVizBreakdownInitialIndex + static_cast<int>(VizBreakdown::kBreakdownCount); + // For each possible FrameSequenceTrackerType there will be a UMA histogram // plus one for general case. constexpr int kFrameSequenceTrackerTypeCount = @@ -31,38 +38,74 @@ constexpr int kFrameSequenceTrackerTypeCount = // Names for CompositorFrameReporter::StageType, which should be updated in case // of changes to the enum. -constexpr const char* kStageNames[] = { - [static_cast<int>(StageType::kBeginImplFrameToSendBeginMainFrame)] = - "BeginImplFrameToSendBeginMainFrame", - [static_cast<int>(StageType::kSendBeginMainFrameToCommit)] = - "SendBeginMainFrameToCommit", - [static_cast<int>(StageType::kCommit)] = "Commit", - [static_cast<int>(StageType::kEndCommitToActivation)] = - "EndCommitToActivation", - [static_cast<int>(StageType::kActivation)] = "Activation", - [static_cast<int>(StageType::kEndActivateToSubmitCompositorFrame)] = - "EndActivateToSubmitCompositorFrame", - [static_cast<int>( - StageType::kSubmitCompositorFrameToPresentationCompositorFrame)] = - "SubmitCompositorFrameToPresentationCompositorFrame", - [static_cast<int>(StageType::kTotalLatency)] = "TotalLatency", - [static_cast<int>(VizBreakdown::kSubmitToReceiveCompositorFrame) + - kStageTypeCount] = - "SubmitCompositorFrameToPresentationCompositorFrame." - "SubmitToReceiveCompositorFrame", - [static_cast<int>(VizBreakdown::kReceivedCompositorFrameToStartDraw) + - kStageTypeCount] = - "SubmitCompositorFrameToPresentationCompositorFrame." - "ReceivedCompositorFrameToStartDraw", - [static_cast<int>(VizBreakdown::kStartDrawToSwapEnd) + kStageTypeCount] = - "SubmitCompositorFrameToPresentationCompositorFrame.StartDrawToSwapEnd", - [static_cast<int>(VizBreakdown::kSwapEndToPresentationCompositorFrame) + - kStageTypeCount] = - "SubmitCompositorFrameToPresentationCompositorFrame." - "SwapEndToPresentationCompositorFrame"}; -static_assert(sizeof(kStageNames) / sizeof(kStageNames[0]) == - kStageTypeCount + kAllBreakdownCount, - "Compositor latency stages has changed."); +constexpr const char* GetStageName(int stage_type_index) { + switch (stage_type_index) { + case static_cast<int>(StageType::kBeginImplFrameToSendBeginMainFrame): + return "BeginImplFrameToSendBeginMainFrame"; + case static_cast<int>(StageType::kSendBeginMainFrameToCommit): + return "SendBeginMainFrameToCommit"; + case static_cast<int>(StageType::kCommit): + return "Commit"; + case static_cast<int>(StageType::kEndCommitToActivation): + return "EndCommitToActivation"; + case static_cast<int>(StageType::kActivation): + return "Activation"; + case static_cast<int>(StageType::kEndActivateToSubmitCompositorFrame): + return "EndActivateToSubmitCompositorFrame"; + case static_cast<int>( + StageType::kSubmitCompositorFrameToPresentationCompositorFrame): + return "SubmitCompositorFrameToPresentationCompositorFrame"; + case static_cast<int>(StageType::kTotalLatency): + return "TotalLatency"; + case static_cast<int>(VizBreakdown::kSubmitToReceiveCompositorFrame) + + kVizBreakdownInitialIndex: + return "SubmitCompositorFrameToPresentationCompositorFrame." + "SubmitToReceiveCompositorFrame"; + case static_cast<int>(VizBreakdown::kReceivedCompositorFrameToStartDraw) + + kVizBreakdownInitialIndex: + return "SubmitCompositorFrameToPresentationCompositorFrame." + "ReceivedCompositorFrameToStartDraw"; + case static_cast<int>(VizBreakdown::kStartDrawToSwapEnd) + + kVizBreakdownInitialIndex: + return "SubmitCompositorFrameToPresentationCompositorFrame." + "StartDrawToSwapEnd"; + case static_cast<int>(VizBreakdown::kSwapEndToPresentationCompositorFrame) + + kVizBreakdownInitialIndex: + return "SubmitCompositorFrameToPresentationCompositorFrame." + "SwapEndToPresentationCompositorFrame"; + case static_cast<int>(BlinkBreakdown::kHandleInputEvents) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.HandleInputEvents"; + case static_cast<int>(BlinkBreakdown::kAnimate) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.Animate"; + case static_cast<int>(BlinkBreakdown::kStyleUpdate) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.StyleUpdate"; + case static_cast<int>(BlinkBreakdown::kLayoutUpdate) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.LayoutUpdate"; + case static_cast<int>(BlinkBreakdown::kPrepaint) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.Prepaint"; + case static_cast<int>(BlinkBreakdown::kComposite) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.Composite"; + case static_cast<int>(BlinkBreakdown::kPaint) + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.Paint"; + case static_cast<int>(BlinkBreakdown::kScrollingCoordinator) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.ScrollingCoordinator"; + case static_cast<int>(BlinkBreakdown::kCompositeCommit) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.CompositeCommit"; + case static_cast<int>(BlinkBreakdown::kUpdateLayers) + + kBlinkBreakdownInitialIndex: + return "SendBeginMainFrameToCommit.UpdateLayers"; + default: + return ""; + } +} // Names for CompositorFrameReporter::MissedFrameReportTypes, which should be // updated in case of changes to the enum. @@ -88,13 +131,14 @@ std::string HistogramName(const int report_type_index, const int stage_type_index) { DCHECK_LE(frame_sequence_tracker_type_index, FrameSequenceTrackerType::kMaxType); - const char* tracker_type_name = FrameSequenceTracker:: - kFrameSequenceTrackerTypeNames[frame_sequence_tracker_type_index]; + const char* tracker_type_name = + FrameSequenceTracker::GetFrameSequenceTrackerTypeName( + frame_sequence_tracker_type_index); DCHECK(tracker_type_name); return base::StrCat({"CompositorLatency.", kReportTypeNames[report_type_index], tracker_type_name, *tracker_type_name ? "." : "", - kStageNames[stage_type_index]}); + GetStageName(stage_type_index)}); } } // namespace @@ -129,8 +173,8 @@ void CompositorFrameReporter::StartStage( CHECK_LT(stage_type_index, static_cast<int>(StageType::kStageTypeCount)); CHECK_GE(stage_type_index, 0); TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( - "cc,benchmark", "PipelineReporter", this, - TRACE_STR_COPY(kStageNames[stage_type_index]), start_time); + "cc,benchmark", "PipelineReporter", this, GetStageName(stage_type_index), + start_time); } void CompositorFrameReporter::EndCurrentStage(base::TimeTicks end_time) { @@ -164,11 +208,19 @@ void CompositorFrameReporter::OnAbortBeginMainFrame() { did_abort_main_frame_ = false; } +void CompositorFrameReporter::SetBlinkBreakdown( + std::unique_ptr<BeginMainFrameMetrics> blink_breakdown) { + DCHECK(blink_breakdown_.paint.is_zero()); + if (blink_breakdown) + blink_breakdown_ = *blink_breakdown; + else + blink_breakdown_ = BeginMainFrameMetrics(); +} + void CompositorFrameReporter::SetVizBreakdown( const viz::FrameTimingDetails& viz_breakdown) { - DCHECK(current_stage_.viz_breakdown.received_compositor_frame_timestamp - .is_null()); - current_stage_.viz_breakdown = viz_breakdown; + DCHECK(viz_breakdown_.received_compositor_frame_timestamp.is_null()); + viz_breakdown_ = viz_breakdown; } void CompositorFrameReporter::TerminateReporter() { @@ -205,9 +257,8 @@ void CompositorFrameReporter::TerminateReporter() { submitted_frame_missed_deadline_ ? "missed_frame" : "non_missed_frame"; TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP2( "cc,benchmark", "PipelineReporter", this, frame_termination_time_, - "termination_status", TRACE_STR_COPY(termination_status_str), - "compositor_frame_submission_status", - TRACE_STR_COPY(submission_status_str)); + "termination_status", termination_status_str, + "compositor_frame_submission_status", submission_status_str); // Only report histograms if the frame was presented. if (report_latency) { @@ -226,27 +277,31 @@ void CompositorFrameReporter::ReportStageHistograms(bool missed_frame) const { : CompositorFrameReporter::MissedFrameReportTypes::kNonMissedFrame; for (const StageData& stage : stage_history_) { - ReportStageHistogramWithBreakdown( - report_type, FrameSequenceTrackerType::kMaxType, stage); + ReportStageHistogramWithBreakdown(report_type, stage); for (const auto& frame_sequence_tracker_type : *active_trackers_) { // Report stage breakdowns. - ReportStageHistogramWithBreakdown(report_type, - frame_sequence_tracker_type, stage); + ReportStageHistogramWithBreakdown(report_type, stage, + frame_sequence_tracker_type); } } } void CompositorFrameReporter::ReportStageHistogramWithBreakdown( CompositorFrameReporter::MissedFrameReportTypes report_type, - FrameSequenceTrackerType frame_sequence_tracker_type, - CompositorFrameReporter::StageData stage) const { + const CompositorFrameReporter::StageData& stage, + FrameSequenceTrackerType frame_sequence_tracker_type) const { base::TimeDelta stage_delta = stage.end_time - stage.start_time; ReportHistogram(report_type, frame_sequence_tracker_type, static_cast<int>(stage.stage_type), stage_delta); switch (stage.stage_type) { + case StageType::kSendBeginMainFrameToCommit: { + ReportBlinkBreakdowns(report_type, frame_sequence_tracker_type); + break; + } case StageType::kSubmitCompositorFrameToPresentationCompositorFrame: { - ReportVizBreakdown(report_type, frame_sequence_tracker_type, stage); + ReportVizBreakdowns(report_type, stage.start_time, + frame_sequence_tracker_type); break; } default: @@ -254,43 +309,76 @@ void CompositorFrameReporter::ReportStageHistogramWithBreakdown( } } -void CompositorFrameReporter::ReportVizBreakdown( +void CompositorFrameReporter::ReportBlinkBreakdowns( CompositorFrameReporter::MissedFrameReportTypes report_type, - FrameSequenceTrackerType frame_sequence_tracker_type, - CompositorFrameReporter::StageData stage) const { + FrameSequenceTrackerType frame_sequence_tracker_type) const { + std::vector<std::pair<BlinkBreakdown, base::TimeDelta>> breakdowns = { + {BlinkBreakdown::kHandleInputEvents, + blink_breakdown_.handle_input_events}, + {BlinkBreakdown::kAnimate, blink_breakdown_.animate}, + {BlinkBreakdown::kStyleUpdate, blink_breakdown_.style_update}, + {BlinkBreakdown::kLayoutUpdate, blink_breakdown_.layout_update}, + {BlinkBreakdown::kPrepaint, blink_breakdown_.prepaint}, + {BlinkBreakdown::kComposite, blink_breakdown_.composite}, + {BlinkBreakdown::kPaint, blink_breakdown_.paint}, + {BlinkBreakdown::kScrollingCoordinator, + blink_breakdown_.scrolling_coordinator}, + {BlinkBreakdown::kCompositeCommit, blink_breakdown_.composite_commit}, + {BlinkBreakdown::kUpdateLayers, blink_breakdown_.update_layers}}; + + for (const auto& pair : breakdowns) { + ReportHistogram(report_type, frame_sequence_tracker_type, + kBlinkBreakdownInitialIndex + static_cast<int>(pair.first), + pair.second); + } +} + +void CompositorFrameReporter::ReportVizBreakdowns( + CompositorFrameReporter::MissedFrameReportTypes report_type, + base::TimeTicks start_time, + FrameSequenceTrackerType frame_sequence_tracker_type) const { // Check if viz_breakdown is set. - if (stage.viz_breakdown.received_compositor_frame_timestamp.is_null()) + if (viz_breakdown_.received_compositor_frame_timestamp.is_null()) return; - - int index_origin = static_cast<int>(StageType::kStageTypeCount); base::TimeDelta submit_to_receive_compositor_frame_delta = - stage.viz_breakdown.received_compositor_frame_timestamp - - stage.start_time; - ReportHistogram(report_type, frame_sequence_tracker_type, index_origin, - submit_to_receive_compositor_frame_delta); - - if (stage.viz_breakdown.draw_start_timestamp.is_null()) + viz_breakdown_.received_compositor_frame_timestamp - start_time; + ReportHistogram( + report_type, frame_sequence_tracker_type, + kVizBreakdownInitialIndex + + static_cast<int>(VizBreakdown::kSubmitToReceiveCompositorFrame), + submit_to_receive_compositor_frame_delta); + + if (viz_breakdown_.draw_start_timestamp.is_null()) return; base::TimeDelta received_compositor_frame_to_start_draw_delta = - stage.viz_breakdown.draw_start_timestamp - - stage.viz_breakdown.received_compositor_frame_timestamp; - ReportHistogram(report_type, frame_sequence_tracker_type, index_origin + 1, - received_compositor_frame_to_start_draw_delta); - - if (stage.viz_breakdown.swap_timings.is_null()) + viz_breakdown_.draw_start_timestamp - + viz_breakdown_.received_compositor_frame_timestamp; + ReportHistogram( + report_type, frame_sequence_tracker_type, + kVizBreakdownInitialIndex + + static_cast<int>(VizBreakdown::kReceivedCompositorFrameToStartDraw), + received_compositor_frame_to_start_draw_delta); + + if (viz_breakdown_.swap_timings.is_null()) return; base::TimeDelta start_draw_to_swap_end_delta = - stage.viz_breakdown.swap_timings.swap_end - - stage.viz_breakdown.draw_start_timestamp; + viz_breakdown_.swap_timings.swap_end - + viz_breakdown_.draw_start_timestamp; - ReportHistogram(report_type, frame_sequence_tracker_type, index_origin + 2, + ReportHistogram(report_type, frame_sequence_tracker_type, + kVizBreakdownInitialIndex + + static_cast<int>(VizBreakdown::kStartDrawToSwapEnd), start_draw_to_swap_end_delta); base::TimeDelta swap_end_to_presentation_compositor_frame_delta = - stage.end_time - stage.viz_breakdown.swap_timings.swap_end; - - ReportHistogram(report_type, frame_sequence_tracker_type, index_origin + 3, - swap_end_to_presentation_compositor_frame_delta); + viz_breakdown_.presentation_feedback.timestamp - + viz_breakdown_.swap_timings.swap_end; + + ReportHistogram( + report_type, frame_sequence_tracker_type, + kVizBreakdownInitialIndex + + static_cast<int>(VizBreakdown::kSwapEndToPresentationCompositorFrame), + swap_end_to_presentation_compositor_frame_delta); } void CompositorFrameReporter::ReportHistogram( diff --git a/chromium/cc/metrics/compositor_frame_reporter.h b/chromium/cc/metrics/compositor_frame_reporter.h index 79cbd089e46..d938249e58a 100644 --- a/chromium/cc/metrics/compositor_frame_reporter.h +++ b/chromium/cc/metrics/compositor_frame_reporter.h @@ -11,6 +11,7 @@ #include "base/time/time.h" #include "cc/base/base_export.h" #include "cc/cc_export.h" +#include "cc/metrics/begin_main_frame_metrics.h" #include "cc/metrics/frame_sequence_tracker.h" #include "components/viz/common/frame_timing_details.h" @@ -91,6 +92,20 @@ class CC_EXPORT CompositorFrameReporter { kBreakdownCount }; + enum class BlinkBreakdown { + kHandleInputEvents = 0, + kAnimate = 1, + kStyleUpdate = 2, + kLayoutUpdate = 3, + kPrepaint = 4, + kComposite = 5, + kPaint = 6, + kScrollingCoordinator = 7, + kCompositeCommit = 8, + kUpdateLayers = 9, + kBreakdownCount + }; + CompositorFrameReporter( const base::flat_set<FrameSequenceTrackerType>* active_trackers, bool is_single_threaded = false); @@ -107,6 +122,8 @@ class CC_EXPORT CompositorFrameReporter { void StartStage(StageType stage_type, base::TimeTicks start_time); void TerminateFrame(FrameTerminationStatus termination_status, base::TimeTicks termination_time); + void SetBlinkBreakdown( + std::unique_ptr<BeginMainFrameMetrics> blink_breakdown); void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown); int StageHistorySizeForTesting() { return stage_history_.size(); } @@ -119,12 +136,11 @@ class CC_EXPORT CompositorFrameReporter { return impl_frame_finish_time_; } - protected: + private: struct StageData { StageType stage_type; base::TimeTicks start_time; base::TimeTicks end_time; - viz::FrameTimingDetails viz_breakdown; StageData(); StageData(StageType stage_type, base::TimeTicks start_time, @@ -133,31 +149,35 @@ class CC_EXPORT CompositorFrameReporter { ~StageData(); }; + void TerminateReporter(); + void EndCurrentStage(base::TimeTicks end_time); + void ReportStageHistograms(bool missed_frame) const; + void ReportStageHistogramWithBreakdown( + MissedFrameReportTypes report_type, + const StageData& stage, + FrameSequenceTrackerType frame_sequence_tracker_type = + FrameSequenceTrackerType::kMaxType) const; + void ReportBlinkBreakdowns( + MissedFrameReportTypes report_type, + FrameSequenceTrackerType frame_sequence_tracker_type) const; + void ReportVizBreakdowns( + MissedFrameReportTypes report_type, + const base::TimeTicks start_time, + FrameSequenceTrackerType frame_sequence_tracker_type) const; + void ReportHistogram(MissedFrameReportTypes report_type, + FrameSequenceTrackerType intraction_type, + const int stage_type_index, + base::TimeDelta time_delta) const; + StageData current_stage_; + BeginMainFrameMetrics blink_breakdown_; + viz::FrameTimingDetails viz_breakdown_; // Stage data is recorded here. On destruction these stages will be reported // to UMA if the termination status is |kPresentedFrame|. Reported data will // be divided based on the frame submission status. std::vector<StageData> stage_history_; - private: - void TerminateReporter(); - void EndCurrentStage(base::TimeTicks end_time); - void ReportStageHistograms(bool missed_frame) const; - void ReportStageHistogramWithBreakdown( - CompositorFrameReporter::MissedFrameReportTypes report_type, - FrameSequenceTrackerType frame_sequence_tracker_type, - CompositorFrameReporter::StageData stage) const; - void ReportVizBreakdown( - CompositorFrameReporter::MissedFrameReportTypes report_type, - FrameSequenceTrackerType frame_sequence_tracker_type, - CompositorFrameReporter::StageData stage) const; - void ReportHistogram( - CompositorFrameReporter::MissedFrameReportTypes report_type, - FrameSequenceTrackerType intraction_type, - const int stage_type_index, - base::TimeDelta time_delta) const; - // Returns true if the stage duration is greater than |kAbnormalityPercentile| // of its RollingTimeDeltaHistory. base::TimeDelta GetStateNormalUpperLimit(const StageData& stage) const; diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.cc b/chromium/cc/metrics/compositor_frame_reporting_controller.cc index 760207b87f0..13a575ff211 100644 --- a/chromium/cc/metrics/compositor_frame_reporting_controller.cc +++ b/chromium/cc/metrics/compositor_frame_reporting_controller.cc @@ -52,8 +52,10 @@ base::TimeTicks CompositorFrameReportingController::Now() const { void CompositorFrameReportingController::WillBeginImplFrame() { base::TimeTicks begin_time = Now(); if (reporters_[PipelineStage::kBeginImplFrame]) { + // If the the reporter is replaced in this stage, it means that Impl frame + // caused no damage. reporters_[PipelineStage::kBeginImplFrame]->TerminateFrame( - CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter, + CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame, begin_time); } std::unique_ptr<CompositorFrameReporter> reporter = @@ -207,6 +209,13 @@ void CompositorFrameReportingController::DidPresentCompositorFrame( } } +void CompositorFrameReportingController::SetBlinkBreakdown( + std::unique_ptr<BeginMainFrameMetrics> details) { + DCHECK(reporters_[PipelineStage::kBeginMainFrame]); + reporters_[PipelineStage::kBeginMainFrame]->SetBlinkBreakdown( + std::move(details)); +} + void CompositorFrameReportingController::AddActiveTracker( FrameSequenceTrackerType type) { active_trackers_.insert(type); diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.h b/chromium/cc/metrics/compositor_frame_reporting_controller.h index 80254c1dc64..eda48867076 100644 --- a/chromium/cc/metrics/compositor_frame_reporting_controller.h +++ b/chromium/cc/metrics/compositor_frame_reporting_controller.h @@ -20,6 +20,7 @@ struct FrameTimingDetails; } namespace cc { +struct BeginMainFrameMetrics; class RollingTimeDeltaHistory; // This is used for managing simultaneous CompositorFrameReporter instances @@ -62,6 +63,8 @@ class CC_EXPORT CompositorFrameReportingController { uint32_t frame_token, const viz::FrameTimingDetails& details); + void SetBlinkBreakdown(std::unique_ptr<BeginMainFrameMetrics> details); + virtual void AddActiveTracker(FrameSequenceTrackerType type); virtual void RemoveActiveTracker(FrameSequenceTrackerType type); diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc index 6fd89c4a30a..7d4884c1e49 100644 --- a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc +++ b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc @@ -61,13 +61,14 @@ class CompositorFrameReportingControllerTest : public testing::Test { reporting_controller_.WillBeginMainFrame(); } - void SimulateCommit() { + void SimulateCommit(std::unique_ptr<BeginMainFrameMetrics> blink_breakdown) { if (!reporting_controller_.reporters()[CompositorFrameReportingController:: PipelineStage::kBeginMainFrame]) SimulateBeginMainFrame(); CHECK( reporting_controller_.reporters()[CompositorFrameReportingController:: PipelineStage::kBeginMainFrame]); + reporting_controller_.SetBlinkBreakdown(std::move(blink_breakdown)); reporting_controller_.WillCommit(); reporting_controller_.DidCommit(); } @@ -75,7 +76,7 @@ class CompositorFrameReportingControllerTest : public testing::Test { void SimulateActivate() { if (!reporting_controller_.reporters() [CompositorFrameReportingController::PipelineStage::kCommit]) - SimulateCommit(); + SimulateCommit(nullptr); CHECK(reporting_controller_.reporters() [CompositorFrameReportingController::PipelineStage::kCommit]); reporting_controller_.WillActivate(); @@ -155,7 +156,7 @@ TEST_F(CompositorFrameReportingControllerTest, ActiveReporterCounts) { // 4 simultaneous reporters active. SimulateActivate(); - SimulateCommit(); + SimulateCommit(nullptr); SimulateBeginMainFrame(); @@ -173,7 +174,7 @@ TEST_F(CompositorFrameReportingControllerTest, // 2 reporters active. SimulateActivate(); - SimulateCommit(); + SimulateCommit(nullptr); // Submitting and Presenting the next reporter which will be a normal frame. SimulatePresentCompositorFrame(); @@ -202,7 +203,7 @@ TEST_F(CompositorFrameReportingControllerTest, // Submitting the next reporter will be replaced as a result of a new commit. // And this will be reported for all stage before activate as a missed frame. - SimulateCommit(); + SimulateCommit(nullptr); // Non Missed frame histogram counts should not change. histogram_tester.ExpectTotalCount( "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 1); @@ -228,5 +229,69 @@ TEST_F(CompositorFrameReportingControllerTest, histogram_tester.ExpectTotalCount( "CompositorLatency.MissedFrame.EndActivateToSubmitCompositorFrame", 0); } + +TEST_F(CompositorFrameReportingControllerTest, ImplFrameCausedNoDamage) { + base::HistogramTester histogram_tester; + + SimulateBeginImplFrame(); + SimulateBeginImplFrame(); + histogram_tester.ExpectTotalCount( + "CompositorLatency.MissedFrame.BeginImplFrameToSendBeginMainFrame", 0); +} + +TEST_F(CompositorFrameReportingControllerTest, BlinkBreakdown) { + base::HistogramTester histogram_tester; + + std::unique_ptr<BeginMainFrameMetrics> blink_breakdown = + std::make_unique<BeginMainFrameMetrics>(); + blink_breakdown->handle_input_events = base::TimeDelta::FromMicroseconds(10); + blink_breakdown->animate = base::TimeDelta::FromMicroseconds(9); + blink_breakdown->style_update = base::TimeDelta::FromMicroseconds(8); + blink_breakdown->layout_update = base::TimeDelta::FromMicroseconds(7); + blink_breakdown->prepaint = base::TimeDelta::FromMicroseconds(6); + blink_breakdown->composite = base::TimeDelta::FromMicroseconds(5); + blink_breakdown->paint = base::TimeDelta::FromMicroseconds(4); + blink_breakdown->scrolling_coordinator = base::TimeDelta::FromMicroseconds(3); + blink_breakdown->composite_commit = base::TimeDelta::FromMicroseconds(2); + blink_breakdown->update_layers = base::TimeDelta::FromMicroseconds(1); + + SimulateActivate(); + SimulateCommit(std::move(blink_breakdown)); + SimulatePresentCompositorFrame(); + + histogram_tester.ExpectTotalCount( + "CompositorLatency.SendBeginMainFrameToCommit", 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.HandleInputEvents", + base::TimeDelta::FromMicroseconds(10).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.Animate", + base::TimeDelta::FromMicroseconds(9).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.StyleUpdate", + base::TimeDelta::FromMicroseconds(8).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.LayoutUpdate", + base::TimeDelta::FromMicroseconds(7).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.Prepaint", + base::TimeDelta::FromMicroseconds(6).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.Composite", + base::TimeDelta::FromMicroseconds(5).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.Paint", + base::TimeDelta::FromMicroseconds(4).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.ScrollingCoordinator", + base::TimeDelta::FromMicroseconds(3).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.CompositeCommit", + base::TimeDelta::FromMicroseconds(2).InMilliseconds(), 1); + histogram_tester.ExpectUniqueSample( + "CompositorLatency.SendBeginMainFrameToCommit.UpdateLayers", + base::TimeDelta::FromMicroseconds(1).InMilliseconds(), 1); +} + } // namespace } // namespace cc diff --git a/chromium/cc/metrics/compositor_timing_history.cc b/chromium/cc/metrics/compositor_timing_history.cc index d244237b7e9..d2bf9e2c354 100644 --- a/chromium/cc/metrics/compositor_timing_history.cc +++ b/chromium/cc/metrics/compositor_timing_history.cc @@ -13,6 +13,7 @@ #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 { @@ -593,25 +594,21 @@ CompositorTimingHistory::CreateUMAReporter(UMACategory category) { return base::WrapUnique<CompositorTimingHistory::UMAReporter>(nullptr); } -void CompositorTimingHistory::AsValueInto( - base::trace_event::TracedValue* state) const { - state->SetDouble( - "begin_main_frame_queue_critical_estimate_ms", - BeginMainFrameQueueDurationCriticalEstimate().InMillisecondsF()); - state->SetDouble( - "begin_main_frame_queue_not_critical_estimate_ms", - BeginMainFrameQueueDurationNotCriticalEstimate().InMillisecondsF()); - state->SetDouble( - "begin_main_frame_start_to_ready_to_commit_estimate_ms", - BeginMainFrameStartToReadyToCommitDurationEstimate().InMillisecondsF()); - state->SetDouble("commit_to_ready_to_activate_estimate_ms", - CommitToReadyToActivateDurationEstimate().InMillisecondsF()); - state->SetDouble("prepare_tiles_estimate_ms", - PrepareTilesDurationEstimate().InMillisecondsF()); - state->SetDouble("activate_estimate_ms", - ActivateDurationEstimate().InMillisecondsF()); - state->SetDouble("draw_estimate_ms", - DrawDurationEstimate().InMillisecondsF()); +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 { @@ -776,8 +773,10 @@ void CompositorTimingHistory::BeginMainFrameAborted() { begin_main_frame_frame_time_ = base::TimeTicks(); } -void CompositorTimingHistory::NotifyReadyToCommit() { +void CompositorTimingHistory::NotifyReadyToCommit( + std::unique_ptr<BeginMainFrameMetrics> details) { DCHECK_NE(begin_main_frame_start_time_, base::TimeTicks()); + compositor_frame_reporting_controller_->SetBlinkBreakdown(std::move(details)); begin_main_frame_start_to_ready_to_commit_duration_history_.InsertSample( Now() - begin_main_frame_start_time_); } diff --git a/chromium/cc/metrics/compositor_timing_history.h b/chromium/cc/metrics/compositor_timing_history.h index c39f69ad071..57b8c115f86 100644 --- a/chromium/cc/metrics/compositor_timing_history.h +++ b/chromium/cc/metrics/compositor_timing_history.h @@ -12,18 +12,20 @@ #include "cc/tiles/tile_priority.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" -namespace base { -namespace trace_event { -class TracedValue; -} // namespace trace_event -} // namespace base +namespace perfetto { +namespace protos { +namespace pbzero { +class CompositorTimingHistory; +} +} // namespace protos +} // namespace perfetto namespace viz { struct FrameTimingDetails; } namespace cc { - +struct BeginMainFrameMetrics; class CompositorFrameReportingController; class RenderingStatsInstrumentation; @@ -47,7 +49,8 @@ class CC_EXPORT CompositorTimingHistory { CompositorTimingHistory& operator=(const CompositorTimingHistory&) = delete; - void AsValueInto(base::trace_event::TracedValue* state) const; + 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. @@ -76,7 +79,7 @@ class CC_EXPORT CompositorTimingHistory { base::TimeTicks main_frame_time); void BeginMainFrameStarted(base::TimeTicks main_thread_start_time); void BeginMainFrameAborted(); - void NotifyReadyToCommit(); + void NotifyReadyToCommit(std::unique_ptr<BeginMainFrameMetrics> details); void WillCommit(); void DidCommit(); void WillPrepareTiles(); diff --git a/chromium/cc/metrics/compositor_timing_history_unittest.cc b/chromium/cc/metrics/compositor_timing_history_unittest.cc index 81f72e61733..695217c62df 100644 --- a/chromium/cc/metrics/compositor_timing_history_unittest.cc +++ b/chromium/cc/metrics/compositor_timing_history_unittest.cc @@ -122,7 +122,7 @@ TEST_F(CompositorTimingHistoryTest, AllSequential_Commit) { AdvanceNowBy(begin_main_frame_queue_duration); timing_history_.BeginMainFrameStarted(Now()); AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration); - timing_history_.NotifyReadyToCommit(); + timing_history_.NotifyReadyToCommit(nullptr); timing_history_.WillCommit(); AdvanceNowBy(commit_duration); timing_history_.DidCommit(); diff --git a/chromium/cc/metrics/frame_sequence_metrics_unittest.cc b/chromium/cc/metrics/frame_sequence_metrics_unittest.cc new file mode 100644 index 00000000000..a41eb1cdf43 --- /dev/null +++ b/chromium/cc/metrics/frame_sequence_metrics_unittest.cc @@ -0,0 +1,75 @@ +// Copyright 2019 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. + +#include "cc/metrics/frame_sequence_tracker.h" + +#include "base/macros.h" +#include "base/test/metrics/histogram_tester.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { + +TEST(FrameSequenceMetricsTest, MergeMetrics) { + // Create a metric with only a small number of frames. It shouldn't report any + // metrics. + FrameSequenceMetrics first(FrameSequenceTrackerType::kTouchScroll, nullptr, + nullptr); + first.impl_throughput().frames_expected = 20; + first.impl_throughput().frames_produced = 10; + EXPECT_FALSE(first.HasEnoughDataForReporting()); + + // Create a second metric with too few frames to report any metrics. + auto second = std::make_unique<FrameSequenceMetrics>( + FrameSequenceTrackerType::kTouchScroll, nullptr, nullptr); + second->impl_throughput().frames_expected = 90; + second->impl_throughput().frames_produced = 60; + EXPECT_FALSE(second->HasEnoughDataForReporting()); + + // Merge the two metrics. The result should have enough frames to report + // metrics. + first.Merge(std::move(second)); + EXPECT_TRUE(first.HasEnoughDataForReporting()); +} + +TEST(FrameSequenceMetricsTest, AllMetricsReported) { + base::HistogramTester histograms; + + // Create a metric with enough frames on impl to be reported, but not enough + // on main. + FrameSequenceMetrics first(FrameSequenceTrackerType::kTouchScroll, nullptr, + nullptr); + first.impl_throughput().frames_expected = 120; + first.impl_throughput().frames_produced = 80; + first.main_throughput().frames_expected = 20; + first.main_throughput().frames_produced = 10; + EXPECT_TRUE(first.HasEnoughDataForReporting()); + first.ReportMetrics(); + + // The compositor-thread metric should be reported, but not the main-thread + // metric. + histograms.ExpectTotalCount( + "Graphics.Smoothness.Throughput.CompositorThread.TouchScroll", 1u); + histograms.ExpectTotalCount( + "Graphics.Smoothness.Throughput.MainThread.TouchScroll", 0u); + + // There should still be data left over for the main-thread. + EXPECT_TRUE(first.HasDataLeftForReporting()); + + auto second = std::make_unique<FrameSequenceMetrics>( + FrameSequenceTrackerType::kTouchScroll, nullptr, nullptr); + second->impl_throughput().frames_expected = 110; + second->impl_throughput().frames_produced = 100; + second->main_throughput().frames_expected = 90; + first.Merge(std::move(second)); + EXPECT_TRUE(first.HasEnoughDataForReporting()); + first.ReportMetrics(); + histograms.ExpectTotalCount( + "Graphics.Smoothness.Throughput.CompositorThread.TouchScroll", 2u); + histograms.ExpectTotalCount( + "Graphics.Smoothness.Throughput.MainThread.TouchScroll", 1u); + // All the metrics have now been reported. No data should be left over. + EXPECT_FALSE(first.HasDataLeftForReporting()); +} + +} // namespace cc diff --git a/chromium/cc/metrics/frame_sequence_tracker.cc b/chromium/cc/metrics/frame_sequence_tracker.cc index 5ba4bf9f95b..5d8cfab6e99 100644 --- a/chromium/cc/metrics/frame_sequence_tracker.cc +++ b/chromium/cc/metrics/frame_sequence_tracker.cc @@ -11,70 +11,200 @@ #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "cc/metrics/compositor_frame_reporting_controller.h" +#include "cc/metrics/throughput_ukm_reporter.h" +#include "cc/trees/ukm_manager.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/quads/compositor_frame_metadata.h" #include "ui/gfx/presentation_feedback.h" +// This macro is used with DCHECK to provide addition debug info. +#if DCHECK_IS_ON() +#define TRACKER_TRACE_STREAM frame_sequence_trace_ +#define TRACKER_DCHECK_MSG \ + " in " << GetFrameSequenceTrackerTypeName(static_cast<int>(this->type_)) \ + << " tracker: " << frame_sequence_trace_.str() << " (" \ + << frame_sequence_trace_.str().size() << ")"; +#else +#define TRACKER_TRACE_STREAM EAT_STREAM_PARAMETERS +#define TRACKER_DCHECK_MSG "" +#endif + namespace cc { -constexpr const char* FrameSequenceTracker::kFrameSequenceTrackerTypeNames[] = { - [FrameSequenceTrackerType::kCompositorAnimation] = "CompositorAnimation", - [FrameSequenceTrackerType::kMainThreadAnimation] = "MainThreadAnimation", - [FrameSequenceTrackerType::kPinchZoom] = "PinchZoom", - [FrameSequenceTrackerType::kRAF] = "RAF", - [FrameSequenceTrackerType::kTouchScroll] = "TouchScroll", - [FrameSequenceTrackerType::kUniversal] = "Universal", - [FrameSequenceTrackerType::kVideo] = "Video", - [FrameSequenceTrackerType::kWheelScroll] = "WheelScroll", - [FrameSequenceTrackerType::kMaxType] = "", -}; +const char* FrameSequenceTracker::GetFrameSequenceTrackerTypeName( + int type_index) { + switch (type_index) { + case static_cast<int>(FrameSequenceTrackerType::kCompositorAnimation): + return "CompositorAnimation"; + case static_cast<int>(FrameSequenceTrackerType::kMainThreadAnimation): + return "MainThreadAnimation"; + case static_cast<int>(FrameSequenceTrackerType::kPinchZoom): + return "PinchZoom"; + case static_cast<int>(FrameSequenceTrackerType::kRAF): + return "RAF"; + case static_cast<int>(FrameSequenceTrackerType::kTouchScroll): + return "TouchScroll"; + case static_cast<int>(FrameSequenceTrackerType::kUniversal): + return "Universal"; + case static_cast<int>(FrameSequenceTrackerType::kVideo): + return "Video"; + case static_cast<int>(FrameSequenceTrackerType::kWheelScroll): + return "WheelScroll"; + default: + return ""; + } +} namespace { -// Avoid reporting any throughput metric for sequences that had a small amount -// of frames. -constexpr int kMinFramesForThroughputMetric = 4; - -enum class ThreadType { - kMain, - kCompositor, - kSlower, -}; +// Avoid reporting any throughput metric for sequences that do not have a +// sufficient number of frames. +constexpr int kMinFramesForThroughputMetric = 100; -constexpr int kBuiltinSequenceNum = - base::size(FrameSequenceTracker::kFrameSequenceTrackerTypeNames); +constexpr int kBuiltinSequenceNum = FrameSequenceTrackerType::kMaxType + 1; constexpr int kMaximumHistogramIndex = 3 * kBuiltinSequenceNum; -int GetIndexForMetric(ThreadType thread_type, FrameSequenceTrackerType type) { - if (thread_type == ThreadType::kMain) +int GetIndexForMetric(FrameSequenceTracker::ThreadType thread_type, + FrameSequenceTrackerType type) { + if (thread_type == FrameSequenceTracker::ThreadType::kMain) return static_cast<int>(type); - if (thread_type == ThreadType::kCompositor) + if (thread_type == FrameSequenceTracker::ThreadType::kCompositor) return static_cast<int>(type + kBuiltinSequenceNum); return static_cast<int>(type + 2 * kBuiltinSequenceNum); } std::string GetCheckerboardingHistogramName(FrameSequenceTrackerType type) { - return base::StrCat( - {"Graphics.Smoothness.Checkerboarding.", - FrameSequenceTracker::kFrameSequenceTrackerTypeNames[type]}); + return base::StrCat({"Graphics.Smoothness.Checkerboarding.", + FrameSequenceTracker::GetFrameSequenceTrackerTypeName( + static_cast<int>(type))}); } std::string GetThroughputHistogramName(FrameSequenceTrackerType type, const char* thread_name) { - return base::StrCat( - {"Graphics.Smoothness.Throughput.", thread_name, ".", - FrameSequenceTracker::kFrameSequenceTrackerTypeNames[type]}); + return base::StrCat({"Graphics.Smoothness.Throughput.", thread_name, ".", + FrameSequenceTracker::GetFrameSequenceTrackerTypeName( + static_cast<int>(type))}); } std::string GetFrameSequenceLengthHistogramName(FrameSequenceTrackerType type) { - return base::StrCat( - {"Graphics.Smoothness.FrameSequenceLength.", - FrameSequenceTracker::kFrameSequenceTrackerTypeNames[type]}); + return base::StrCat({"Graphics.Smoothness.FrameSequenceLength.", + FrameSequenceTracker::GetFrameSequenceTrackerTypeName( + static_cast<int>(type))}); } } // namespace //////////////////////////////////////////////////////////////////////////////// +// FrameSequenceMetrics + +FrameSequenceMetrics::FrameSequenceMetrics(FrameSequenceTrackerType type, + UkmManager* ukm_manager, + ThroughputUkmReporter* ukm_reporter) + : type_(type), + ukm_manager_(ukm_manager), + throughput_ukm_reporter_(ukm_reporter) { + TRACE_EVENT_ASYNC_BEGIN1( + "cc,benchmark", "FrameSequenceTracker", this, "name", + FrameSequenceTracker::GetFrameSequenceTrackerTypeName( + static_cast<int>(type_))); +} + +FrameSequenceMetrics::~FrameSequenceMetrics() { + if (HasDataLeftForReporting()) + ReportMetrics(); +} + +void FrameSequenceMetrics::Merge( + std::unique_ptr<FrameSequenceMetrics> metrics) { + DCHECK_EQ(type_, metrics->type_); + impl_throughput_.Merge(metrics->impl_throughput_); + main_throughput_.Merge(metrics->main_throughput_); + frames_checkerboarded_ += metrics->frames_checkerboarded_; + + // Reset the state of |metrics| before destroying it, so that it doesn't end + // up reporting the metrics. + metrics->impl_throughput_ = {}; + metrics->main_throughput_ = {}; + metrics->frames_checkerboarded_ = 0; +} + +bool FrameSequenceMetrics::HasEnoughDataForReporting() const { + return impl_throughput_.frames_expected >= kMinFramesForThroughputMetric || + main_throughput_.frames_expected >= kMinFramesForThroughputMetric; +} + +bool FrameSequenceMetrics::HasDataLeftForReporting() const { + return impl_throughput_.frames_expected > 0 || + main_throughput_.frames_expected > 0; +} + +void FrameSequenceMetrics::ReportMetrics() { + DCHECK_LE(impl_throughput_.frames_produced, impl_throughput_.frames_expected); + DCHECK_LE(main_throughput_.frames_produced, main_throughput_.frames_expected); + TRACE_EVENT_ASYNC_END2( + "cc,benchmark", "FrameSequenceTracker", this, "args", + ThroughputData::ToTracedValue(impl_throughput_, main_throughput_), + "checkerboard", frames_checkerboarded_); + + // Report the throughput metrics. + base::Optional<int> impl_throughput_percent = ThroughputData::ReportHistogram( + type_, "CompositorThread", + GetIndexForMetric(FrameSequenceTracker::ThreadType::kCompositor, type_), + impl_throughput_); + base::Optional<int> main_throughput_percent = ThroughputData::ReportHistogram( + type_, "MainThread", + GetIndexForMetric(FrameSequenceTracker::ThreadType::kMain, type_), + main_throughput_); + + base::Optional<ThroughputData> slower_throughput; + base::Optional<int> slower_throughput_percent; + if (impl_throughput_percent && + (!main_throughput_percent || + impl_throughput_percent.value() <= main_throughput_percent.value())) { + slower_throughput = impl_throughput_; + } + if (main_throughput_percent && + (!impl_throughput_percent || + main_throughput_percent.value() < impl_throughput_percent.value())) { + slower_throughput = main_throughput_; + } + if (slower_throughput.has_value()) { + slower_throughput_percent = ThroughputData::ReportHistogram( + type_, "SlowerThread", + GetIndexForMetric(FrameSequenceTracker::ThreadType::kSlower, type_), + slower_throughput.value()); + DCHECK(slower_throughput_percent.has_value()); + } + + // slower_throughput has value indicates that we have reported UMA. + if (slower_throughput.has_value() && ukm_manager_ && + throughput_ukm_reporter_) { + throughput_ukm_reporter_->ReportThroughputUkm( + ukm_manager_, slower_throughput_percent, impl_throughput_percent, + main_throughput_percent, type_); + } + + // Report the checkerboarding metrics. + if (impl_throughput_.frames_expected >= kMinFramesForThroughputMetric) { + const int checkerboarding_percent = static_cast<int>( + 100 * frames_checkerboarded_ / impl_throughput_.frames_expected); + STATIC_HISTOGRAM_POINTER_GROUP( + GetCheckerboardingHistogramName(type_), type_, + FrameSequenceTrackerType::kMaxType, Add(checkerboarding_percent), + base::LinearHistogram::FactoryGet( + GetCheckerboardingHistogramName(type_), 1, 100, 101, + base::HistogramBase::kUmaTargetedHistogramFlag)); + frames_checkerboarded_ = 0; + } + + // Reset the metrics that have already been reported. + if (impl_throughput_percent.has_value()) + impl_throughput_ = {}; + if (main_throughput_percent.has_value()) + main_throughput_ = {}; +} + +//////////////////////////////////////////////////////////////////////////////// // FrameSequenceTrackerCollection FrameSequenceTrackerCollection::FrameSequenceTrackerCollection( @@ -82,7 +212,8 @@ FrameSequenceTrackerCollection::FrameSequenceTrackerCollection( CompositorFrameReportingController* compositor_frame_reporting_controller) : is_single_threaded_(is_single_threaded), compositor_frame_reporting_controller_( - compositor_frame_reporting_controller) {} + compositor_frame_reporting_controller), + throughput_ukm_reporter_(std::make_unique<ThroughputUkmReporter>()) {} FrameSequenceTrackerCollection::~FrameSequenceTrackerCollection() { frame_trackers_.clear(); @@ -95,7 +226,8 @@ void FrameSequenceTrackerCollection::StartSequence( return; if (frame_trackers_.contains(type)) return; - auto tracker = base::WrapUnique(new FrameSequenceTracker(type)); + auto tracker = base::WrapUnique(new FrameSequenceTracker( + type, ukm_manager_, throughput_ukm_reporter_.get())); frame_trackers_[type] = std::move(tracker); if (compositor_frame_reporting_controller_) @@ -175,6 +307,26 @@ void FrameSequenceTrackerCollection::NotifyFramePresented( for (auto& tracker : removal_trackers_) tracker->ReportFramePresented(frame_token, feedback); + for (auto& tracker : removal_trackers_) { + if (tracker->termination_status() == + FrameSequenceTracker::TerminationStatus::kReadyForTermination) { + // The tracker is ready to be terminated. Take the metrics from the + // tracker, merge with any outstanding metrics from previous trackers of + // the same type. If there are enough frames to report the metrics, then + // report the metrics and destroy it. Otherwise, retain it to be merged + // with follow-up sequences. + auto metrics = tracker->TakeMetrics(); + if (accumulated_metrics_.contains(tracker->type())) { + metrics->Merge(std::move(accumulated_metrics_[tracker->type()])); + accumulated_metrics_.erase(tracker->type()); + } + if (metrics->HasEnoughDataForReporting()) + metrics->ReportMetrics(); + if (metrics->HasDataLeftForReporting()) + accumulated_metrics_[tracker->type()] = std::move(metrics); + } + } + // Destroy the trackers that are ready to be terminated. base::EraseIf( removal_trackers_, @@ -209,67 +361,31 @@ FrameSequenceTracker* FrameSequenceTrackerCollection::GetTrackerForTesting( return frame_trackers_[type].get(); } +void FrameSequenceTrackerCollection::SetUkmManager(UkmManager* manager) { + DCHECK(frame_trackers_.empty()); + ukm_manager_ = manager; +} + //////////////////////////////////////////////////////////////////////////////// // FrameSequenceTracker -FrameSequenceTracker::FrameSequenceTracker(FrameSequenceTrackerType type) - : type_(type) { +FrameSequenceTracker::FrameSequenceTracker( + FrameSequenceTrackerType type, + UkmManager* manager, + ThroughputUkmReporter* throughput_ukm_reporter) + : type_(type), + metrics_( + std::make_unique<FrameSequenceMetrics>(type, + manager, + throughput_ukm_reporter)) { DCHECK_LT(type_, FrameSequenceTrackerType::kMaxType); - TRACE_EVENT_ASYNC_BEGIN1( - "cc,benchmark", "FrameSequenceTracker", this, "name", - TRACE_STR_COPY( - FrameSequenceTracker::kFrameSequenceTrackerTypeNames[type_])); } FrameSequenceTracker::~FrameSequenceTracker() { - DCHECK_LE(impl_throughput_.frames_produced, impl_throughput_.frames_expected); - DCHECK_LE(main_throughput_.frames_produced, main_throughput_.frames_expected); - DCHECK_LE(main_throughput_.frames_produced, impl_throughput_.frames_produced); - TRACE_EVENT_ASYNC_END2( - "cc,benchmark", "FrameSequenceTracker", this, "args", - ThroughputData::ToTracedValue(impl_throughput_, main_throughput_), - "checkerboard", checkerboarding_.frames_checkerboarded); - ReportMetrics(); } void FrameSequenceTracker::ReportMetrics() { - // Report the throughput metrics. - base::Optional<int> impl_throughput_percent = ThroughputData::ReportHistogram( - type_, "CompositorThread", - GetIndexForMetric(ThreadType::kCompositor, type_), impl_throughput_); - base::Optional<int> main_throughput_percent = ThroughputData::ReportHistogram( - type_, "MainThread", GetIndexForMetric(ThreadType::kMain, type_), - main_throughput_); - - base::Optional<ThroughputData> slower_throughput; - if (impl_throughput_percent && - (!main_throughput_percent || - impl_throughput_percent.value() <= main_throughput_percent.value())) { - slower_throughput = impl_throughput_; - } - if (main_throughput_percent && - (!impl_throughput_percent || - main_throughput_percent.value() < impl_throughput_percent.value())) { - slower_throughput = main_throughput_; - } - if (slower_throughput.has_value()) { - ThroughputData::ReportHistogram( - type_, "SlowerThread", GetIndexForMetric(ThreadType::kSlower, type_), - slower_throughput.value()); - } - - // Report the checkerboarding metrics. - if (impl_throughput_.frames_expected >= kMinFramesForThroughputMetric) { - const int checkerboarding_percent = - static_cast<int>(100 * checkerboarding_.frames_checkerboarded / - impl_throughput_.frames_expected); - STATIC_HISTOGRAM_POINTER_GROUP( - GetCheckerboardingHistogramName(type_), type_, - FrameSequenceTrackerType::kMaxType, Add(checkerboarding_percent), - base::LinearHistogram::FactoryGet( - GetCheckerboardingHistogramName(type_), 1, 100, 101, - base::HistogramBase::kUmaTargetedHistogramFlag)); - } + metrics_->ReportMetrics(); } void FrameSequenceTracker::ReportBeginImplFrame( @@ -280,9 +396,14 @@ void FrameSequenceTracker::ReportBeginImplFrame( if (ShouldIgnoreBeginFrameSource(args.source_id)) return; +#if DCHECK_IS_ON() + if (args.type == viz::BeginFrameArgs::NORMAL) + impl_frames_.insert(std::make_pair(args.source_id, args.sequence_number)); +#endif + TRACKER_TRACE_STREAM << 'b'; UpdateTrackedFrameData(&begin_impl_frame_data_, args.source_id, args.sequence_number); - impl_throughput_.frames_expected += + impl_throughput().frames_expected += begin_impl_frame_data_.previous_sequence_delta; if (first_frame_timestamp_.is_null()) @@ -297,11 +418,24 @@ void FrameSequenceTracker::ReportBeginMainFrame( if (ShouldIgnoreBeginFrameSource(args.source_id)) return; + if (ShouldIgnoreSequence(args.sequence_number)) + return; + +#if DCHECK_IS_ON() + if (args.type == viz::BeginFrameArgs::NORMAL) { + DCHECK(impl_frames_.contains( + std::make_pair(args.source_id, args.sequence_number))); + } +#endif + + TRACKER_TRACE_STREAM << 'B'; + TRACKER_TRACE_STREAM << "(" << begin_main_frame_data_.previous_sequence << "," + << args.sequence_number << ")"; UpdateTrackedFrameData(&begin_main_frame_data_, args.source_id, args.sequence_number); if (first_received_main_sequence_ == 0) first_received_main_sequence_ = args.sequence_number; - main_throughput_.frames_expected += + main_throughput().frames_expected += begin_main_frame_data_.previous_sequence_delta; } @@ -310,14 +444,10 @@ void FrameSequenceTracker::ReportSubmitFrame( bool has_missing_content, const viz::BeginFrameAck& ack, const viz::BeginFrameArgs& origin_args) { - if (termination_status_ != TerminationStatus::kActive) - return; - - if (ShouldIgnoreBeginFrameSource(ack.source_id)) - return; - - if (begin_impl_frame_data_.previous_sequence == 0 || - ack.sequence_number < begin_impl_frame_data_.previous_sequence) { + if (termination_status_ != TerminationStatus::kActive || + ShouldIgnoreBeginFrameSource(ack.source_id) || + ShouldIgnoreSequence(ack.sequence_number)) { + ignored_frame_tokens_.insert(frame_token); return; } @@ -330,9 +460,12 @@ void FrameSequenceTracker::ReportSubmitFrame( origin_args.sequence_number >= first_received_main_sequence_) { if (last_submitted_main_sequence_ == 0 || origin_args.sequence_number > last_submitted_main_sequence_) { + TRACKER_TRACE_STREAM << 'S'; + last_submitted_main_sequence_ = origin_args.sequence_number; main_frames_.push_back(frame_token); - DCHECK_GE(main_throughput_.frames_expected, main_frames_.size()); + DCHECK_GE(main_throughput().frames_expected, main_frames_.size()) + << TRACKER_DCHECK_MSG; } } @@ -363,14 +496,20 @@ void FrameSequenceTracker::ReportFramePresented( return; } + if (ignored_frame_tokens_.contains(frame_token)) + return; + + TRACKER_TRACE_STREAM << 'P'; + TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( - "cc,benchmark", "FrameSequenceTracker", this, "FramePresented", + "cc,benchmark", "FrameSequenceTracker", metrics_.get(), "FramePresented", feedback.timestamp); const bool was_presented = !feedback.timestamp.is_null(); if (was_presented && last_submitted_frame_) { - DCHECK_LT(impl_throughput_.frames_produced, - impl_throughput_.frames_expected); - ++impl_throughput_.frames_produced; + DCHECK_LT(impl_throughput().frames_produced, + impl_throughput().frames_expected) + << TRACKER_DCHECK_MSG; + ++impl_throughput().frames_produced; if (frame_token_acks_last_frame) last_submitted_frame_ = 0; @@ -379,17 +518,19 @@ void FrameSequenceTracker::ReportFramePresented( while (!main_frames_.empty() && !viz::FrameTokenGT(main_frames_.front(), frame_token)) { if (was_presented && main_frames_.front() == frame_token) { - DCHECK_LT(main_throughput_.frames_produced, - main_throughput_.frames_expected); - ++main_throughput_.frames_produced; + DCHECK_LT(main_throughput().frames_produced, + main_throughput().frames_expected) + << TRACKER_DCHECK_MSG; + ++main_throughput().frames_produced; } main_frames_.pop_front(); } if (was_presented) { if (checkerboarding_.last_frame_had_checkerboarding) { - DCHECK(!checkerboarding_.last_frame_timestamp.is_null()); - DCHECK(!feedback.timestamp.is_null()); + DCHECK(!checkerboarding_.last_frame_timestamp.is_null()) + << TRACKER_DCHECK_MSG; + DCHECK(!feedback.timestamp.is_null()) << TRACKER_DCHECK_MSG; // |feedback.timestamp| is the timestamp when the latest frame was // presented. |checkerboarding_.last_frame_timestamp| is the timestamp @@ -402,10 +543,10 @@ void FrameSequenceTracker::ReportFramePresented( const auto& interval = feedback.interval.is_zero() ? viz::BeginFrameArgs::DefaultInterval() : feedback.interval; - DCHECK(!interval.is_zero()); + DCHECK(!interval.is_zero()) << TRACKER_DCHECK_MSG; constexpr base::TimeDelta kEpsilon = base::TimeDelta::FromMilliseconds(1); int64_t frames = (difference + kEpsilon) / interval; - checkerboarding_.frames_checkerboarded += frames; + metrics_->add_checkerboarded_frames(frames); } const bool frame_had_checkerboarding = @@ -430,13 +571,15 @@ void FrameSequenceTracker::ReportImplFrameCausedNoDamage( // It is possible that this is called before a begin-impl-frame has been // dispatched for this frame-sequence. In such cases, ignore this call. - if (begin_impl_frame_data_.previous_sequence == 0 || - ack.sequence_number < begin_impl_frame_data_.previous_sequence) { + if (ShouldIgnoreSequence(ack.sequence_number)) return; - } - DCHECK_GT(impl_throughput_.frames_expected, 0u); - DCHECK_GT(impl_throughput_.frames_expected, impl_throughput_.frames_produced); - --impl_throughput_.frames_expected; + + TRACKER_TRACE_STREAM << 'n'; + DCHECK_GT(impl_throughput().frames_expected, 0u) << TRACKER_DCHECK_MSG; + DCHECK_GT(impl_throughput().frames_expected, + impl_throughput().frames_produced) + << TRACKER_DCHECK_MSG; + --impl_throughput().frames_expected; if (begin_impl_frame_data_.previous_sequence == ack.sequence_number) begin_impl_frame_data_.previous_sequence = 0; @@ -450,6 +593,10 @@ void FrameSequenceTracker::ReportMainFrameCausedNoDamage( if (ShouldIgnoreBeginFrameSource(args.source_id)) return; + // ReportBeginMainFrame could be called without ReportBeginImplFrame, in that + // case we should ignore this call. + if (ShouldIgnoreSequence(args.sequence_number)) + return; // It is possible that this is called before a begin-main-frame has been // dispatched for this frame-sequence. In such cases, ignore this call. if (begin_main_frame_data_.previous_sequence == 0 || @@ -457,10 +604,16 @@ void FrameSequenceTracker::ReportMainFrameCausedNoDamage( return; } - DCHECK_GT(main_throughput_.frames_expected, 0u); - DCHECK_GT(main_throughput_.frames_expected, main_throughput_.frames_produced); - --main_throughput_.frames_expected; - DCHECK_GE(main_throughput_.frames_expected, main_frames_.size()); + TRACKER_TRACE_STREAM << 'N'; + TRACKER_TRACE_STREAM << "(" << begin_main_frame_data_.previous_sequence << "," + << args.sequence_number << ")"; + DCHECK_GT(main_throughput().frames_expected, 0u) << TRACKER_DCHECK_MSG; + DCHECK_GT(main_throughput().frames_expected, + main_throughput().frames_produced) + << TRACKER_DCHECK_MSG; + --main_throughput().frames_expected; + DCHECK_GE(main_throughput().frames_expected, main_frames_.size()) + << TRACKER_DCHECK_MSG; if (begin_main_frame_data_.previous_sequence == args.sequence_number) begin_main_frame_data_.previous_sequence = 0; @@ -478,7 +631,7 @@ void FrameSequenceTracker::UpdateTrackedFrameData(TrackedFrameData* frame_data, uint64_t sequence_number) { if (frame_data->previous_sequence && frame_data->previous_source == source_id) { - uint8_t current_latency = sequence_number - frame_data->previous_sequence; + uint32_t current_latency = sequence_number - frame_data->previous_sequence; frame_data->previous_sequence_delta = current_latency; } else { frame_data->previous_sequence_delta = 1; @@ -494,8 +647,17 @@ bool FrameSequenceTracker::ShouldIgnoreBeginFrameSource( return source_id != begin_impl_frame_data_.previous_source; } +// This check ensures that when ReportBeginMainFrame, or ReportSubmitFrame, or +// ReportFramePresented is called for a particular arg, the ReportBeginImplFrame +// is been called already. +bool FrameSequenceTracker::ShouldIgnoreSequence( + uint64_t sequence_number) const { + return begin_impl_frame_data_.previous_sequence == 0 || + sequence_number < begin_impl_frame_data_.previous_sequence; +} + std::unique_ptr<base::trace_event::TracedValue> -FrameSequenceTracker::ThroughputData::ToTracedValue( +FrameSequenceMetrics::ThroughputData::ToTracedValue( const ThroughputData& impl, const ThroughputData& main) { auto dict = std::make_unique<base::trace_event::TracedValue>(); @@ -508,13 +670,16 @@ FrameSequenceTracker::ThroughputData::ToTracedValue( bool FrameSequenceTracker::ShouldReportMetricsNow( const viz::BeginFrameArgs& args) const { - if (!first_frame_timestamp_.is_null() && - args.frame_time - first_frame_timestamp_ >= time_delta_to_report_) - return true; - return false; + return metrics_->HasEnoughDataForReporting() && + !first_frame_timestamp_.is_null() && + args.frame_time - first_frame_timestamp_ >= time_delta_to_report_; +} + +std::unique_ptr<FrameSequenceMetrics> FrameSequenceTracker::TakeMetrics() { + return std::move(metrics_); } -base::Optional<int> FrameSequenceTracker::ThroughputData::ReportHistogram( +base::Optional<int> FrameSequenceMetrics::ThroughputData::ReportHistogram( FrameSequenceTrackerType sequence_type, const char* thread_name, int metric_index, diff --git a/chromium/cc/metrics/frame_sequence_tracker.h b/chromium/cc/metrics/frame_sequence_tracker.h index 5004aa001c5..ac18280b445 100644 --- a/chromium/cc/metrics/frame_sequence_tracker.h +++ b/chromium/cc/metrics/frame_sequence_tracker.h @@ -14,6 +14,7 @@ #include "base/callback_helpers.h" #include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "base/macros.h" #include "base/optional.h" #include "base/trace_event/traced_value.h" @@ -31,6 +32,8 @@ struct BeginFrameArgs; namespace cc { class FrameSequenceTracker; class CompositorFrameReportingController; +class ThroughputUkmReporter; +class UkmManager; enum FrameSequenceTrackerType { kCompositorAnimation = 0, @@ -44,6 +47,73 @@ enum FrameSequenceTrackerType { kMaxType }; +class CC_EXPORT FrameSequenceMetrics { + public: + FrameSequenceMetrics(FrameSequenceTrackerType type, + UkmManager* ukm_manager, + ThroughputUkmReporter* ukm_reporter); + ~FrameSequenceMetrics(); + + FrameSequenceMetrics(const FrameSequenceMetrics&) = delete; + FrameSequenceMetrics& operator=(const FrameSequenceMetrics&) = delete; + + struct ThroughputData { + static std::unique_ptr<base::trace_event::TracedValue> ToTracedValue( + const ThroughputData& impl, + const ThroughputData& main); + + // Returns the throughput in percent, a return value of base::nullopt + // indicates that no throughput metric is reported. + static base::Optional<int> ReportHistogram( + FrameSequenceTrackerType sequence_type, + const char* thread_name, + int metric_index, + const ThroughputData& data); + + void Merge(const ThroughputData& data) { + frames_expected += data.frames_expected; + frames_produced += data.frames_produced; + } + + // Tracks the number of frames that were expected to be shown during this + // frame-sequence. + uint32_t frames_expected = 0; + + // Tracks the number of frames that were actually presented to the user + // during this frame-sequence. + uint32_t frames_produced = 0; + }; + + void Merge(std::unique_ptr<FrameSequenceMetrics> metrics); + bool HasEnoughDataForReporting() const; + bool HasDataLeftForReporting() const; + void ReportMetrics(); + + ThroughputData& impl_throughput() { return impl_throughput_; } + ThroughputData& main_throughput() { return main_throughput_; } + void add_checkerboarded_frames(int64_t frames) { + frames_checkerboarded_ += frames; + } + uint32_t frames_checkerboarded() const { return frames_checkerboarded_; } + + private: + const FrameSequenceTrackerType type_; + + // Please refer to the comments in FrameSequenceTrackerCollection's + // ukm_manager_. + UkmManager* const ukm_manager_; + + // Pointer to the reporter owned by the FrameSequenceTrackerCollection. + ThroughputUkmReporter* const throughput_ukm_reporter_; + + ThroughputData impl_throughput_; + ThroughputData main_throughput_; + + // Tracks the number of produced frames that had some amount of + // checkerboarding, and how many frames showed such checkerboarded frames. + uint32_t frames_checkerboarded_ = 0; +}; + // Used for notifying attached FrameSequenceTracker's of begin-frames and // submitted frames. class CC_EXPORT FrameSequenceTrackerCollection { @@ -93,6 +163,8 @@ class CC_EXPORT FrameSequenceTrackerCollection { FrameSequenceTracker* GetTrackerForTesting(FrameSequenceTrackerType type); + void SetUkmManager(UkmManager* manager); + private: friend class FrameSequenceTrackerTest; @@ -106,6 +178,20 @@ class CC_EXPORT FrameSequenceTrackerCollection { std::vector<std::unique_ptr<FrameSequenceTracker>> removal_trackers_; CompositorFrameReportingController* const compositor_frame_reporting_controller_; + + // The reporter takes throughput data and connect to UkmManager to report it. + std::unique_ptr<ThroughputUkmReporter> throughput_ukm_reporter_; + + // This is pointing to the LayerTreeHostImpl::ukm_manager_, which is + // initialized right after the LayerTreeHostImpl is created. So when this + // pointer is initialized, there should be no trackers yet. Moreover, the + // LayerTreeHostImpl::ukm_manager_ lives as long as the LayerTreeHostImpl, so + // this pointer should never be null as long as LayerTreeHostImpl is alive. + UkmManager* ukm_manager_ = nullptr; + + base::flat_map<FrameSequenceTrackerType, + std::unique_ptr<FrameSequenceMetrics>> + accumulated_metrics_; }; // Tracks a sequence of frames to determine the throughput. It tracks this by @@ -123,7 +209,13 @@ class CC_EXPORT FrameSequenceTracker { kReadyForTermination, }; - static const char* const kFrameSequenceTrackerTypeNames[]; + enum class ThreadType { + kMain, + kCompositor, + kSlower, + }; + + static const char* GetFrameSequenceTrackerTypeName(int type_index); ~FrameSequenceTracker(); @@ -172,11 +264,25 @@ class CC_EXPORT FrameSequenceTracker { // Returns true if we should ask this tracker to report its throughput data. bool ShouldReportMetricsNow(const viz::BeginFrameArgs& args) const; + FrameSequenceMetrics* metrics() { return metrics_.get(); } + FrameSequenceTrackerType type() const { return type_; } + + std::unique_ptr<FrameSequenceMetrics> TakeMetrics(); + private: friend class FrameSequenceTrackerCollection; friend class FrameSequenceTrackerTest; - explicit FrameSequenceTracker(FrameSequenceTrackerType type); + FrameSequenceTracker(FrameSequenceTrackerType type, + UkmManager* manager, + ThroughputUkmReporter* throughput_ukm_reporter); + + FrameSequenceMetrics::ThroughputData& impl_throughput() { + return metrics_->impl_throughput(); + } + FrameSequenceMetrics::ThroughputData& main_throughput() { + return metrics_->main_throughput(); + } void ScheduleTerminate() { termination_status_ = TerminationStatus::kScheduledForTermination; @@ -191,37 +297,13 @@ class CC_EXPORT FrameSequenceTracker { // The difference in |BeginFrameArgs::sequence_number| fields of the last // two processed BeginFrameArgs. - uint8_t previous_sequence_delta = 0; - }; - - struct ThroughputData { - static std::unique_ptr<base::trace_event::TracedValue> ToTracedValue( - const ThroughputData& impl, - const ThroughputData& main); - // Returns the throughput in percent, a return value of base::nullopt - // indicates that no throughput metric is reported. - static base::Optional<int> ReportHistogram( - FrameSequenceTrackerType sequence_type, - const char* thread_name, - int metric_index, - const ThroughputData& data); - // Tracks the number of frames that were expected to be shown during this - // frame-sequence. - uint32_t frames_expected = 0; - - // Tracks the number of frames that were actually presented to the user - // during this frame-sequence. - uint32_t frames_produced = 0; + uint32_t previous_sequence_delta = 0; }; struct CheckerboardingData { CheckerboardingData(); ~CheckerboardingData(); - // Tracks the number of produced frames that had some amount of - // checkerboarding, and how many frames showed such checkerboarded frames. - uint32_t frames_checkerboarded = 0; - // Tracks whether the last presented frame had checkerboarding. This is used // to track how many vsyncs showed frames with checkerboarding. bool last_frame_had_checkerboarding = false; @@ -238,6 +320,8 @@ class CC_EXPORT FrameSequenceTracker { bool ShouldIgnoreBeginFrameSource(uint64_t source_id) const; + bool ShouldIgnoreSequence(uint64_t sequence_number) const; + // Report related metrics: throughput, checkboarding... void ReportMetrics(); @@ -248,8 +332,7 @@ class CC_EXPORT FrameSequenceTracker { TrackedFrameData begin_impl_frame_data_; TrackedFrameData begin_main_frame_data_; - ThroughputData impl_throughput_; - ThroughputData main_throughput_; + std::unique_ptr<FrameSequenceMetrics> metrics_; CheckerboardingData checkerboarding_; @@ -282,8 +365,29 @@ class CC_EXPORT FrameSequenceTracker { // scheduled to report histogram. base::TimeTicks first_frame_timestamp_; + // A frame that is ignored at ReportSubmitFrame should never be presented. + // TODO(xidachen): this should not be necessary. Some webview tests seem to + // present a frame even if it is ignored by ReportSubmitFrame. + base::flat_set<uint32_t> ignored_frame_tokens_; + // Report the throughput metrics every 5 seconds. const base::TimeDelta time_delta_to_report_ = base::TimeDelta::FromSeconds(5); + +#if DCHECK_IS_ON() + // This stringstream represents a sequence of frame reporting activities on + // the current tracker. Each letter can be one of the following: + // {'B', 'N', 'b', 'n', 'S', 'P'}, where + // 'B' = ReportBeginMainFrame(), 'N' = ReportMainFrameCausedNoDamage(), + // 'b' = ReportBeginImplFrame(), 'n' = ReportMainFrameCausedNoDamage(), + // 'S' = ReportSubmitFrame() and 'P' = ReportFramePresented(). + // Note that |frame_sequence_trace_| is only defined and populated + // when DCHECK is on. + std::stringstream frame_sequence_trace_; + + // If ReportBeginImplFrame is never called on a arg, then ReportBeginMainFrame + // should ignore that arg. + base::flat_set<std::pair<uint64_t, uint64_t>> impl_frames_; +#endif }; } // namespace cc diff --git a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc index 53d9b62a8d3..d2c1fa482fc 100644 --- a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc +++ b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc @@ -117,8 +117,8 @@ class FrameSequenceTrackerTest : public testing::Test { base::HistogramTester histogram_tester; // Test that there is no main thread frames expected. - tracker_->impl_throughput_.frames_expected = 100u; - tracker_->impl_throughput_.frames_produced = 85u; + tracker_->impl_throughput().frames_expected = 100u; + tracker_->impl_throughput().frames_produced = 85u; tracker_->ReportMetrics(); histogram_tester.ExpectTotalCount( "Graphics.Smoothness.Throughput.CompositorThread.TouchScroll", 1u); @@ -128,8 +128,10 @@ class FrameSequenceTrackerTest : public testing::Test { "Graphics.Smoothness.Throughput.SlowerThread.TouchScroll", 1u); // Test that both are reported. - tracker_->main_throughput_.frames_expected = 50u; - tracker_->main_throughput_.frames_produced = 25u; + tracker_->impl_throughput().frames_expected = 100u; + tracker_->impl_throughput().frames_produced = 85u; + tracker_->main_throughput().frames_expected = 150u; + tracker_->main_throughput().frames_produced = 25u; tracker_->ReportMetrics(); histogram_tester.ExpectTotalCount( "Graphics.Smoothness.Throughput.CompositorThread.TouchScroll", 2u); @@ -139,10 +141,10 @@ class FrameSequenceTrackerTest : public testing::Test { "Graphics.Smoothness.Throughput.SlowerThread.TouchScroll", 2u); // Test that none is reported. - tracker_->main_throughput_.frames_expected = 2u; - tracker_->main_throughput_.frames_produced = 1u; - tracker_->impl_throughput_.frames_expected = 2u; - tracker_->impl_throughput_.frames_produced = 1u; + tracker_->main_throughput().frames_expected = 2u; + tracker_->main_throughput().frames_produced = 1u; + tracker_->impl_throughput().frames_expected = 2u; + tracker_->impl_throughput().frames_produced = 1u; tracker_->ReportMetrics(); histogram_tester.ExpectTotalCount( "Graphics.Smoothness.Throughput.CompositorThread.TouchScroll", 2u); @@ -152,10 +154,10 @@ class FrameSequenceTrackerTest : public testing::Test { "Graphics.Smoothness.Throughput.SlowerThread.TouchScroll", 2u); // Test the case where compositor and main thread have the same throughput. - tracker_->impl_throughput_.frames_expected = 20u; - tracker_->impl_throughput_.frames_produced = 18u; - tracker_->main_throughput_.frames_expected = 20u; - tracker_->main_throughput_.frames_produced = 18u; + tracker_->impl_throughput().frames_expected = 120u; + tracker_->impl_throughput().frames_produced = 118u; + tracker_->main_throughput().frames_expected = 120u; + tracker_->main_throughput().frames_produced = 118u; tracker_->ReportMetrics(); histogram_tester.ExpectTotalCount( "Graphics.Smoothness.Throughput.CompositorThread.TouchScroll", 3u); @@ -176,9 +178,27 @@ class FrameSequenceTrackerTest : public testing::Test { return collection_.removal_trackers_.size(); } + uint64_t BeginImplFrameDataPreviousSequence() const { + return tracker_->begin_impl_frame_data_.previous_sequence; + } + uint64_t BeginMainFrameDataPreviousSequence() const { + return tracker_->begin_main_frame_data_.previous_sequence; + } + + base::flat_set<uint32_t> IgnoredFrameTokens() const { + return tracker_->ignored_frame_tokens_; + } + + FrameSequenceMetrics::ThroughputData& ImplThroughput() const { + return tracker_->impl_throughput(); + } + FrameSequenceMetrics::ThroughputData& MainThroughput() const { + return tracker_->main_throughput(); + } + protected: uint32_t number_of_frames_checkerboarded() const { - return tracker_->checkerboarding_.frames_checkerboarded; + return tracker_->metrics_->frames_checkerboarded(); } std::unique_ptr<CompositorFrameReportingController> @@ -356,6 +376,7 @@ TEST_F(FrameSequenceTrackerTest, ReportMetricsAtFixedInterval) { EXPECT_EQ(NumberOfTrackers(), 1u); EXPECT_EQ(NumberOfRemovalTrackers(), 0u); + ImplThroughput().frames_expected += 100; // Now args.frame_time is 5s since the tracker creation time, so this tracker // should be scheduled to report its throughput. args = CreateBeginFrameArgs(source, ++sequence, @@ -365,4 +386,28 @@ TEST_F(FrameSequenceTrackerTest, ReportMetricsAtFixedInterval) { EXPECT_EQ(NumberOfRemovalTrackers(), 1u); } +TEST_F(FrameSequenceTrackerTest, ReportWithoutBeginImplFrame) { + const uint64_t source = 1; + uint64_t sequence = 0; + + auto args = CreateBeginFrameArgs(source, ++sequence); + collection_.NotifyBeginMainFrame(args); + + EXPECT_EQ(BeginImplFrameDataPreviousSequence(), 0u); + // Call to ReportBeginMainFrame should early exit. + EXPECT_EQ(BeginMainFrameDataPreviousSequence(), 0u); + + uint32_t frame_token = NextFrameToken(); + collection_.NotifySubmitFrame(frame_token, false, + viz::BeginFrameAck(args, true), args); + + // Call to ReportSubmitFrame should early exit. + EXPECT_TRUE(IgnoredFrameTokens().contains(frame_token)); + + gfx::PresentationFeedback feedback; + collection_.NotifyFramePresented(frame_token, feedback); + EXPECT_EQ(ImplThroughput().frames_produced, 0u); + EXPECT_EQ(MainThroughput().frames_produced, 0u); +} + } // namespace cc diff --git a/chromium/cc/metrics/throughput_ukm_reporter.cc b/chromium/cc/metrics/throughput_ukm_reporter.cc new file mode 100644 index 00000000000..796cd184b32 --- /dev/null +++ b/chromium/cc/metrics/throughput_ukm_reporter.cc @@ -0,0 +1,51 @@ +// Copyright 2019 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. + +#include "cc/metrics/throughput_ukm_reporter.h" + +#include "cc/trees/ukm_manager.h" + +namespace cc { + +namespace { +// Collect UKM once per kNumberOfSamplesToReport UMA reports. +constexpr unsigned kNumberOfSamplesToReport = 2000u; +} // namespace + +void ThroughputUkmReporter::ReportThroughputUkm( + const UkmManager* ukm_manager, + const base::Optional<int>& slower_throughput_percent, + const base::Optional<int>& impl_throughput_percent, + const base::Optional<int>& main_throughput_percent, + FrameSequenceTrackerType type) { + // Sampling control. We sample the event here to not throttle the UKM system. + // Currently, the same sampling rate is applied to all existing trackers. We + // might want to iterate on this based on the collected data. + static uint32_t samples_to_next_event = 0; + + if (samples_to_next_event == 0) { + // Sample every 2000 events. Using the Universal tracker as an example + // which reports UMA every 5s, then the system collects UKM once per + // 2000*5 = 10000 seconds, which is about 3 hours. This number may need to + // be tuned to not throttle the UKM system. + samples_to_next_event = kNumberOfSamplesToReport; + if (impl_throughput_percent) { + ukm_manager->RecordThroughputUKM( + type, FrameSequenceTracker::ThreadType::kCompositor, + impl_throughput_percent.value()); + } + if (main_throughput_percent) { + ukm_manager->RecordThroughputUKM(type, + FrameSequenceTracker::ThreadType::kMain, + main_throughput_percent.value()); + } + ukm_manager->RecordThroughputUKM(type, + FrameSequenceTracker::ThreadType::kSlower, + slower_throughput_percent.value()); + } + DCHECK_GT(samples_to_next_event, 0u); + samples_to_next_event--; +} + +} // namespace cc diff --git a/chromium/cc/metrics/throughput_ukm_reporter.h b/chromium/cc/metrics/throughput_ukm_reporter.h new file mode 100644 index 00000000000..defa8703ee8 --- /dev/null +++ b/chromium/cc/metrics/throughput_ukm_reporter.h @@ -0,0 +1,31 @@ +// Copyright 2019 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_METRICS_THROUGHPUT_UKM_REPORTER_H_ +#define CC_METRICS_THROUGHPUT_UKM_REPORTER_H_ + +#include "base/optional.h" +#include "cc/cc_export.h" +#include "cc/metrics/frame_sequence_tracker.h" + +namespace cc { +class UkmManager; + +// A helper class that takes throughput data from a FrameSequenceTracker and +// talk to UkmManager to report it. +class CC_EXPORT ThroughputUkmReporter { + public: + ThroughputUkmReporter() = default; + ~ThroughputUkmReporter() = default; + + void ReportThroughputUkm(const UkmManager* ukm_manager, + const base::Optional<int>& slower_throughput_percent, + const base::Optional<int>& impl_throughput_percent, + const base::Optional<int>& main_throughput_percent, + FrameSequenceTrackerType type); +}; + +} // namespace cc + +#endif // CC_METRICS_THROUGHPUT_UKM_REPORTER_H_ 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 72c13d9231f..401958e0bcb 100644 --- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc +++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc @@ -14,7 +14,6 @@ #include "base/trace_event/trace_event.h" #include "cc/base/histograms.h" #include "cc/trees/layer_tree_frame_sink_client.h" -#include "components/viz/client/hit_test_data_provider.h" #include "components/viz/common/features.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/hit_test/hit_test_region_list.h" @@ -82,7 +81,6 @@ AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink( std::move(worker_context_provider), std::move(params->compositor_task_runner), params->gpu_memory_buffer_manager), - hit_test_data_provider_(std::move(params->hit_test_data_provider)), synthetic_begin_frame_source_( std::move(params->synthetic_begin_frame_source)), pipes_(std::move(params->pipes)), @@ -93,10 +91,6 @@ AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink( submit_begin_frame_histogram_(GetHistogramNamed( "GraphicsPipeline.%s.SubmitCompositorFrameAfterBeginFrame", params->client_name)) { - // We should not create hit test data provider if we want to use cc layer tree - // to generated data. - if (features::IsVizHitTestingSurfaceLayerEnabled()) - DCHECK(!params->hit_test_data_provider); DETACH_FROM_THREAD(thread_checker_); } @@ -186,11 +180,8 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame( frame.size_in_pixels().width()); } - base::Optional<viz::HitTestRegionList> hit_test_region_list; - if (hit_test_data_provider_) - hit_test_region_list = hit_test_data_provider_->GetHitTestData(frame); - else - hit_test_region_list = client_->BuildHitTestData(); + base::Optional<viz::HitTestRegionList> hit_test_region_list = + client_->BuildHitTestData(); if (show_hit_test_borders && hit_test_region_list) hit_test_region_list->flags |= viz::HitTestRegionFlags::kHitTestDebug; 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 236d792b4b0..076f3428163 100644 --- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h +++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h @@ -31,10 +31,6 @@ namespace base { class HistogramBase; } // namespace base -namespace viz { -class HitTestDataProvider; -} // namespace viz - namespace cc { namespace mojo_embedder { @@ -97,7 +93,6 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr; std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source; - std::unique_ptr<viz::HitTestDataProvider> hit_test_data_provider; UnboundMessagePipes pipes; bool wants_animate_only_begin_frames = false; const char* client_name = nullptr; @@ -112,10 +107,6 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink AsyncLayerTreeFrameSink& operator=(const AsyncLayerTreeFrameSink&) = delete; - const viz::HitTestDataProvider* hit_test_data_provider() const { - return hit_test_data_provider_.get(); - } - const viz::LocalSurfaceId& local_surface_id() const { return local_surface_id_; } @@ -155,7 +146,6 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink bool begin_frames_paused_ = false; bool needs_begin_frames_ = false; viz::LocalSurfaceId local_surface_id_; - std::unique_ptr<viz::HitTestDataProvider> hit_test_data_provider_; std::unique_ptr<viz::ExternalBeginFrameSource> begin_frame_source_; std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source_; diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc index 82984c11006..2a4ba2e5906 100644 --- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc +++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc @@ -13,7 +13,6 @@ #include "base/test/test_mock_time_task_runner.h" #include "base/threading/thread.h" #include "cc/test/fake_layer_tree_frame_sink_client.h" -#include "components/viz/client/hit_test_data_provider_draw_quad.h" #include "components/viz/common/quads/render_pass_draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/surface_draw_quad.h" @@ -141,9 +140,6 @@ class AsyncLayerTreeFrameSinkSimpleTest : public testing::Test { init_params_.pipes.compositor_frame_sink_remote = std::move(sink_remote); init_params_.pipes.client_receiver = client.InitWithNewPipeAndPassReceiver(); - init_params_.hit_test_data_provider = - std::make_unique<viz::HitTestDataProviderDrawQuad>( - /*should_ask_for_child_region=*/true, /*root_accepts_events=*/true); layer_tree_frame_sink_ = std::make_unique<AsyncLayerTreeFrameSink>( std::move(context_provider), nullptr, &init_params_); @@ -177,27 +173,33 @@ class AsyncLayerTreeFrameSinkSimpleTest : public testing::Test { FakeLayerTreeFrameSinkClient layer_tree_frame_sink_client_; }; -TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { +TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListEmpty) { viz::RenderPassList pass_list; + auto pass = viz::RenderPass::Create(); + pass->id = 1; + pass->output_rect = display_rect_; + pass_list.push_back(move(pass)); + + SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); + task_runner_->RunUntilIdle(); + + EXPECT_TRUE(viz::HitTestRegionList::IsEqual(viz::HitTestRegionList(), + GetHitTestData())); +} +TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { + viz::RenderPassList pass_list; // Initial submission. auto pass1 = viz::RenderPass::Create(); pass1->id = 1; pass1->output_rect = display_rect_; - auto* shared_quad_state1 = pass1->CreateAndAppendSharedQuadState(); - gfx::Rect rect1(display_rect_); - shared_quad_state1->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect1, - /*visible_quad_layer_rect=*/rect1, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect1, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad1 = - pass1->quad_list.AllocateAndConstruct<viz::SolidColorDrawQuad>(); - quad1->SetNew(shared_quad_state1, /*rect=*/rect1, - /*visible_rect=*/rect1, SK_ColorBLACK, - /*force_anti_aliasing_off=*/false); pass_list.push_back(move(pass1)); + + viz::HitTestRegionList region_list1; + region_list1.flags = viz::HitTestRegionFlags::kHitTestMine; + region_list1.bounds.SetRect(0, 0, 1024, 768); + layer_tree_frame_sink_client_.set_hit_test_region_list(region_list1); + SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); const viz::HitTestRegionList hit_test_region_list = GetHitTestData(); @@ -206,20 +208,8 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { auto pass2 = viz::RenderPass::Create(); pass2->id = 2; pass2->output_rect = display_rect_; - auto* shared_quad_state2 = pass2->CreateAndAppendSharedQuadState(); - gfx::Rect rect2(display_rect_); - shared_quad_state2->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect2, - /*visible_quad_layer_rect=*/rect2, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect2, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad2 = - pass2->quad_list.AllocateAndConstruct<viz::SolidColorDrawQuad>(); - quad2->SetNew(shared_quad_state2, /*rect=*/rect2, - /*visible_rect=*/rect2, SK_ColorBLACK, - /*force_anti_aliasing_off=*/false); pass_list.push_back(move(pass2)); + SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); @@ -227,76 +217,15 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, HitTestRegionListDuplicate) { viz::HitTestRegionList::IsEqual(hit_test_region_list, GetHitTestData())); // Different submission. - const viz::SurfaceId child_surface_id( - viz::FrameSinkId(1, 1), - viz::LocalSurfaceId(2, base::UnguessableToken::Create())); - auto pass3_0 = viz::RenderPass::Create(); - pass3_0->output_rect = display_rect_; - pass3_0->id = 3; - auto* shared_quad_state3_0 = pass3_0->CreateAndAppendSharedQuadState(); - gfx::Rect rect3_0(display_rect_); - gfx::Transform transform3_0; - transform3_0.Translate(-200, -100); - shared_quad_state3_0->SetAll( - transform3_0, /*quad_layer_rect=*/rect3_0, - /*visible_quad_layer_rect=*/rect3_0, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect3_0, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad3_0 = - pass3_0->quad_list.AllocateAndConstruct<viz::SurfaceDrawQuad>(); - quad3_0->SetNew(shared_quad_state3_0, /*rect=*/rect3_0, - /*visible_rect=*/rect3_0, - viz::SurfaceRange(base::nullopt, child_surface_id), - SK_ColorBLACK, - /*stretch_content_to_fill_bounds=*/false, - /*ignores_input_event=*/false); - pass_list.push_back(std::move(pass3_0)); - - auto pass3_1 = viz::RenderPass::Create(); - pass3_1->output_rect = display_rect_; - pass3_1->id = 4; - auto* shared_quad_state3_1 = pass3_1->CreateAndAppendSharedQuadState(); - gfx::Rect rect3_1(display_rect_); - shared_quad_state3_1->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect3_1, - /*visible_quad_layer_rect=*/rect3_1, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect3_1, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad3_1 = - pass3_1->quad_list.AllocateAndConstruct<viz::SolidColorDrawQuad>(); - quad3_1->SetNew(shared_quad_state3_1, /*rect=*/rect3_1, - /*visible_rect=*/rect3_1, SK_ColorBLACK, - /*force_anti_aliasing_off=*/false); - pass_list.push_back(std::move(pass3_1)); - - auto pass3_root = viz::RenderPass::Create(); - pass3_root->output_rect = display_rect_; - pass3_root->id = 5; - auto* shared_quad_state3_root = pass3_root->CreateAndAppendSharedQuadState(); - gfx::Rect rect3_root(display_rect_); - shared_quad_state3_root->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect3_root, - /*visible_quad_layer_rect=*/rect3_root, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect3_root, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad3_root_1 = - pass3_root->quad_list.AllocateAndConstruct<viz::RenderPassDrawQuad>(); - quad3_root_1->SetNew(shared_quad_state3_root, /*rect=*/rect3_root, - /*visible_rect=*/rect3_root, /*render_pass_id=*/3, - /*mask_resource_id=*/0, gfx::RectF(), gfx::Size(), - gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, - 1.0f); - auto* quad3_root_2 = - pass3_root->quad_list.AllocateAndConstruct<viz::RenderPassDrawQuad>(); - quad3_root_2->SetNew(shared_quad_state3_root, /*rect=*/rect3_root, - /*visible_rect=*/rect3_root, /*render_pass_id=*/4, - /*mask_resource_id=*/0, gfx::RectF(), gfx::Size(), - gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, - 1.0f); - pass_list.push_back(std::move(pass3_root)); + auto pass3 = viz::RenderPass::Create(); + pass3->id = 3; + pass3->output_rect = display_rect_; + pass_list.push_back(move(pass3)); + + viz::HitTestRegionList region_list2; + region_list2.flags = viz::HitTestRegionFlags::kHitTestMine; + region_list2.bounds.SetRect(0, 0, 800, 600); + layer_tree_frame_sink_client_.set_hit_test_region_list(region_list2); SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); @@ -312,95 +241,27 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, auto pass1 = viz::RenderPass::Create(); pass1->id = 1; pass1->output_rect = display_rect_; - auto* shared_quad_state1 = pass1->CreateAndAppendSharedQuadState(); - gfx::Rect rect1(display_rect_); - shared_quad_state1->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect1, - /*visible_quad_layer_rect=*/rect1, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect1, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad1 = - pass1->quad_list.AllocateAndConstruct<viz::SolidColorDrawQuad>(); - quad1->SetNew(shared_quad_state1, /*rect=*/rect1, - /*visible_rect=*/rect1, SK_ColorBLACK, - /*force_anti_aliasing_off=*/false); pass_list.push_back(move(pass1)); + + viz::HitTestRegionList region_list1; + region_list1.flags = viz::HitTestRegionFlags::kHitTestMine; + region_list1.bounds.SetRect(0, 0, 1024, 768); + layer_tree_frame_sink_client_.set_hit_test_region_list(region_list1); + SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); viz::HitTestRegionList hit_test_region_list = GetHitTestData(); // Different submission with |hit_test_data_changed| set to true. - const viz::SurfaceId child_surface_id( - viz::FrameSinkId(1, 1), - viz::LocalSurfaceId(2, base::UnguessableToken::Create())); - auto pass2_0 = viz::RenderPass::Create(); - pass2_0->output_rect = display_rect_; - pass2_0->id = 2; - auto* shared_quad_state2_0 = pass2_0->CreateAndAppendSharedQuadState(); - gfx::Rect rect2_0(display_rect_); - gfx::Transform transform2_0; - transform2_0.Translate(-200, -100); - shared_quad_state2_0->SetAll( - transform2_0, /*quad_layer_rect=*/rect2_0, - /*visible_quad_layer_rect=*/rect2_0, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect2_0, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad2_0 = - pass2_0->quad_list.AllocateAndConstruct<viz::SurfaceDrawQuad>(); - quad2_0->SetNew(shared_quad_state2_0, /*rect=*/rect2_0, - /*visible_rect=*/rect2_0, - viz::SurfaceRange(base::nullopt, child_surface_id), - SK_ColorBLACK, - /*stretch_content_to_fill_bounds=*/false, - /*ignores_input_event=*/false); - pass_list.push_back(std::move(pass2_0)); - - auto pass2_1 = viz::RenderPass::Create(); - pass2_1->output_rect = display_rect_; - pass2_1->id = 3; - auto* shared_quad_state2_1 = pass2_1->CreateAndAppendSharedQuadState(); - gfx::Rect rect2_1(display_rect_); - shared_quad_state2_1->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect2_1, - /*visible_quad_layer_rect=*/rect2_1, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect2_1, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad2_1 = - pass2_1->quad_list.AllocateAndConstruct<viz::SolidColorDrawQuad>(); - quad2_1->SetNew(shared_quad_state2_1, /*rect=*/rect2_1, - /*visible_rect=*/rect2_1, SK_ColorBLACK, - /*force_anti_aliasing_off=*/false); - pass_list.push_back(std::move(pass2_1)); - - auto pass2_root = viz::RenderPass::Create(); - pass2_root->output_rect = display_rect_; - pass2_root->id = 4; - auto* shared_quad_state2_root = pass2_root->CreateAndAppendSharedQuadState(); - gfx::Rect rect2_root(display_rect_); - shared_quad_state2_root->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect2_root, - /*visible_quad_layer_rect=*/rect2_root, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect2_root, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad2_root_1 = - pass2_root->quad_list.AllocateAndConstruct<viz::RenderPassDrawQuad>(); - quad2_root_1->SetNew(shared_quad_state2_root, /*rect=*/rect2_root, - /*visible_rect=*/rect2_root, /*render_pass_id=*/2, - /*mask_resource_id=*/0, gfx::RectF(), gfx::Size(), - gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, - 1.0f); - auto* quad2_root_2 = - pass2_root->quad_list.AllocateAndConstruct<viz::RenderPassDrawQuad>(); - quad2_root_2->SetNew(shared_quad_state2_root, /*rect=*/rect2_root, - /*visible_rect=*/rect2_root, /*render_pass_id=*/3, - /*mask_resource_id=*/0, gfx::RectF(), gfx::Size(), - gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, - 1.0f); - pass_list.push_back(std::move(pass2_root)); + auto pass2 = viz::RenderPass::Create(); + pass2->id = 2; + pass2->output_rect = display_rect_; + pass_list.push_back(std::move(pass2)); + + viz::HitTestRegionList region_list2; + region_list2.flags = viz::HitTestRegionFlags::kHitTestMine; + region_list2.bounds.SetRect(0, 0, 800, 600); + layer_tree_frame_sink_client_.set_hit_test_region_list(region_list2); SendRenderPassList(&pass_list, /*hit_test_data_changed=*/true); task_runner_->RunUntilIdle(); @@ -409,25 +270,18 @@ TEST_F(AsyncLayerTreeFrameSinkSimpleTest, viz::HitTestRegionList::IsEqual(hit_test_region_list, GetHitTestData())); hit_test_region_list = GetHitTestData(); - // Identical submission with |hit_test_data_changed| set back to false. We + // Different submission with |hit_test_data_changed| set back to false. We // expect the hit-data to still have been sent. auto pass3 = viz::RenderPass::Create(); - pass3->id = 4; + pass3->id = 3; pass3->output_rect = display_rect_; - auto* shared_quad_state3 = pass3->CreateAndAppendSharedQuadState(); - gfx::Rect rect3(display_rect_); - shared_quad_state3->SetAll( - gfx::Transform(), /*quad_layer_rect=*/rect3, - /*visible_quad_layer_rect=*/rect3, - /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/rect3, - /*is_clipped=*/false, /*are_contents_opaque=*/false, - /*opacity=*/0.5f, SkBlendMode::kSrcOver, /*sorting_context_id=*/0); - auto* quad3 = - pass3->quad_list.AllocateAndConstruct<viz::SolidColorDrawQuad>(); - quad3->SetNew(shared_quad_state3, /*rect=*/rect3, - /*visible_rect=*/rect3, SK_ColorBLACK, - /*force_anti_aliasing_off=*/false); pass_list.push_back(move(pass3)); + + viz::HitTestRegionList region_list3; + region_list3.flags = viz::HitTestRegionFlags::kHitTestChildSurface; + region_list3.bounds.SetRect(0, 0, 800, 600); + layer_tree_frame_sink_client_.set_hit_test_region_list(region_list3); + SendRenderPassList(&pass_list, /*hit_test_data_changed=*/false); task_runner_->RunUntilIdle(); diff --git a/chromium/cc/mojom/BUILD.gn b/chromium/cc/mojom/BUILD.gn new file mode 100644 index 00000000000..7f648e69f14 --- /dev/null +++ b/chromium/cc/mojom/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright 2019 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("mojom") { + generate_java = true + sources = [ + "touch_action.mojom", + ] + + public_deps = [ + "//mojo/public/mojom/base", + ] +} diff --git a/chromium/cc/mojom/OWNERS b/chromium/cc/mojom/OWNERS new file mode 100644 index 00000000000..d28aad21794 --- /dev/null +++ b/chromium/cc/mojom/OWNERS @@ -0,0 +1,5 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS + +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS diff --git a/chromium/cc/mojom/README.md b/chromium/cc/mojom/README.md new file mode 100644 index 00000000000..ec9c22f8c27 --- /dev/null +++ b/chromium/cc/mojom/README.md @@ -0,0 +1,10 @@ +# cc/mojom + +[TOC] + +## Overview + +cc/mojom provides the mojom typemaps for cc types. This directory is where +cc types that appear as part of mojo APIs should be placed. Structures that +are defined in C++ and have mojo based NativeEnum definitions will +require legacy Chrome IPC validators, see cc/ipc. diff --git a/chromium/cc/mojom/touch_action.mojom b/chromium/cc/mojom/touch_action.mojom new file mode 100644 index 00000000000..00084ffff29 --- /dev/null +++ b/chromium/cc/mojom/touch_action.mojom @@ -0,0 +1,8 @@ +// Copyright 2019 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. + +module cc.mojom; + +[Native] +enum TouchAction; diff --git a/chromium/cc/mojom/touch_action.typemap b/chromium/cc/mojom/touch_action.typemap new file mode 100644 index 00000000000..0ca823399df --- /dev/null +++ b/chromium/cc/mojom/touch_action.typemap @@ -0,0 +1,12 @@ +# Copyright 2019 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. + +mojom = "//cc/mojom/touch_action.mojom" +public_headers = [ "//cc/input/touch_action.h" ] +traits_headers = [ "//cc/ipc/cc_param_traits_macros.h" ] +public_deps = [ + "//cc", + "//cc/ipc", +] +type_mappings = [ "cc.mojom.TouchAction=::cc::TouchAction" ] diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc index ddc1c7d3347..47b0c7b4f2c 100644 --- a/chromium/cc/paint/discardable_image_map.cc +++ b/chromium/cc/paint/discardable_image_map.cc @@ -30,60 +30,26 @@ SkRect MapRect(const SkMatrix& matrix, const SkRect& src) { return dst; } -// This canvas is used only for tracking transform/clip/filter state from the -// non-drawing ops. -class PaintTrackingCanvas final : public SkNoDrawCanvas { - public: - PaintTrackingCanvas(int width, int height) : SkNoDrawCanvas(width, height) {} - ~PaintTrackingCanvas() override = default; - - bool ComputePaintBounds(const SkRect& rect, - const SkPaint* current_paint, - SkRect* paint_bounds) { - *paint_bounds = rect; - if (current_paint) { - if (!current_paint->canComputeFastBounds()) - return false; - *paint_bounds = - current_paint->computeFastBounds(*paint_bounds, paint_bounds); - } - - for (const auto& paint : base::Reversed(saved_paints_)) { - if (!paint.canComputeFastBounds()) - return false; - *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds); - } - - return true; - } - - private: - // SkNoDrawCanvas overrides. - SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { - saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint()); - return SkNoDrawCanvas::getSaveLayerStrategy(rec); - } - - void willSave() override { - saved_paints_.push_back(SkPaint()); - return SkNoDrawCanvas::willSave(); +bool ComputePaintBounds(const SkRect& rect, + const SkPaint* current_paint, + SkRect* paint_bounds) { + *paint_bounds = rect; + if (current_paint) { + if (!current_paint->canComputeFastBounds()) + return false; + *paint_bounds = + current_paint->computeFastBounds(*paint_bounds, paint_bounds); } - void willRestore() override { - DCHECK_GT(saved_paints_.size(), 0u); - saved_paints_.pop_back(); - SkNoDrawCanvas::willRestore(); - } - - std::vector<SkPaint> saved_paints_; -}; + return true; +} class DiscardableImageGenerator { public: DiscardableImageGenerator(int width, int height, const PaintOpBuffer* buffer) { - PaintTrackingCanvas canvas(width, height); + SkNoDrawCanvas canvas(width, height); GatherDiscardableImages(buffer, nullptr, &canvas); } ~DiscardableImageGenerator() = default; @@ -157,7 +123,7 @@ class DiscardableImageGenerator { // this image in the top-level buffer. void GatherDiscardableImages(const PaintOpBuffer* buffer, const gfx::Rect* top_level_op_rect, - PaintTrackingCanvas* canvas) { + SkNoDrawCanvas* canvas) { if (!buffer->HasDiscardableImages()) return; @@ -221,7 +187,7 @@ class DiscardableImageGenerator { // Given the |op_rect|, which is the rect for the draw op, returns the // transformed rect accounting for the current transform, clip and paint // state on |canvas_|. - gfx::Rect ComputePaintRect(const PaintOp* op, PaintTrackingCanvas* canvas) { + gfx::Rect ComputePaintRect(const PaintOp* op, SkNoDrawCanvas* canvas) { const SkRect& clip_rect = SkRect::Make(canvas->getDeviceClipBounds()); const SkMatrix& ctm = canvas->getTotalMatrix(); @@ -243,7 +209,7 @@ class DiscardableImageGenerator { SkRect paint_rect = MapRect(ctm, op_rect); bool computed_paint_bounds = - canvas->ComputePaintBounds(paint_rect, &paint, &paint_rect); + ComputePaintBounds(paint_rect, &paint, &paint_rect); if (!computed_paint_bounds) { // TODO(vmpstr): UMA this case. paint_rect = clip_rect; @@ -308,8 +274,8 @@ class DiscardableImageGenerator { return; } - PaintTrackingCanvas canvas(scaled_tile_rect.width(), - scaled_tile_rect.height()); + SkNoDrawCanvas canvas(scaled_tile_rect.width(), + scaled_tile_rect.height()); canvas.setMatrix(SkMatrix::MakeRectToRect( shader->tile(), scaled_tile_rect, SkMatrix::kFill_ScaleToFit)); base::AutoReset<bool> auto_reset(&only_gather_animated_images_, true); diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc index 28a86bfcebe..23e9c990175 100644 --- a/chromium/cc/paint/discardable_image_map_unittest.cc +++ b/chromium/cc/paint/discardable_image_map_unittest.cc @@ -30,6 +30,7 @@ namespace cc { namespace { +using Rects = base::StackVector<gfx::Rect, 1>; struct PositionScaleDrawImage { PositionScaleDrawImage(const PaintImage& image, @@ -378,6 +379,65 @@ TEST_F(DiscardableImageMapTest, PaintDestroyedWhileImageIsDrawn) { EXPECT_TRUE(images[0].image == discardable_image); } +// Check if SkNoDrawCanvas does not crash for large layers. +TEST_F(DiscardableImageMapTest, RestoreSavedBigLayers) { + PaintFlags flags; + SkRect rect = SkRect::MakeWH(INT_MAX, INT_MAX); + scoped_refptr<DisplayItemList> display_list = new DisplayItemList; + display_list->StartPaint(); + display_list->push<DrawRectOp>(rect, flags); + display_list->EndPaintOfUnpaired(gfx::Rect(INT_MAX, INT_MAX)); + display_list->Finalize(); + display_list->GenerateDiscardableImagesMetadata(); +} + +// Test if SaveLayer and Restore work together. +// 1. Move cursor to (25, 25) draw a black rect of size 25x25. +// 2. save layer, move the cursor by (100, 100) or to point (125, 125), draw a +// red rect of size 25x25. +// 3. Restore layer, so the cursor moved back to (25, 25), move cursor by (100, +// 0) or at the point (125, 25), draw a yellow rect of size 25x25. +// (25, 25) +// +---+ +// | | +// +---+ +// (25, 125) (125, 125) +// +---+ +---+ +// | | | | +// +---+ +---+ +TEST_F(DiscardableImageMapTest, RestoreSavedTransformedLayers) { + scoped_refptr<DisplayItemList> display_list = new DisplayItemList; + PaintFlags paint; + gfx::Rect visible_rect(200, 200); + display_list->StartPaint(); + + PaintImage discardable_image1 = + CreateDiscardablePaintImage(gfx::Size(25, 25)); + PaintImage discardable_image2 = + CreateDiscardablePaintImage(gfx::Size(25, 25)); + PaintImage discardable_image3 = + CreateDiscardablePaintImage(gfx::Size(25, 25)); + display_list->push<TranslateOp>(25, 25); + display_list->push<DrawImageOp>(discardable_image1, 0.f, 0.f, nullptr); + display_list->push<SaveLayerOp>(nullptr, &paint); + display_list->push<TranslateOp>(100, 100); + display_list->push<DrawImageOp>(discardable_image2, 0.f, 0.f, nullptr); + display_list->push<RestoreOp>(); + display_list->push<TranslateOp>(0, 100); + display_list->push<DrawImageOp>(discardable_image3, 0.f, 0.f, nullptr); + display_list->EndPaintOfUnpaired(visible_rect); + display_list->Finalize(); + + display_list->GenerateDiscardableImagesMetadata(); + const DiscardableImageMap& image_map = display_list->discardable_image_map(); + std::vector<PositionScaleDrawImage> images = + GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 200, 200)); + EXPECT_EQ(3u, images.size()); + EXPECT_EQ(gfx::Rect(25, 25, 25, 25), InsetImageRects(images)[0]); + EXPECT_EQ(gfx::Rect(125, 125, 25, 25), InsetImageRects(images)[1]); + EXPECT_EQ(gfx::Rect(25, 125, 25, 25), InsetImageRects(images)[2]); +} + TEST_F(DiscardableImageMapTest, NullPaintOnSaveLayer) { gfx::Rect visible_rect(2048, 2048); FakeContentLayerClient content_layer_client; diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h index af922d371b7..bb297dc88bf 100644 --- a/chromium/cc/paint/display_item_list.h +++ b/chromium/cc/paint/display_item_list.h @@ -90,6 +90,8 @@ class CC_PAINT_EXPORT DisplayItemList return offset; } + UsageHint GetUsageHint() const { return usage_hint_; } + // Called by blink::PaintChunksToCcLayer when an effect ends, to update the // bounds of a SaveLayer[Alpha]Op which was emitted when the effect started. // This is needed because blink doesn't know the bounds when an effect starts. diff --git a/chromium/cc/paint/filter_operations.cc b/chromium/cc/paint/filter_operations.cc index 332bca8f9de..0d79dfa793f 100644 --- a/chromium/cc/paint/filter_operations.cc +++ b/chromium/cc/paint/filter_operations.cc @@ -235,7 +235,7 @@ void FilterOperations::AsValueInto( } std::string FilterOperations::ToString() const { - base::trace_event::TracedValue value; + base::trace_event::TracedValue value(0, /*force_json=*/true); value.BeginArray("FilterOperations"); AsValueInto(&value); value.EndArray(); diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc index 5939e789bb8..7041d9d8487 100644 --- a/chromium/cc/paint/image_transfer_cache_entry.cc +++ b/chromium/cc/paint/image_transfer_cache_entry.cc @@ -174,6 +174,7 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry( safe_size += sizeof(uint32_t); // height safe_size += sizeof(uint32_t); // has mips safe_size += sizeof(uint64_t) + align; // pixels size + alignment + safe_size += sizeof(uint64_t) + align; // row bytes + alignment safe_size += target_color_space_size + sizeof(uint64_t) + align; safe_size += pixmap_color_space_size + sizeof(uint64_t) + align; // Include 4 bytes of padding so we can always align our data pointer to a @@ -216,6 +217,7 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry( safe_size += decoded_color_space_size + align; safe_size += num_planes_ * sizeof(uint64_t); // plane widths safe_size += num_planes_ * sizeof(uint64_t); // plane heights + safe_size += num_planes_ * sizeof(uint64_t); // plane strides safe_size += num_planes_ * (sizeof(uint64_t) + align); // pixels size + alignment // Include 4 bytes of padding before each plane data chunk so we can always @@ -249,8 +251,8 @@ void ClientImageTransferCacheEntry::ValidateYUVDataBeforeSerializing() const { const SkPixmap* plane = yuv_pixmaps_->at(i); DCHECK_GT(plane->width(), 0); DCHECK_GT(plane->height(), 0); + DCHECK_GT(plane->rowBytes(), 0u); } - DCHECK(yuv_color_space_); } bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const { @@ -273,6 +275,7 @@ bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const { const SkPixmap* plane = yuv_pixmaps_->at(i); writer.Write(plane->width()); writer.Write(plane->height()); + writer.WriteSize(plane->rowBytes()); size_t plane_size = plane->computeByteSize(); if (plane_size == SIZE_MAX) return false; @@ -299,7 +302,7 @@ bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const { if (pixmap_size == SIZE_MAX) return false; writer.WriteSize(pixmap_size); - // TODO(enne): we should consider caching these in some form. + writer.WriteSize(pixmap_->rowBytes()); writer.Write(pixmap_->colorSpace()); writer.Write(target_color_space_); writer.AlignMemory(4); @@ -403,6 +406,8 @@ bool ServiceImageTransferCacheEntry::Deserialize( reader.Read(&plane_width); uint32_t plane_height = 0; reader.Read(&plane_height); + size_t plane_stride = 0; + reader.ReadSize(&plane_stride); // Because Skia does not support YUV rasterization from software planes, // we require that each pixmap fits in a GPU texture. In the // GpuImageDecodeCache, we veto YUV decoding if the planes would be too @@ -411,7 +416,8 @@ bool ServiceImageTransferCacheEntry::Deserialize( // We compute this for each plane in case a malicious renderer tries to // send very large U or V planes. fits_on_gpu_ = plane_width <= max_size && plane_height <= max_size; - if (!fits_on_gpu_ || plane_width == 0 || plane_height == 0) + if (!fits_on_gpu_ || plane_width == 0 || plane_height == 0 || + plane_stride == 0) return false; size_t plane_bytes; @@ -435,7 +441,9 @@ bool ServiceImageTransferCacheEntry::Deserialize( // are OK with this as the worst case scenario is visual corruption. SkPixmap plane_pixmap(plane_pixmap_info, const_cast<const void*>(plane_pixel_data), - plane_pixmap_info.minRowBytes()); + plane_stride); + if (plane_pixmap.computeByteSize() > plane_bytes) + return false; // Nothing should read the colorspace of individual planes because that // information is stored in image_, so we pass nullptr. @@ -478,6 +486,8 @@ bool ServiceImageTransferCacheEntry::Deserialize( has_mips_ = needs_mips; size_t pixel_size; reader.ReadSize(&pixel_size); + size_t row_bytes; + reader.ReadSize(&row_bytes); sk_sp<SkColorSpace> pixmap_color_space; reader.Read(&pixmap_color_space); sk_sp<SkColorSpace> target_color_space; @@ -488,8 +498,10 @@ bool ServiceImageTransferCacheEntry::Deserialize( SkImageInfo image_info = SkImageInfo::Make( width, height, color_type, kPremul_SkAlphaType, pixmap_color_space); - if (image_info.computeMinByteSize() > pixel_size) + if (row_bytes < image_info.minRowBytes() || + image_info.computeByteSize(row_bytes) > pixel_size) { return false; + } // Align data to a 4-byte boundry, to match what we did when writing. reader.AlignMemory(4); @@ -505,8 +517,7 @@ bool ServiceImageTransferCacheEntry::Deserialize( // Const-cast away the "volatile" on |pixel_data|. We specifically understand // that a malicious caller may change our pixels under us, and are OK with // this as the worst case scenario is visual corruption. - SkPixmap pixmap(image_info, const_cast<const void*>(pixel_data), - image_info.minRowBytes()); + SkPixmap pixmap(image_info, const_cast<const void*>(pixel_data), row_bytes); image_ = MakeSkImage(pixmap, width, height, target_color_space); if (image_) { @@ -537,6 +548,8 @@ sk_sp<SkImage> ServiceImageTransferCacheEntry::MakeSkImage( image = MakeTextureImage(context_, std::move(image), target_color_space, has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo); } else { + // If the image is on the CPU, no work is needed to generate mips. + has_mips_ = true; sk_sp<SkImage> original = SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr); if (!original) @@ -571,6 +584,7 @@ void ServiceImageTransferCacheEntry::EnsureMips() { if (has_mips_) return; + DCHECK(fits_on_gpu_); if (is_yuv()) { DCHECK(image_); DCHECK(yuv_color_space_.has_value()); diff --git a/chromium/cc/paint/image_transfer_cache_entry.h b/chromium/cc/paint/image_transfer_cache_entry.h index f4975a5c16e..12eb917e91c 100644 --- a/chromium/cc/paint/image_transfer_cache_entry.h +++ b/chromium/cc/paint/image_transfer_cache_entry.h @@ -132,6 +132,7 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry // Ensures the cached image has mips. void EnsureMips(); + bool has_mips() const { return has_mips_; } // Used in tests and for registering each texture for memory dumps. const sk_sp<SkImage>& GetPlaneImage(size_t index) const; diff --git a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc index ac1819daf31..4c03a544e4f 100644 --- a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc +++ b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc @@ -46,9 +46,10 @@ void MarkTextureAsReleased(SkImage::ReleaseContext context) { *released = true; } -// Checks if all the pixels in |image| are |expected_color|. -bool CheckImageIsSolidColor(const sk_sp<SkImage>& image, - SkColor expected_color) { +// Checks if all the pixels in the |subset| of |image| are |expected_color|. +bool CheckRectIsSolidColor(const sk_sp<SkImage>& image, + SkColor expected_color, + const SkIRect& subset) { DCHECK_GE(image->width(), 1); DCHECK_GE(image->height(), 1); SkBitmap bitmap; @@ -59,8 +60,8 @@ bool CheckImageIsSolidColor(const sk_sp<SkImage>& image, return false; if (!image->readPixels(pixmap, 0 /* srcX */, 0 /* srcY */)) return false; - for (int y = 0; y < image->height(); y++) { - for (int x = 0; x < image->width(); x++) { + for (int y = subset.fTop; y < subset.fBottom; y++) { + for (int x = subset.fLeft; x < subset.fRight; x++) { if (bitmap.getColor(x, y) != expected_color) return false; } @@ -68,6 +69,13 @@ bool CheckImageIsSolidColor(const sk_sp<SkImage>& image, return true; } +// Checks if all the pixels in |image| are |expected_color|. +bool CheckImageIsSolidColor(const sk_sp<SkImage>& image, + SkColor expected_color) { + return CheckRectIsSolidColor( + image, expected_color, SkIRect::MakeWH(image->width(), image->height())); +} + class ImageTransferCacheEntryTest : public testing::TestWithParam<YUVDecodeFormat> { public: @@ -196,8 +204,77 @@ class ImageTransferCacheEntryTest scoped_refptr<gl::GLShareGroup> share_group_; scoped_refptr<gl::GLContext> gl_context_; sk_sp<GrContext> gr_context_; + gl::DisableNullDrawGLBindings enable_pixel_output_; }; +TEST_P(ImageTransferCacheEntryTest, Deserialize) { +#if defined(OS_ANDROID) + // TODO(crbug.com/985458): this test is failing on Android for NV12 and we + // don't understand why yet. Revisit this once Skia supports an RG8 + // SkColorType. + if (GetParam() == YUVDecodeFormat::kYUV2) + return; +#endif + + // Create a client-side entry from YUV planes. Use a different stride than the + // width to test that alignment works correctly. + const int image_width = 12; + const int image_height = 10; + const size_t y_stride = 16; + const size_t uv_stride = 8; + + const size_t y_bytes = y_stride * image_height; + const size_t uv_bytes = uv_stride * image_height / 2; + const size_t planes_size = y_bytes + 2 * uv_bytes; + std::unique_ptr<char[]> planes_data(new char[planes_size]); + + void* planes[3]; + planes[0] = reinterpret_cast<void*>(planes_data.get()); + planes[1] = ((char*)planes[0]) + y_bytes; + planes[2] = ((char*)planes[1]) + uv_bytes; + + auto info = SkImageInfo::Make(image_width, image_height, kGray_8_SkColorType, + kUnknown_SkAlphaType); + SkPixmap y_pixmap(info, planes[0], y_stride); + SkPixmap u_pixmap(info.makeWH(image_width / 2, image_height / 2), planes[1], + uv_stride); + SkPixmap v_pixmap(info.makeWH(image_width / 2, image_height / 2), planes[2], + uv_stride); + + // rgb (255, 121, 255) -> yuv (255, 255, 255) + const SkIRect bottom_color_rect = + SkIRect::MakeXYWH(0, image_height / 2, image_width, image_height / 2); + ASSERT_TRUE(y_pixmap.erase(SkColors::kWhite)); + ASSERT_TRUE(u_pixmap.erase(SkColors::kWhite)); + ASSERT_TRUE(v_pixmap.erase(SkColors::kWhite)); + // rgb (178, 0, 225) -> yuv (0, 255, 255) + const SkIRect top_color_rect = SkIRect::MakeWH(image_width, image_height / 2); + ASSERT_TRUE(y_pixmap.erase(SkColors::kBlack, &top_color_rect)); + + auto client_entry(std::make_unique<ClientImageTransferCacheEntry>( + &y_pixmap, &u_pixmap, &v_pixmap, nullptr, kJpegYUVColorSpace, + true /* needs_mips */)); + uint32_t size = client_entry->SerializedSize(); + std::vector<uint8_t> data(size); + ASSERT_TRUE(client_entry->Serialize( + base::make_span(static_cast<uint8_t*>(data.data()), size))); + + // Create service-side entry from the client-side serialize info + auto entry(std::make_unique<ServiceImageTransferCacheEntry>()); + ASSERT_TRUE(entry->Deserialize( + gr_context(), base::make_span(static_cast<uint8_t*>(data.data()), size))); + ASSERT_TRUE(entry->is_yuv()); + + // Check color of pixels + ASSERT_TRUE(CheckRectIsSolidColor(entry->image(), SkColorSetRGB(178, 0, 225), + top_color_rect)); + ASSERT_TRUE(CheckRectIsSolidColor( + entry->image(), SkColorSetRGB(255, 121, 255), bottom_color_rect)); + + client_entry.reset(); + entry.reset(); +} + TEST_P(ImageTransferCacheEntryTest, HardwareDecodedNoMipsAtCreation) { std::unique_ptr<bool[]> release_flags; std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags); @@ -320,12 +397,64 @@ std::string TestParamToString( } } -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, ImageTransferCacheEntryTest, ::testing::Values(YUVDecodeFormat::kYUV3, YUVDecodeFormat::kYVU3, YUVDecodeFormat::kYUV2), TestParamToString); +TEST(ImageTransferCacheEntryTestNoYUV, CPUImageWithMips) { + GrMockOptions options; + auto gr_context = GrContext::MakeMock(&options); + + SkBitmap bitmap; + bitmap.allocPixels( + SkImageInfo::MakeN32Premul(gr_context->maxTextureSize() + 1, 10)); + ClientImageTransferCacheEntry client_entry(&bitmap.pixmap(), nullptr, true); + std::vector<uint8_t> storage(client_entry.SerializedSize()); + client_entry.Serialize(base::make_span(storage.data(), storage.size())); + + ServiceImageTransferCacheEntry service_entry; + service_entry.Deserialize(gr_context.get(), + base::make_span(storage.data(), storage.size())); + ASSERT_TRUE(service_entry.image()); + auto pre_mip_image = service_entry.image(); + EXPECT_FALSE(pre_mip_image->isTextureBacked()); + EXPECT_TRUE(service_entry.has_mips()); + + service_entry.EnsureMips(); + ASSERT_TRUE(service_entry.image()); + EXPECT_FALSE(service_entry.image()->isTextureBacked()); + EXPECT_TRUE(service_entry.has_mips()); + EXPECT_EQ(pre_mip_image, service_entry.image()); +} + +TEST(ImageTransferCacheEntryTestNoYUV, CPUImageAddMipsLater) { + GrMockOptions options; + auto gr_context = GrContext::MakeMock(&options); + + SkBitmap bitmap; + bitmap.allocPixels( + SkImageInfo::MakeN32Premul(gr_context->maxTextureSize() + 1, 10)); + ClientImageTransferCacheEntry client_entry(&bitmap.pixmap(), nullptr, false); + std::vector<uint8_t> storage(client_entry.SerializedSize()); + client_entry.Serialize(base::make_span(storage.data(), storage.size())); + + ServiceImageTransferCacheEntry service_entry; + service_entry.Deserialize(gr_context.get(), + base::make_span(storage.data(), storage.size())); + ASSERT_TRUE(service_entry.image()); + auto pre_mip_image = service_entry.image(); + EXPECT_FALSE(pre_mip_image->isTextureBacked()); + EXPECT_TRUE(service_entry.has_mips()); + + service_entry.EnsureMips(); + ASSERT_TRUE(service_entry.image()); + EXPECT_FALSE(service_entry.image()->isTextureBacked()); + EXPECT_TRUE(service_entry.has_mips()); + EXPECT_EQ(pre_mip_image, service_entry.image()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h index 32918efd58a..31a736d7dc3 100644 --- a/chromium/cc/paint/paint_canvas.h +++ b/chromium/cc/paint/paint_canvas.h @@ -18,6 +18,10 @@ namespace printing { class MetafileSkia; } // namespace printing +namespace paint_preview { +class PaintPreviewTracker; +} // namespace paint_preview + namespace cc { class SkottieWrapper; class PaintFlags; @@ -191,12 +195,19 @@ class CC_PAINT_EXPORT PaintCanvas { void SetPrintingMetafile(printing::MetafileSkia* metafile) { metafile_ = metafile; } + paint_preview::PaintPreviewTracker* GetPaintPreviewTracker() const { + return tracker_; + } + void SetPaintPreviewTracker(paint_preview::PaintPreviewTracker* tracker) { + tracker_ = tracker; + } // Subclasses can override to handle custom data. virtual void recordCustomData(uint32_t id) {} private: printing::MetafileSkia* metafile_ = nullptr; + paint_preview::PaintPreviewTracker* tracker_ = nullptr; }; class CC_PAINT_EXPORT PaintCanvasAutoRestore { diff --git a/chromium/cc/paint/paint_image.cc b/chromium/cc/paint/paint_image.cc index c601c016c78..f9b3d0e0798 100644 --- a/chromium/cc/paint/paint_image.cc +++ b/chromium/cc/paint/paint_image.cc @@ -193,19 +193,17 @@ bool PaintImage::Decode(void* memory, client_id); } -bool PaintImage::DecodeYuv(void* planes[SkYUVASizeInfo::kMaxCount], - size_t frame_index, - GeneratorClientId client_id, - const SkYUVASizeInfo& yuva_size_info) const { - SkYUVAIndex indices[SkYUVAIndex::kIndexCount]; - // Passing nullptr for the SkYUVASizeInfo forces IsYuv to create and fill out - // a temporary object instead because |yuva_size_info| is const. - bool is_yuv = IsYuv(nullptr, indices); - DCHECK(is_yuv); +bool PaintImage::DecodeYuv( + void* planes[SkYUVASizeInfo::kMaxCount], + size_t frame_index, + GeneratorClientId client_id, + const SkYUVASizeInfo& yuva_size_info, + SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount]) const { + DCHECK(plane_indices != nullptr); DCHECK(CanDecodeFromGenerator()); const uint32_t lazy_pixel_ref = unique_id(); - return paint_image_generator_->GetYUVA8Planes(yuva_size_info, indices, planes, - frame_index, lazy_pixel_ref); + return paint_image_generator_->GetYUVA8Planes( + yuva_size_info, plane_indices, planes, frame_index, lazy_pixel_ref); } bool PaintImage::DecodeFromGenerator(void* memory, diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h index df01c1086f9..00c74fcc1f3 100644 --- a/chromium/cc/paint/paint_image.h +++ b/chromium/cc/paint/paint_image.h @@ -51,6 +51,7 @@ struct CC_PAINT_EXPORT ImageHeaderMetadata { // The size of the area containing coded data, if known. For example, if the // |image_size| for a 4:2:0 JPEG is 12x31, its coded size should be 16x32 // because the size of a minimum-coded unit for 4:2:0 is 16x16. + // A zero-initialized |coded_size| indicates an invalid image. base::Optional<gfx::Size> coded_size; // Whether the image embeds an ICC color profile. @@ -218,10 +219,14 @@ class CC_PAINT_EXPORT PaintImage { // - The |frame_index| parameter will be passed along to // ImageDecoder::DecodeToYUV but for multi-frame YUV support, ImageDecoder // needs a separate YUV frame buffer cache. + // - The mapping of source planes to channels is tracked by |plane_indices|. + // This struct is initialized by QueryYUVA8 in calls to + // PaintImage::IsYuv(), including within this method. bool DecodeYuv(void* planes[SkYUVASizeInfo::kMaxCount], size_t frame_index, GeneratorClientId client_id, - const SkYUVASizeInfo& yuva_size_info) const; + const SkYUVASizeInfo& yuva_size_info, + SkYUVAIndex* plane_indices) const; Id stable_id() const { return id_; } const sk_sp<SkImage>& GetSkImage() const; diff --git a/chromium/cc/paint/paint_image_unittest.cc b/chromium/cc/paint/paint_image_unittest.cc index bc1a06d80ac..3837d80ef2a 100644 --- a/chromium/cc/paint/paint_image_unittest.cc +++ b/chromium/cc/paint/paint_image_unittest.cc @@ -150,8 +150,10 @@ TEST(PaintImageTest, DecodeToYuv420NoAlpha) { ASSERT_TRUE(image.IsYuv(&image_yuv_size_info, image_plane_indices)); ASSERT_EQ(yuva_size_info, image_yuv_size_info); + SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount]; image.DecodeYuv(planes, 1u /* frame_index */, - PaintImage::kDefaultGeneratorClientId, yuva_size_info); + PaintImage::kDefaultGeneratorClientId, yuva_size_info, + plane_indices); ASSERT_EQ(yuv_generator->frames_decoded().size(), 1u); EXPECT_EQ(yuv_generator->frames_decoded().count(1u), 1u); yuv_generator->reset_frames_decoded(); diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc index 02915f75f95..20afc9bc84f 100644 --- a/chromium/cc/paint/paint_op_buffer.cc +++ b/chromium/cc/paint/paint_op_buffer.cc @@ -2480,14 +2480,10 @@ void PaintOpBuffer::Playback(SkCanvas* canvas, } } -sk_sp<PaintOpBuffer> PaintOpBuffer::MakeFromMemory( - const volatile void* input, - size_t input_size, - const PaintOp::DeserializeOptions& options) { - auto buffer = sk_make_sp<PaintOpBuffer>(); - if (input_size == 0) - return buffer; - +bool PaintOpBuffer::Deserialize(const volatile void* input, + size_t input_size, + const PaintOp::DeserializeOptions& options) { + Reset(); size_t total_bytes_read = 0u; while (total_bytes_read < input_size) { const volatile void* next_op = @@ -2497,26 +2493,39 @@ sk_sp<PaintOpBuffer> PaintOpBuffer::MakeFromMemory( uint32_t skip; if (!PaintOpReader::ReadAndValidateOpHeader( next_op, input_size - total_bytes_read, &type, &skip)) { - return nullptr; + return false; } size_t op_skip = ComputeOpSkip(g_type_to_size[type]); const auto* op = g_deserialize_functions[type]( - next_op, skip, buffer->AllocatePaintOp(op_skip), op_skip, options); + next_op, skip, AllocatePaintOp(op_skip), op_skip, options); if (!op) { // The last allocated op has already been destroyed if it failed to // deserialize. Update the buffer's op tracking to exclude it to avoid // access during cleanup at destruction. - buffer->used_ -= op_skip; - buffer->op_count_--; - return nullptr; + used_ -= op_skip; + op_count_--; + return false; } - g_analyze_op_functions[type](buffer.get(), op); + g_analyze_op_functions[type](this, op); total_bytes_read += skip; } - DCHECK_GT(buffer->size(), 0u); + DCHECK_GT(size(), 0u); + return true; +} + +// static +sk_sp<PaintOpBuffer> PaintOpBuffer::MakeFromMemory( + const volatile void* input, + size_t input_size, + const PaintOp::DeserializeOptions& options) { + auto buffer = sk_make_sp<PaintOpBuffer>(); + if (input_size == 0) + return buffer; + if (!buffer->Deserialize(input, input_size, options)) + return nullptr; return buffer; } diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h index 11615ac3697..cd3ac1c50ca 100644 --- a/chromium/cc/paint/paint_op_buffer.h +++ b/chromium/cc/paint/paint_op_buffer.h @@ -937,6 +937,12 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { void Playback(SkCanvas* canvas) const; void Playback(SkCanvas* canvas, const PlaybackParams& params) const; + // Deserialize PaintOps from |input|. The original content will be + // overwritten. + bool Deserialize(const volatile void* input, + size_t input_size, + const PaintOp::DeserializeOptions& options); + static sk_sp<PaintOpBuffer> MakeFromMemory( const volatile void* input, size_t input_size, @@ -949,6 +955,8 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { size_t bytes_used() const { return sizeof(*this) + reserved_ + subrecord_bytes_used_; } + // Returns the number of bytes used by paint ops. + size_t paint_ops_size() const { return used_ + subrecord_bytes_used_; } // Returns the total number of ops including sub-records. size_t total_op_count() const { return op_count_ + subrecord_op_count_; } diff --git a/chromium/cc/paint/paint_recorder.h b/chromium/cc/paint/paint_recorder.h index 58b26fa3fb5..4dce74a70e2 100644 --- a/chromium/cc/paint/paint_recorder.h +++ b/chromium/cc/paint/paint_recorder.h @@ -30,7 +30,7 @@ class CC_PAINT_EXPORT PaintRecorder { return beginRecording(SkRect::MakeWH(width, height)); } - // Only valid between between and finish recording. + // Only valid while recording. ALWAYS_INLINE RecordPaintCanvas* getRecordingCanvas() { return canvas_.has_value() ? &canvas_.value() : nullptr; } diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc index db625272e7c..a2bbd75c2c9 100644 --- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc +++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc @@ -99,7 +99,10 @@ std::unique_ptr<RasterBuffer> BitmapRasterBufferProvider::AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) { DCHECK_EQ(resource.format(), viz::RGBA_8888); const gfx::Size& size = resource.size(); diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.h b/chromium/cc/raster/bitmap_raster_buffer_provider.h index bdf1fc8d06d..b8c18b6c428 100644 --- a/chromium/cc/raster/bitmap_raster_buffer_provider.h +++ b/chromium/cc/raster/bitmap_raster_buffer_provider.h @@ -33,7 +33,10 @@ class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider { std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override; + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; bool IsResourcePremultiplied() const override; diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc index cbe878b7e1c..ae560bafe01 100644 --- a/chromium/cc/raster/gpu_raster_buffer_provider.cc +++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc @@ -31,7 +31,6 @@ #include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/common/shared_image_trace_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" -#include "third_party/skia/include/core/SkMultiPictureDraw.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrContext.h" @@ -128,8 +127,7 @@ static void RasterizeSourceOOP( const gfx::Rect& playback_rect, const gfx::AxisTransform2d& transform, const RasterSource::PlaybackSettings& playback_settings, - viz::RasterContextProvider* context_provider, - int msaa_sample_count) { + viz::RasterContextProvider* context_provider) { gpu::raster::RasterInterface* ri = context_provider->RasterInterface(); if (mailbox->IsZero()) { DCHECK(!sync_token.HasData()); @@ -146,9 +144,9 @@ static void RasterizeSourceOOP( ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); } - ri->BeginRasterCHROMIUM(raster_source->background_color(), msaa_sample_count, - playback_settings.use_lcd_text, color_space, - mailbox->name); + ri->BeginRasterCHROMIUM( + raster_source->background_color(), 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()); @@ -183,7 +181,6 @@ static void RasterizeSource( const gfx::AxisTransform2d& transform, const RasterSource::PlaybackSettings& playback_settings, viz::RasterContextProvider* context_provider, - int msaa_sample_count, bool unpremultiply_and_dither, const gfx::Size& max_tile_size) { gpu::raster::RasterInterface* ri = context_provider->RasterInterface(); @@ -203,7 +200,9 @@ static void RasterizeSource( // valid by the time the consume command executes. ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); } - GLuint texture_id = ri->CreateAndConsumeForGpuRaster(mailbox->name); + GLuint texture_id = ri->CreateAndConsumeForGpuRaster(*mailbox); + ri->BeginSharedImageAccessDirectCHROMIUM( + texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); { ScopedGrContextAccess gr_context_access(context_provider); base::Optional<viz::ClientResourceProvider::ScopedSkSurface> scoped_surface; @@ -215,13 +214,13 @@ static void RasterizeSource( scoped_surface.emplace(context_provider->GrContext(), sk_color_space, texture_id, texture_target, resource_size, resource_format, playback_settings.use_lcd_text, - msaa_sample_count); + playback_settings.msaa_sample_count); surface = scoped_surface->surface(); } else { scoped_dither_surface.emplace( context_provider, sk_color_space, playback_rect, raster_full_rect, max_tile_size, texture_id, resource_size, - playback_settings.use_lcd_text, msaa_sample_count); + playback_settings.use_lcd_text, playback_settings.msaa_sample_count); surface = scoped_dither_surface->surface(); } @@ -243,7 +242,7 @@ static void RasterizeSource( playback_rect, transform, playback_settings); } - + ri->EndSharedImageAccessDirectCHROMIUM(texture_id); ri->DeleteGpuRasterTexture(texture_id); } @@ -285,13 +284,21 @@ GpuRasterBufferProvider::RasterBufferImpl::RasterBufferImpl( GpuRasterBufferProvider* client, const ResourcePool::InUsePoolResource& in_use_resource, GpuRasterBacking* backing, - bool resource_has_previous_content) + bool resource_has_previous_content, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) : client_(client), backing_(backing), resource_size_(in_use_resource.size()), resource_format_(in_use_resource.format()), color_space_(in_use_resource.color_space()), resource_has_previous_content_(resource_has_previous_content), + depends_on_at_raster_decodes_(depends_on_at_raster_decodes), + depends_on_hardware_accelerated_jpeg_candidates_( + depends_on_hardware_accelerated_jpeg_candidates), + depends_on_hardware_accelerated_webp_candidates_( + depends_on_hardware_accelerated_webp_candidates), before_raster_sync_token_(backing->returned_sync_token), texture_target_(backing->texture_target), texture_is_overlay_candidate_(backing->overlay_candidate), @@ -339,14 +346,15 @@ void GpuRasterBufferProvider::RasterBufferImpl::Playback( before_raster_sync_token_, resource_size_, resource_format_, color_space_, resource_has_previous_content_, raster_source, raster_full_rect, raster_dirty_rect, new_content_id, transform, playback_settings, url, - creation_time_); + creation_time_, depends_on_at_raster_decodes_, + depends_on_hardware_accelerated_jpeg_candidates_, + depends_on_hardware_accelerated_webp_candidates_); } GpuRasterBufferProvider::GpuRasterBufferProvider( viz::ContextProvider* compositor_context_provider, viz::RasterContextProvider* worker_context_provider, bool use_gpu_memory_buffer_resources, - int gpu_rasterization_msaa_sample_count, viz::ResourceFormat tile_format, const gfx::Size& max_tile_size, bool unpremultiply_and_dither_low_bit_depth_tiles, @@ -355,7 +363,6 @@ GpuRasterBufferProvider::GpuRasterBufferProvider( : compositor_context_provider_(compositor_context_provider), worker_context_provider_(worker_context_provider), use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources), - msaa_sample_count_(gpu_rasterization_msaa_sample_count), tile_format_(tile_format), max_tile_size_(max_tile_size), unpremultiply_and_dither_low_bit_depth_tiles_( @@ -373,7 +380,10 @@ GpuRasterBufferProvider::~GpuRasterBufferProvider() { std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) { if (!resource.gpu_backing()) { auto backing = std::make_unique<GpuRasterBacking>(); backing->worker_context_provider = worker_context_provider_; @@ -386,8 +396,11 @@ std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster( static_cast<GpuRasterBacking*>(resource.gpu_backing()); bool resource_has_previous_content = resource_content_id && resource_content_id == previous_content_id; - return std::make_unique<RasterBufferImpl>(this, resource, backing, - resource_has_previous_content); + return std::make_unique<RasterBufferImpl>( + this, resource, backing, resource_has_previous_content, + depends_on_at_raster_decodes, + depends_on_hardware_accelerated_jpeg_candidates, + depends_on_hardware_accelerated_webp_candidates); } void GpuRasterBufferProvider::Flush() { @@ -402,13 +415,6 @@ bool GpuRasterBufferProvider::IsResourcePremultiplied() const { return !ShouldUnpremultiplyAndDitherResource(GetResourceFormat()); } -bool GpuRasterBufferProvider::CanPartialRasterIntoProvidedResource() const { - // Partial raster doesn't support MSAA, as the MSAA resolve is unaware of clip - // rects. - // TODO(crbug.com/629683): See if we can work around this limitation. - return msaa_sample_count_ == 0; -} - bool GpuRasterBufferProvider::IsResourceReadyToDraw( const ResourcePool::InUsePoolResource& resource) const { const gpu::SyncToken& sync_token = resource.gpu_backing()->mailbox_sync_token; @@ -421,6 +427,10 @@ bool GpuRasterBufferProvider::IsResourceReadyToDraw( sync_token); } +bool GpuRasterBufferProvider::CanPartialRasterIntoProvidedResource() const { + return true; +} + uint64_t GpuRasterBufferProvider::SetReadyToDrawCallback( const std::vector<const ResourcePool::InUsePoolResource*>& resources, base::OnceClosure callback, @@ -467,14 +477,21 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThread( const gfx::AxisTransform2d& transform, const RasterSource::PlaybackSettings& playback_settings, const GURL& url, - base::TimeTicks raster_buffer_creation_time) { + base::TimeTicks raster_buffer_creation_time, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) { PendingRasterQuery query; + query.depends_on_hardware_accelerated_jpeg_candidates = + depends_on_hardware_accelerated_jpeg_candidates; + query.depends_on_hardware_accelerated_webp_candidates = + depends_on_hardware_accelerated_webp_candidates; gpu::SyncToken raster_finished_token = PlaybackOnWorkerThreadInternal( mailbox, texture_target, texture_is_overlay_candidate, sync_token, resource_size, resource_format, color_space, resource_has_previous_content, raster_source, raster_full_rect, raster_dirty_rect, new_content_id, transform, playback_settings, url, - &query); + depends_on_at_raster_decodes, &query); if (query.raster_duration_query_id) { if (query.raster_start_query_id) @@ -508,6 +525,7 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal( const gfx::AxisTransform2d& transform, const RasterSource::PlaybackSettings& playback_settings, const GURL& url, + bool depends_on_at_raster_decodes, PendingRasterQuery* query) { viz::RasterContextProvider::ScopedRasterContextLock scoped_context( worker_context_provider_, url.possibly_invalid_spec().c_str()); @@ -545,8 +563,11 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal( // enabled because we will use this timestamp to measure raster scheduling // delay and we only need to collect that data to assess the impact of // hardware acceleration of image decodes which work only in Chrome OS with - // OOP-R. - if (enable_oop_rasterization_) { + // OOP-R. Furthermore, we don't count raster work that depends on at-raster + // image decodes. This is because we want the delay to always include + // image decoding and uploading time, and at-raster decodes should be + // relatively rare. + if (enable_oop_rasterization_ && !depends_on_at_raster_decodes) { ri->GenQueriesEXT(1, &query->raster_start_query_id); DCHECK_GT(query->raster_start_query_id, 0u); ri->QueryCounterEXT(query->raster_start_query_id, @@ -566,19 +587,17 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal( if (measure_raster_metric) timer.emplace(); if (enable_oop_rasterization_) { - RasterizeSourceOOP(raster_source, resource_has_previous_content, mailbox, - sync_token, texture_target, - texture_is_overlay_candidate, resource_size, - resource_format, color_space, raster_full_rect, - playback_rect, transform, playback_settings, - worker_context_provider_, msaa_sample_count_); + RasterizeSourceOOP( + raster_source, resource_has_previous_content, mailbox, sync_token, + texture_target, texture_is_overlay_candidate, resource_size, + resource_format, color_space, raster_full_rect, playback_rect, + transform, playback_settings, worker_context_provider_); } else { RasterizeSource(raster_source, resource_has_previous_content, mailbox, sync_token, texture_target, texture_is_overlay_candidate, resource_size, resource_format, color_space, raster_full_rect, playback_rect, transform, playback_settings, worker_context_provider_, - msaa_sample_count_, ShouldUnpremultiplyAndDitherResource(resource_format), max_tile_size_); } @@ -671,9 +690,26 @@ bool GpuRasterBufferProvider::CheckRasterFinishedQueries() { // negative scheduling delay. DCHECK_GE(raster_scheduling_delay.InMicroseconds(), 0u); UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( - base::StringPrintf("Renderer4.%s.RasterTaskSchedulingDelay.All", - client_name), + base::StringPrintf( + "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes.All", + client_name), raster_scheduling_delay); + if (it->depends_on_hardware_accelerated_jpeg_candidates) { + UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( + base::StringPrintf( + "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes." + "TilesWithJpegHwDecodeCandidates", + client_name), + raster_scheduling_delay); + } + if (it->depends_on_hardware_accelerated_webp_candidates) { + UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( + base::StringPrintf( + "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes." + "TilesWithWebPHwDecodeCandidates", + client_name), + raster_scheduling_delay); + } } if (enable_oop_rasterization_) { diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h index 2f54037b443..4a442a3b6a1 100644 --- a/chromium/cc/raster/gpu_raster_buffer_provider.h +++ b/chromium/cc/raster/gpu_raster_buffer_provider.h @@ -32,7 +32,6 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { viz::ContextProvider* compositor_context_provider, viz::RasterContextProvider* worker_context_provider, bool use_gpu_memory_buffer_resources, - int gpu_rasterization_msaa_sample_count, viz::ResourceFormat tile_format, const gfx::Size& max_tile_size, bool unpremultiply_and_dither_low_bit_depth_tiles, @@ -47,7 +46,10 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override; + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; bool IsResourcePremultiplied() const override; @@ -77,7 +79,10 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { const gfx::AxisTransform2d& transform, const RasterSource::PlaybackSettings& playback_settings, const GURL& url, - base::TimeTicks raster_buffer_creation_time); + base::TimeTicks raster_buffer_creation_time, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates); private: class GpuRasterBacking; @@ -87,7 +92,10 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { RasterBufferImpl(GpuRasterBufferProvider* client, const ResourcePool::InUsePoolResource& in_use_resource, GpuRasterBacking* backing, - bool resource_has_previous_content); + bool resource_has_previous_content, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates); RasterBufferImpl(const RasterBufferImpl&) = delete; ~RasterBufferImpl() override; @@ -112,6 +120,9 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { const viz::ResourceFormat resource_format_; const gfx::ColorSpace color_space_; const bool resource_has_previous_content_; + const bool depends_on_at_raster_decodes_; + const bool depends_on_hardware_accelerated_jpeg_candidates_; + const bool depends_on_hardware_accelerated_webp_candidates_; const gpu::SyncToken before_raster_sync_token_; const GLenum texture_target_; const bool texture_is_overlay_candidate_; @@ -137,6 +148,11 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { // The time at which the raster buffer was created. base::TimeTicks raster_buffer_creation_time; + + // Whether the raster work depends on candidates for hardware accelerated + // JPEG or WebP decodes. + bool depends_on_hardware_accelerated_jpeg_candidates = false; + bool depends_on_hardware_accelerated_webp_candidates = false; }; bool ShouldUnpremultiplyAndDitherResource(viz::ResourceFormat format) const; @@ -156,12 +172,12 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { const gfx::AxisTransform2d& transform, const RasterSource::PlaybackSettings& playback_settings, const GURL& url, + bool depends_on_at_raster_decodes, PendingRasterQuery* query); viz::ContextProvider* const compositor_context_provider_; viz::RasterContextProvider* const worker_context_provider_; const bool use_gpu_memory_buffer_resources_; - const int msaa_sample_count_; const viz::ResourceFormat tile_format_; const gfx::Size max_tile_size_; const bool unpremultiply_and_dither_low_bit_depth_tiles_; diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc index 6a40f4e513e..6c0c9d9e0b1 100644 --- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc @@ -159,7 +159,10 @@ std::unique_ptr<RasterBuffer> OneCopyRasterBufferProvider::AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) { if (!resource.gpu_backing()) { auto backing = std::make_unique<OneCopyGpuBacking>(); backing->worker_context_provider = worker_context_provider_; @@ -377,21 +380,20 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread( } if (mailbox->IsZero()) { - uint32_t flags = + uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_RASTER; if (mailbox_texture_is_overlay_candidate) - flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; + usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT; *mailbox = sii->CreateSharedImage(resource_format, resource_size, - color_space, flags); + color_space, usage); } // Create staging shared image. if (staging_buffer->mailbox.IsZero()) { - uint32_t flags = - gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_RASTER; + const uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER; staging_buffer->mailbox = sii->CreateSharedImage(staging_buffer->gpu_memory_buffer.get(), - gpu_memory_buffer_manager_, color_space, flags); + gpu_memory_buffer_manager_, color_space, usage); } else { sii->UpdateSharedImage(staging_buffer->sync_token, staging_buffer->mailbox); } diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.h b/chromium/cc/raster/one_copy_raster_buffer_provider.h index 370e6cbf43c..0d2a7d0dbe7 100644 --- a/chromium/cc/raster/one_copy_raster_buffer_provider.h +++ b/chromium/cc/raster/one_copy_raster_buffer_provider.h @@ -48,7 +48,10 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider { std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override; + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; bool IsResourcePremultiplied() const override; diff --git a/chromium/cc/raster/raster_buffer_provider.h b/chromium/cc/raster/raster_buffer_provider.h index a23befca140..7b4937373ff 100644 --- a/chromium/cc/raster/raster_buffer_provider.h +++ b/chromium/cc/raster/raster_buffer_provider.h @@ -50,7 +50,10 @@ class CC_EXPORT RasterBufferProvider { virtual std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) = 0; + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) = 0; // Flush pending work from writing the content of the RasterBuffer, so that // queries to tell if the backing is ready to draw from will get the right diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc index 66391be769d..e6a0a2aa825 100644 --- a/chromium/cc/raster/raster_buffer_provider_perftest.cc +++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc @@ -202,7 +202,8 @@ class PerfRasterBufferProviderHelper { virtual std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) = 0; + uint64_t previous_content_id, + bool depends_on_at_raster_decodes) = 0; }; class PerfRasterTaskImpl : public PerfTileTask { @@ -277,7 +278,8 @@ class RasterBufferProviderPerfTestBase { // No tile ids are given to support partial updates. std::unique_ptr<RasterBuffer> raster_buffer; if (helper) - raster_buffer = helper->AcquireBufferForRaster(in_use_resource, 0, 0); + raster_buffer = + helper->AcquireBufferForRaster(in_use_resource, 0, 0, false); TileTask::Vector dependencies = image_decode_tasks; raster_tasks->push_back(new PerfRasterTaskImpl( resource_pool_.get(), std::move(in_use_resource), @@ -371,7 +373,7 @@ class RasterBufferProviderPerfTest Create3dResourceProvider(); raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>( compositor_context_provider_.get(), worker_context_provider_.get(), - false, 0, viz::RGBA_8888, gfx::Size(), true, false); + false, viz::RGBA_8888, gfx::Size(), true, false); break; case RASTER_BUFFER_PROVIDER_TYPE_BITMAP: CreateSoftwareResourceProvider(); @@ -398,9 +400,13 @@ class RasterBufferProviderPerfTest std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes) override { return raster_buffer_provider_->AcquireBufferForRaster( - resource, resource_content_id, previous_content_id); + resource, resource_content_id, previous_content_id, + depends_on_at_raster_decodes, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); } void RunMessageLoopUntilAllTasksHaveCompleted() { diff --git a/chromium/cc/raster/raster_buffer_provider_unittest.cc b/chromium/cc/raster/raster_buffer_provider_unittest.cc index 391ee0eb52d..9953e5b19aa 100644 --- a/chromium/cc/raster/raster_buffer_provider_unittest.cc +++ b/chromium/cc/raster/raster_buffer_provider_unittest.cc @@ -225,13 +225,13 @@ class RasterBufferProviderTest case RASTER_BUFFER_PROVIDER_TYPE_GPU: Create3dResourceProvider(); raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>( - context_provider_.get(), worker_context_provider_.get(), false, 0, + context_provider_.get(), worker_context_provider_.get(), false, viz::RGBA_8888, gfx::Size(), true, false, 1); break; case RASTER_BUFFER_PROVIDER_TYPE_GPU_OOPR: Create3dResourceProvider(); raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>( - context_provider_.get(), worker_context_provider_.get(), false, 0, + context_provider_.get(), worker_context_provider_.get(), false, viz::RGBA_8888, gfx::Size(), true, true, 1); break; case RASTER_BUFFER_PROVIDER_TYPE_BITMAP: @@ -289,25 +289,39 @@ class RasterBufferProviderTest return pool_->AcquireResource(size, viz::RGBA_8888, gfx::ColorSpace()); } - void AppendTask(unsigned id, const gfx::Size& size) { + void AppendTask(unsigned id, + const gfx::Size& size, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) { ResourcePool::InUsePoolResource resource = AllocateResource(size); // The raster buffer has no tile ids associated with it for partial update, // so doesn't need to provide a valid dirty rect. std::unique_ptr<RasterBuffer> raster_buffer = - raster_buffer_provider_->AcquireBufferForRaster(resource, 0, 0); + raster_buffer_provider_->AcquireBufferForRaster( + resource, 0, 0, depends_on_at_raster_decodes, + depends_on_hardware_accelerated_jpeg_candidates, + depends_on_hardware_accelerated_webp_candidates); TileTask::Vector empty; tasks_.push_back( new TestRasterTaskImpl(this, id, std::move(raster_buffer), &empty)); resources_.push_back(std::move(resource)); } - void AppendTask(unsigned id) { AppendTask(id, gfx::Size(1, 1)); } + void AppendTask(unsigned id) { + AppendTask(id, gfx::Size(1, 1), false /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); + } void AppendBlockingTask(unsigned id, base::Lock* lock) { ResourcePool::InUsePoolResource resource = AllocateResource(gfx::Size(1, 1)); std::unique_ptr<RasterBuffer> raster_buffer = - raster_buffer_provider_->AcquireBufferForRaster(resource, 0, 0); + raster_buffer_provider_->AcquireBufferForRaster( + resource, 0, 0, false /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); TileTask::Vector empty; tasks_.push_back(new BlockingTestRasterTaskImpl( this, id, std::move(raster_buffer), lock, &empty)); @@ -317,7 +331,10 @@ class RasterBufferProviderTest void AppendTaskWithResource(unsigned id, const ResourcePool::InUsePoolResource* resource) { std::unique_ptr<RasterBuffer> raster_buffer = - raster_buffer_provider_->AcquireBufferForRaster(*resource, 0, 0); + raster_buffer_provider_->AcquireBufferForRaster( + *resource, 0, 0, false /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); TileTask::Vector empty; tasks_.push_back( new TestRasterTaskImpl(this, id, std::move(raster_buffer), &empty)); @@ -571,8 +588,35 @@ TEST_P(RasterBufferProviderTest, MeasureGpuRasterDuration) { return; } - // Schedule a task. - AppendTask(0u); + // Schedule a few tasks. + constexpr gfx::Size size(1, 1); + AppendTask(0u, size, false /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(1u, size, false /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + true /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(2u, size, false /* depends_on_at_raster_decodes */, + true /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(3u, size, false /* depends_on_at_raster_decodes */, + true /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(4u, size, false /* depends_on_at_raster_decodes */, + true /* depends_on_hardware_accelerated_jpeg_candidates */, + true /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(5u, size, true /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(6u, size, true /* depends_on_at_raster_decodes */, + false /* depends_on_hardware_accelerated_jpeg_candidates */, + true /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(7u, size, true /* depends_on_at_raster_decodes */, + true /* depends_on_hardware_accelerated_jpeg_candidates */, + false /* depends_on_hardware_accelerated_webp_candidates */); + AppendTask(8u, size, true /* depends_on_at_raster_decodes */, + true /* depends_on_hardware_accelerated_jpeg_candidates */, + true /* depends_on_hardware_accelerated_webp_candidates */); ScheduleTasks(); RunMessageLoopUntilAllTasksHaveCompleted(); @@ -591,24 +635,41 @@ TEST_P(RasterBufferProviderTest, MeasureGpuRasterDuration) { std::string duration_histogram("Renderer4.Renderer.RasterTaskTotalDuration."); duration_histogram += GetParam() == RASTER_BUFFER_PROVIDER_TYPE_GPU_OOPR ? "Oop" : "Gpu"; - std::string delay_histogram( - "Renderer4.Renderer.RasterTaskSchedulingDelay.All"); + std::string delay_histogram_all_tiles( + "Renderer4.Renderer.RasterTaskSchedulingDelayNoAtRasterDecodes.All"); + std::string delay_histogram_jpeg_tiles( + "Renderer4.Renderer.RasterTaskSchedulingDelayNoAtRasterDecodes." + "TilesWithJpegHwDecodeCandidates"); + std::string delay_histogram_webp_tiles( + "Renderer4.Renderer.RasterTaskSchedulingDelayNoAtRasterDecodes." + "TilesWithWebPHwDecodeCandidates"); histogram_tester.ExpectTotalCount(duration_histogram, 0); - histogram_tester.ExpectTotalCount(delay_histogram, 0); + histogram_tester.ExpectTotalCount(delay_histogram_all_tiles, 0); + histogram_tester.ExpectTotalCount(delay_histogram_jpeg_tiles, 0); + histogram_tester.ExpectTotalCount(delay_histogram_webp_tiles, 0); bool has_pending_queries = raster_buffer_provider_->CheckRasterFinishedQueries(); EXPECT_FALSE(has_pending_queries); - histogram_tester.ExpectTotalCount(duration_histogram, 1); + histogram_tester.ExpectTotalCount(duration_histogram, 9); // Only in Chrome OS with OOP-R, we should be measuring raster scheduling - // delay. - base::HistogramBase::Count expected_delay_histogram_count = 0; + // delay (and only for tasks that don't depend on at-raster image decodes). + base::HistogramBase::Count expected_delay_histogram_all_tiles_count = 0; + base::HistogramBase::Count expected_delay_histogram_jpeg_tiles_count = 0; + base::HistogramBase::Count expected_delay_histogram_webp_tiles_count = 0; #if defined(OS_CHROMEOS) - if (GetParam() == RASTER_BUFFER_PROVIDER_TYPE_GPU_OOPR) - expected_delay_histogram_count = 1; + if (GetParam() == RASTER_BUFFER_PROVIDER_TYPE_GPU_OOPR) { + expected_delay_histogram_all_tiles_count = 5; + expected_delay_histogram_jpeg_tiles_count = 3; + expected_delay_histogram_webp_tiles_count = 2; + } #endif - histogram_tester.ExpectTotalCount(delay_histogram, - expected_delay_histogram_count); + histogram_tester.ExpectTotalCount(delay_histogram_all_tiles, + expected_delay_histogram_all_tiles_count); + histogram_tester.ExpectTotalCount(delay_histogram_jpeg_tiles, + expected_delay_histogram_jpeg_tiles_count); + histogram_tester.ExpectTotalCount(delay_histogram_webp_tiles, + expected_delay_histogram_webp_tiles_count); } INSTANTIATE_TEST_SUITE_P( diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h index bbf9f1490a4..33b3564055a 100644 --- a/chromium/cc/raster/raster_source.h +++ b/chromium/cc/raster/raster_source.h @@ -38,6 +38,9 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { // If set to true, we should use LCD text. bool use_lcd_text = true; + // Specifies the sample count if MSAA is enabled for this tile. + int msaa_sample_count = 0; + ImageProvider* image_provider = nullptr; }; diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc index ef6c2c73433..b364de68c58 100644 --- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc @@ -174,7 +174,10 @@ std::unique_ptr<RasterBuffer> ZeroCopyRasterBufferProvider::AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) { if (!resource.gpu_backing()) { auto backing = std::make_unique<ZeroCopyGpuBacking>(); const gpu::Capabilities& caps = diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.h b/chromium/cc/raster/zero_copy_raster_buffer_provider.h index 653228c7c65..e34376f4aec 100644 --- a/chromium/cc/raster/zero_copy_raster_buffer_provider.h +++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.h @@ -39,7 +39,10 @@ class CC_EXPORT ZeroCopyRasterBufferProvider : public RasterBufferProvider { std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override; + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; bool IsResourcePremultiplied() const override; diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index e169cac0f0f..ceb4d5ffd27 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -13,7 +13,6 @@ #include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/format_macros.h" -#include "base/memory/shared_memory_handle.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" diff --git a/chromium/cc/scheduler/begin_frame_tracker.cc b/chromium/cc/scheduler/begin_frame_tracker.cc index 19d106e0f1d..fe8f84012ad 100644 --- a/chromium/cc/scheduler/begin_frame_tracker.cc +++ b/chromium/cc/scheduler/begin_frame_tracker.cc @@ -4,6 +4,8 @@ #include "cc/scheduler/begin_frame_tracker.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h" + namespace cc { BeginFrameTracker::BeginFrameTracker(const base::Location& location) @@ -77,36 +79,35 @@ base::TimeDelta BeginFrameTracker::Interval() const { return interval; } -void BeginFrameTracker::AsValueInto( +void BeginFrameTracker::AsProtozeroInto( base::TimeTicks now, - base::trace_event::TracedValue* state) const { - state->SetDouble("updated_at_ms", - current_updated_at_.since_origin().InMillisecondsF()); - state->SetDouble("finished_at_ms", - current_finished_at_.since_origin().InMillisecondsF()); + perfetto::protos::pbzero::BeginImplFrameArgs* state) const { + state->set_updated_at_us(current_updated_at_.since_origin().InMicroseconds()); + state->set_finished_at_us( + current_finished_at_.since_origin().InMicroseconds()); if (HasFinished()) { - state->SetString("state", "FINISHED"); - state->BeginDictionary("current_args_"); + state->set_state( + perfetto::protos::pbzero::BeginImplFrameArgs::BEGIN_FRAME_FINISHED); + current_args_.AsProtozeroInto(state->set_current_args()); } else { - state->SetString("state", "USING"); - state->BeginDictionary("last_args_"); + state->set_state( + perfetto::protos::pbzero::BeginImplFrameArgs::BEGIN_FRAME_USING); + current_args_.AsProtozeroInto(state->set_last_args()); } - current_args_.AsValueInto(state); - state->EndDictionary(); base::TimeTicks frame_time = current_args_.frame_time; base::TimeTicks deadline = current_args_.deadline; base::TimeDelta interval = current_args_.interval; - state->BeginDictionary("major_timestamps_in_ms"); - state->SetDouble("0_interval", interval.InMillisecondsF()); - state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF()); - state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF()); - state->SetDouble("3_frame_time_to_deadline", - (deadline - frame_time).InMillisecondsF()); - state->SetDouble("4_now", now.since_origin().InMillisecondsF()); - state->SetDouble("5_frame_time", frame_time.since_origin().InMillisecondsF()); - state->SetDouble("6_deadline", deadline.since_origin().InMillisecondsF()); - state->EndDictionary(); + + auto* timestamps = state->set_timestamps_in_us(); + timestamps->set_interval_delta(interval.InMicroseconds()); + timestamps->set_now_to_deadline_delta((deadline - now).InMicroseconds()); + timestamps->set_frame_time_to_now_delta((now - frame_time).InMicroseconds()); + timestamps->set_frame_time_to_deadline_delta( + (deadline - frame_time).InMicroseconds()); + timestamps->set_now(now.since_origin().InMicroseconds()); + timestamps->set_frame_time(frame_time.since_origin().InMicroseconds()); + timestamps->set_deadline(deadline.since_origin().InMicroseconds()); } const viz::BeginFrameArgs& BeginFrameTracker::DangerousMethodCurrentOrLast() diff --git a/chromium/cc/scheduler/begin_frame_tracker.h b/chromium/cc/scheduler/begin_frame_tracker.h index e80f7383768..81c27d5a115 100644 --- a/chromium/cc/scheduler/begin_frame_tracker.h +++ b/chromium/cc/scheduler/begin_frame_tracker.h @@ -16,6 +16,13 @@ #define BEGINFRAMETRACKER_FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION("") +namespace perfetto { +namespace protos { +namespace pbzero { +class BeginImplFrameArgs; +} +} // namespace protos +} // namespace perfetto namespace cc { // Microclass to trace and check properties for correct BeginFrameArgs (BFA) @@ -68,8 +75,9 @@ class CC_EXPORT BeginFrameTracker { // any time. base::TimeDelta Interval() const; - void AsValueInto(base::TimeTicks now, - base::trace_event::TracedValue* dict) const; + void AsProtozeroInto( + base::TimeTicks now, + perfetto::protos::pbzero::BeginImplFrameArgs* dict) const; // The following methods violate principles of how viz::BeginFrameArgs should // be used. These methods should only be used when there is no other choice. diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc index 523b09c2e4f..04a285de7ee 100644 --- a/chromium/cc/scheduler/scheduler.cc +++ b/chromium/cc/scheduler/scheduler.cc @@ -13,8 +13,11 @@ #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "cc/base/devtools_instrumentation.h" +#include "cc/metrics/begin_main_frame_metrics.h" #include "cc/metrics/compositor_timing_history.h" #include "components/viz/common/frame_sinks/delay_based_time_source.h" +#include "services/tracing/public/cpp/perfetto/macros.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h" namespace cc { @@ -153,7 +156,7 @@ void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token) { } void Scheduler::DidReceiveCompositorFrameAck() { - DCHECK_GT(state_machine_.pending_submit_frames(), 0) << AsValue()->ToString(); + DCHECK_GT(state_machine_.pending_submit_frames(), 0); compositor_timing_history_->DidReceiveCompositorFrameAck(); state_machine_.DidReceiveCompositorFrameAck(); ProcessScheduledActions(); @@ -168,9 +171,10 @@ void Scheduler::SetTreePrioritiesAndScrollState( ProcessScheduledActions(); } -void Scheduler::NotifyReadyToCommit() { +void Scheduler::NotifyReadyToCommit( + std::unique_ptr<BeginMainFrameMetrics> details) { TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); - compositor_timing_history_->NotifyReadyToCommit(); + compositor_timing_history_->NotifyReadyToCommit(std::move(details)); state_machine_.NotifyReadyToCommit(); ProcessScheduledActions(); } @@ -782,8 +786,10 @@ void Scheduler::ProcessScheduledActions() { SchedulerStateMachine::Action action; do { action = state_machine_.NextAction(); - TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), - "SchedulerStateMachine", "state", AsValue()); + TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), + "SchedulerStateMachine", [this](perfetto::EventContext ctx) { + this->AsProtozeroInto(ctx.event()->set_cc_scheduler_state()); + }); base::AutoReset<SchedulerStateMachine::Action> mark_inside_action( &inside_action_, action); switch (action) { @@ -864,62 +870,47 @@ void Scheduler::ProcessScheduledActions() { StartOrStopBeginFrames(); } -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -Scheduler::AsValue() const { - auto state = std::make_unique<base::trace_event::TracedValue>(); - AsValueInto(state.get()); - return std::move(state); -} - -void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const { +void Scheduler::AsProtozeroInto( + perfetto::protos::pbzero::ChromeCompositorSchedulerState* state) const { base::TimeTicks now = Now(); - state->BeginDictionary("state_machine"); - state_machine_.AsValueInto(state); - state->EndDictionary(); - - state->SetBoolean("observing_begin_frame_source", - observing_begin_frame_source_); - state->SetBoolean("begin_impl_frame_deadline_task", - !begin_impl_frame_deadline_task_.IsCancelled()); - state->SetBoolean("pending_begin_frame_task", - !pending_begin_frame_task_.IsCancelled()); - state->SetBoolean("skipped_last_frame_missed_exceeded_deadline", - skipped_last_frame_missed_exceeded_deadline_); - state->SetBoolean("skipped_last_frame_to_reduce_latency", - skipped_last_frame_to_reduce_latency_); - state->SetString("inside_action", - SchedulerStateMachine::ActionToString(inside_action_)); - state->SetString("deadline_mode", - SchedulerStateMachine::BeginImplFrameDeadlineModeToString( - deadline_mode_)); - - state->SetDouble("deadline_ms", deadline_.since_origin().InMillisecondsF()); - state->SetDouble("deadline_scheduled_at_ms", - deadline_scheduled_at_.since_origin().InMillisecondsF()); - - state->SetDouble("now_ms", Now().since_origin().InMillisecondsF()); - state->SetDouble("now_to_deadline_ms", (deadline_ - Now()).InMillisecondsF()); - state->SetDouble("now_to_deadline_scheduled_at_ms", - (deadline_scheduled_at_ - Now()).InMillisecondsF()); - - state->BeginDictionary("begin_impl_frame_args"); - begin_impl_frame_tracker_.AsValueInto(now, state); - state->EndDictionary(); - - state->BeginDictionary("begin_frame_observer_state"); - BeginFrameObserverBase::AsValueInto(state); - state->EndDictionary(); + state_machine_.AsProtozeroInto(state->set_state_machine()); + + state->set_observing_begin_frame_source(observing_begin_frame_source_); + state->set_begin_impl_frame_deadline_task( + !begin_impl_frame_deadline_task_.IsCancelled()); + state->set_pending_begin_frame_task(!pending_begin_frame_task_.IsCancelled()); + state->set_skipped_last_frame_missed_exceeded_deadline( + skipped_last_frame_missed_exceeded_deadline_); + state->set_skipped_last_frame_to_reduce_latency( + skipped_last_frame_to_reduce_latency_); + state->set_inside_action( + SchedulerStateMachine::ActionToProtozeroEnum(inside_action_)); + state->set_deadline_mode( + SchedulerStateMachine::BeginImplFrameDeadlineModeToProtozeroEnum( + deadline_mode_)); + + state->set_deadline_us(deadline_.since_origin().InMicroseconds()); + state->set_deadline_scheduled_at_us( + deadline_scheduled_at_.since_origin().InMicroseconds()); + + state->set_now_us(Now().since_origin().InMicroseconds()); + state->set_now_to_deadline_delta_us((deadline_ - Now()).InMicroseconds()); + state->set_now_to_deadline_scheduled_at_delta_us( + (deadline_scheduled_at_ - Now()).InMicroseconds()); + + begin_impl_frame_tracker_.AsProtozeroInto(now, + state->set_begin_impl_frame_args()); + + BeginFrameObserverBase::AsProtozeroInto( + state->set_begin_frame_observer_state()); if (begin_frame_source_) { - state->BeginDictionary("begin_frame_source_state"); - begin_frame_source_->AsValueInto(state); - state->EndDictionary(); + begin_frame_source_->AsProtozeroInto(state->set_begin_frame_source_state()); } - state->BeginDictionary("compositor_timing_history"); - compositor_timing_history_->AsValueInto(state); - state->EndDictionary(); + 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 23571c15023..fe99ee0fcac 100644 --- a/chromium/cc/scheduler/scheduler.h +++ b/chromium/cc/scheduler/scheduler.h @@ -20,10 +20,14 @@ #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/frame_sinks/delay_based_time_source.h" -namespace base { -namespace trace_event { -class ConvertableToTraceFormat; +namespace perfetto { +namespace protos { +namespace pbzero { +class ChromeCompositorSchedulerState; } +} // namespace protos +} // namespace perfetto +namespace base { class SingleThreadTaskRunner; } @@ -32,7 +36,7 @@ struct FrameTimingDetails; } namespace cc { - +struct BeginMainFrameMetrics; class CompositorTimingHistory; class SchedulerClient { @@ -170,7 +174,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { // BeginMainFrame request from the compositor, and blocks the main thread // to copy the layer tree to the compositor thread. Call this method when the // main thread updates are completed to signal it is ready for the commmit. - void NotifyReadyToCommit(); + void NotifyReadyToCommit(std::unique_ptr<BeginMainFrameMetrics> details); void BeginMainFrameAborted(CommitEarlyOutReason reason); void DidCommit(); @@ -224,9 +228,8 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { // the main thread by the cc scheduler. void SetMainThreadWantsBeginMainFrameNotExpected(bool new_state); - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const; - - void AsValueInto(base::trace_event::TracedValue* state) const; + void AsProtozeroInto( + perfetto::protos::pbzero::ChromeCompositorSchedulerState* state) const; void SetVideoNeedsBeginFrames(bool video_needs_begin_frames); diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc index dbbe56848fa..042772481bd 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.cc +++ b/chromium/cc/scheduler/scheduler_state_machine.cc @@ -15,6 +15,7 @@ namespace cc { namespace { // Surfaces and CompositorTimingHistory don't support more than 1 pending swap. const int kMaxPendingSubmitFrames = 1; + } // namespace SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) @@ -22,36 +23,44 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) SchedulerStateMachine::~SchedulerStateMachine() = default; -const char* SchedulerStateMachine::LayerTreeFrameSinkStateToString( - LayerTreeFrameSinkState state) { +perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + LayerTreeFrameSinkState + SchedulerStateMachine::LayerTreeFrameSinkStateToProtozeroEnum( + LayerTreeFrameSinkState state) { + using pbzeroMajorState = + perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState; switch (state) { case LayerTreeFrameSinkState::NONE: - return "LayerTreeFrameSinkState::NONE"; + return pbzeroMajorState::LAYER_TREE_FRAME_NONE; case LayerTreeFrameSinkState::ACTIVE: - return "LayerTreeFrameSinkState::ACTIVE"; + return pbzeroMajorState::LAYER_TREE_FRAME_ACTIVE; case LayerTreeFrameSinkState::CREATING: - return "LayerTreeFrameSinkState::CREATING"; + return pbzeroMajorState::LAYER_TREE_FRAME_CREATING; case LayerTreeFrameSinkState::WAITING_FOR_FIRST_COMMIT: - return "LayerTreeFrameSinkState::WAITING_FOR_FIRST_COMMIT"; + return pbzeroMajorState::LAYER_TREE_FRAME_WAITING_FOR_FIRST_COMMIT; case LayerTreeFrameSinkState::WAITING_FOR_FIRST_ACTIVATION: - return "LayerTreeFrameSinkState::WAITING_FOR_FIRST_ACTIVATION"; + return pbzeroMajorState::LAYER_TREE_FRAME_WAITING_FOR_FIRST_ACTIVATION; } NOTREACHED(); - return "???"; + return pbzeroMajorState::LAYER_TREE_FRAME_UNSPECIFIED; } -const char* SchedulerStateMachine::BeginImplFrameStateToString( - BeginImplFrameState state) { +perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + BeginImplFrameState + SchedulerStateMachine::BeginImplFrameStateToProtozeroEnum( + BeginImplFrameState state) { + using pbzeroMajorState = + perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState; switch (state) { case BeginImplFrameState::IDLE: - return "BeginImplFrameState::IDLE"; + return pbzeroMajorState::BEGIN_IMPL_FRAME_IDLE; case BeginImplFrameState::INSIDE_BEGIN_FRAME: - return "BeginImplFrameState::INSIDE_BEGIN_FRAME"; + return pbzeroMajorState::BEGIN_IMPL_FRAME_INSIDE_BEGIN_FRAME; case BeginImplFrameState::INSIDE_DEADLINE: - return "BeginImplFrameState::INSIDE_DEADLINE"; + return pbzeroMajorState::BEGIN_IMPL_FRAME_INSIDE_DEADLINE; } NOTREACHED(); - return "???"; + return pbzeroMajorState::BEGIN_IMPL_FRAME_UNSPECIFIED; } const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( @@ -72,176 +81,204 @@ const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( return "???"; } -const char* SchedulerStateMachine::BeginMainFrameStateToString( - BeginMainFrameState state) { +perfetto::protos::pbzero::ChromeCompositorSchedulerState:: + BeginImplFrameDeadlineMode + SchedulerStateMachine::BeginImplFrameDeadlineModeToProtozeroEnum( + BeginImplFrameDeadlineMode mode) { + using pbzeroSchedulerState = + perfetto::protos::pbzero::ChromeCompositorSchedulerState; + switch (mode) { + case BeginImplFrameDeadlineMode::NONE: + return pbzeroSchedulerState::DEADLINE_MODE_NONE; + case BeginImplFrameDeadlineMode::IMMEDIATE: + return pbzeroSchedulerState::DEADLINE_MODE_IMMEDIATE; + case BeginImplFrameDeadlineMode::REGULAR: + return pbzeroSchedulerState::DEADLINE_MODE_REGULAR; + case BeginImplFrameDeadlineMode::LATE: + return pbzeroSchedulerState::DEADLINE_MODE_LATE; + case BeginImplFrameDeadlineMode::BLOCKED: + return pbzeroSchedulerState::DEADLINE_MODE_BLOCKED; + } + NOTREACHED(); + return pbzeroSchedulerState::DEADLINE_MODE_UNSPECIFIED; +} + +perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + BeginMainFrameState + SchedulerStateMachine::BeginMainFrameStateToProtozeroEnum( + BeginMainFrameState state) { + using pbzeroMajorState = + perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState; switch (state) { case BeginMainFrameState::IDLE: - return "BeginMainFrameState::IDLE"; + return pbzeroMajorState::BEGIN_MAIN_FRAME_IDLE; case BeginMainFrameState::SENT: - return "BeginMainFrameState::SENT"; + return pbzeroMajorState::BEGIN_MAIN_FRAME_SENT; case BeginMainFrameState::READY_TO_COMMIT: - return "BeginMainFrameState::READY_TO_COMMIT"; + return pbzeroMajorState::BEGIN_MAIN_FRAME_READY_TO_COMMIT; } NOTREACHED(); - return "???"; + return pbzeroMajorState::BEGIN_MAIN_FRAME_UNSPECIFIED; } -const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString( - ForcedRedrawOnTimeoutState state) { +perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + ForcedRedrawOnTimeoutState + SchedulerStateMachine::ForcedRedrawOnTimeoutStateToProtozeroEnum( + ForcedRedrawOnTimeoutState state) { + using pbzeroMajorState = + perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState; switch (state) { case ForcedRedrawOnTimeoutState::IDLE: - return "ForcedRedrawOnTimeoutState::IDLE"; + return pbzeroMajorState::FORCED_REDRAW_IDLE; case ForcedRedrawOnTimeoutState::WAITING_FOR_COMMIT: - return "ForcedRedrawOnTimeoutState::WAITING_FOR_COMMIT"; + return pbzeroMajorState::FORCED_REDRAW_WAITING_FOR_COMMIT; case ForcedRedrawOnTimeoutState::WAITING_FOR_ACTIVATION: - return "ForcedRedrawOnTimeoutState::WAITING_FOR_ACTIVATION"; + return pbzeroMajorState::FORCED_REDRAW_WAITING_FOR_ACTIVATION; case ForcedRedrawOnTimeoutState::WAITING_FOR_DRAW: - return "ForcedRedrawOnTimeoutState::WAITING_FOR_DRAW"; + return pbzeroMajorState::FORCED_REDRAW_WAITING_FOR_DRAW; } NOTREACHED(); - return "???"; + return pbzeroMajorState::FORCED_REDRAW_UNSPECIFIED; } -const char* ScrollHandlerStateToString(ScrollHandlerState state) { +perfetto::protos::pbzero::ChromeCompositorStateMachine::MinorState:: + ScrollHandlerState + ScrollHandlerStateToProtozeroEnum(ScrollHandlerState state) { + using pbzeroMinorState = + perfetto::protos::pbzero::ChromeCompositorStateMachine::MinorState; switch (state) { case ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER: - return "SCROLL_AFFECTS_SCROLL_HANDLER"; + return pbzeroMinorState::SCROLL_AFFECTS_SCROLL_HANDLER; case ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER: - return "SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER"; + return pbzeroMinorState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER; } NOTREACHED(); - return "???"; + return pbzeroMinorState::SCROLL_HANDLER_UNSPECIFIED; } -const char* SchedulerStateMachine::ActionToString(Action action) { +perfetto::protos::pbzero::ChromeCompositorSchedulerAction +SchedulerStateMachine::ActionToProtozeroEnum(Action action) { + using pbzeroSchedulerAction = + perfetto::protos::pbzero::ChromeCompositorSchedulerAction; switch (action) { case Action::NONE: - return "Action::NONE"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_NONE; case Action::SEND_BEGIN_MAIN_FRAME: - return "Action::SEND_BEGIN_MAIN_FRAME"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_SEND_BEGIN_MAIN_FRAME; case Action::COMMIT: - return "Action::COMMIT"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_COMMIT; case Action::ACTIVATE_SYNC_TREE: - return "Action::ACTIVATE_SYNC_TREE"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_ACTIVATE_SYNC_TREE; case Action::DRAW_IF_POSSIBLE: - return "Action::DRAW_IF_POSSIBLE"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_DRAW_IF_POSSIBLE; case Action::DRAW_FORCED: - return "Action::DRAW_FORCED"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_DRAW_FORCED; case Action::DRAW_ABORT: - return "Action::DRAW_ABORT"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_DRAW_ABORT; case Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION: - return "Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION"; + return pbzeroSchedulerAction:: + CC_SCHEDULER_ACTION_BEGIN_LAYER_TREE_FRAME_SINK_CREATION; case Action::PREPARE_TILES: - return "Action::PREPARE_TILES"; + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_PREPARE_TILES; case Action::INVALIDATE_LAYER_TREE_FRAME_SINK: - return "Action::INVALIDATE_LAYER_TREE_FRAME_SINK"; + return pbzeroSchedulerAction:: + CC_SCHEDULER_ACTION_INVALIDATE_LAYER_TREE_FRAME_SINK; case Action::PERFORM_IMPL_SIDE_INVALIDATION: - return "Action::PERFORM_IMPL_SIDE_INVALIDATION"; + return pbzeroSchedulerAction:: + CC_SCHEDULER_ACTION_PERFORM_IMPL_SIDE_INVALIDATION; case Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL: - return "Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL"; + return pbzeroSchedulerAction:: + CC_SCHEDULER_ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL; case Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON: - return "Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON"; + return pbzeroSchedulerAction:: + CC_SCHEDULER_ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON; } NOTREACHED(); - return "???"; -} - -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -SchedulerStateMachine::AsValue() const { - std::unique_ptr<base::trace_event::TracedValue> state( - new base::trace_event::TracedValue()); - AsValueInto(state.get()); - return std::move(state); -} - -void SchedulerStateMachine::AsValueInto( - base::trace_event::TracedValue* state) const { - state->BeginDictionary("major_state"); - state->SetString("next_action", ActionToString(NextAction())); - state->SetString("begin_impl_frame_state", - BeginImplFrameStateToString(begin_impl_frame_state_)); - state->SetString("begin_main_frame_state", - BeginMainFrameStateToString(begin_main_frame_state_)); - state->SetString( - "layer_tree_frame_sink_state", - LayerTreeFrameSinkStateToString(layer_tree_frame_sink_state_)); - state->SetString("forced_redraw_state", - ForcedRedrawOnTimeoutStateToString(forced_redraw_state_)); - state->EndDictionary(); - - state->BeginDictionary("minor_state"); - state->SetInteger("commit_count", commit_count_); - state->SetInteger("current_frame_number", current_frame_number_); - state->SetInteger("last_frame_number_submit_performed", - last_frame_number_submit_performed_); - state->SetInteger("last_frame_number_draw_performed", - last_frame_number_draw_performed_); - state->SetInteger("last_frame_number_begin_main_frame_sent", - last_frame_number_begin_main_frame_sent_); - state->SetBoolean("did_draw", did_draw_); - state->SetBoolean("did_send_begin_main_frame_for_current_frame", - did_send_begin_main_frame_for_current_frame_); - state->SetBoolean("did_notify_begin_main_frame_not_expected_until", - did_notify_begin_main_frame_not_expected_until_); - state->SetBoolean("did_notify_begin_main_frame_not_expected_soon", - did_notify_begin_main_frame_not_expected_soon_); - state->SetBoolean("wants_begin_main_frame_not_expected", - wants_begin_main_frame_not_expected_); - state->SetBoolean("did_commit_during_frame", did_commit_during_frame_); - state->SetBoolean("did_invalidate_layer_tree_frame_sink", - did_invalidate_layer_tree_frame_sink_); - state->SetBoolean("did_perform_impl_side_invalidaion", - did_perform_impl_side_invalidation_); - state->SetBoolean("did_prepare_tiles", did_prepare_tiles_); - state->SetInteger("consecutive_checkerboard_animations", - consecutive_checkerboard_animations_); - state->SetInteger("pending_submit_frames", pending_submit_frames_); - state->SetInteger("submit_frames_with_current_layer_tree_frame_sink", - submit_frames_with_current_layer_tree_frame_sink_); - state->SetBoolean("needs_redraw", needs_redraw_); - state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); - state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); - state->SetBoolean("needs_one_begin_impl_frame", needs_one_begin_impl_frame_); - state->SetBoolean("visible", visible_); - state->SetBoolean("begin_frame_source_paused", begin_frame_source_paused_); - state->SetBoolean("can_draw", can_draw_); - state->SetBoolean("resourceless_draw", resourceless_draw_); - state->SetBoolean("has_pending_tree", has_pending_tree_); - state->SetBoolean("pending_tree_is_ready_for_activation", - pending_tree_is_ready_for_activation_); - state->SetBoolean("active_tree_needs_first_draw", - active_tree_needs_first_draw_); - state->SetBoolean("active_tree_is_ready_to_draw", - active_tree_is_ready_to_draw_); - state->SetBoolean("did_create_and_initialize_first_layer_tree_frame_sink", - did_create_and_initialize_first_layer_tree_frame_sink_); - state->SetString("tree_priority", TreePriorityToString(tree_priority_)); - state->SetString("scroll_handler_state", - ScrollHandlerStateToString(scroll_handler_state_)); - state->SetBoolean("critical_begin_main_frame_to_activate_is_fast", - critical_begin_main_frame_to_activate_is_fast_); - state->SetBoolean("main_thread_missed_last_deadline", - main_thread_missed_last_deadline_); - state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency", - skip_next_begin_main_frame_to_reduce_latency_); - state->SetBoolean("video_needs_begin_frames", video_needs_begin_frames_); - state->SetBoolean("defer_begin_main_frame", defer_begin_main_frame_); - state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_); - state->SetBoolean("did_draw_in_last_frame", did_draw_in_last_frame_); - state->SetBoolean("did_submit_in_last_frame", did_submit_in_last_frame_); - state->SetBoolean("needs_impl_side_invalidation", - needs_impl_side_invalidation_); - state->SetBoolean("current_pending_tree_is_impl_side", - current_pending_tree_is_impl_side_); - state->SetBoolean("previous_pending_tree_was_impl_side", - previous_pending_tree_was_impl_side_); - state->SetBoolean("processing_animation_worklets_for_active_tree", - processing_animation_worklets_for_active_tree_); - state->SetBoolean("processing_animation_worklets_for_pending_tree", - processing_animation_worklets_for_pending_tree_); - state->SetBoolean("processing_paint_worklets_for_pending_tree", - processing_paint_worklets_for_pending_tree_); - state->EndDictionary(); + return pbzeroSchedulerAction::CC_SCHEDULER_ACTION_UNSPECIFIED; +} + +void SchedulerStateMachine::AsProtozeroInto( + perfetto::protos::pbzero::ChromeCompositorStateMachine* state) const { + auto* major_state = state->set_major_state(); + major_state->set_next_action(ActionToProtozeroEnum(NextAction())); + major_state->set_begin_impl_frame_state( + BeginImplFrameStateToProtozeroEnum(begin_impl_frame_state_)); + major_state->set_begin_main_frame_state( + BeginMainFrameStateToProtozeroEnum(begin_main_frame_state_)); + major_state->set_layer_tree_frame_sink_state( + LayerTreeFrameSinkStateToProtozeroEnum(layer_tree_frame_sink_state_)); + major_state->set_forced_redraw_state( + ForcedRedrawOnTimeoutStateToProtozeroEnum(forced_redraw_state_)); + + auto* minor_state = state->set_minor_state(); + minor_state->set_commit_count(commit_count_); + minor_state->set_current_frame_number(current_frame_number_); + minor_state->set_last_frame_number_submit_performed( + last_frame_number_submit_performed_); + minor_state->set_last_frame_number_draw_performed( + last_frame_number_draw_performed_); + minor_state->set_last_frame_number_begin_main_frame_sent( + last_frame_number_begin_main_frame_sent_); + minor_state->set_did_draw(did_draw_); + minor_state->set_did_send_begin_main_frame_for_current_frame( + did_send_begin_main_frame_for_current_frame_); + minor_state->set_did_notify_begin_main_frame_not_expected_until( + did_notify_begin_main_frame_not_expected_until_); + minor_state->set_did_notify_begin_main_frame_not_expected_soon( + did_notify_begin_main_frame_not_expected_soon_); + minor_state->set_wants_begin_main_frame_not_expected( + wants_begin_main_frame_not_expected_); + minor_state->set_did_commit_during_frame(did_commit_during_frame_); + minor_state->set_did_invalidate_layer_tree_frame_sink( + did_invalidate_layer_tree_frame_sink_); + minor_state->set_did_perform_impl_side_invalidaion( + did_perform_impl_side_invalidation_); + minor_state->set_did_prepare_tiles(did_prepare_tiles_); + minor_state->set_consecutive_checkerboard_animations( + consecutive_checkerboard_animations_); + minor_state->set_pending_submit_frames(pending_submit_frames_); + minor_state->set_submit_frames_with_current_layer_tree_frame_sink( + submit_frames_with_current_layer_tree_frame_sink_); + minor_state->set_needs_redraw(needs_redraw_); + minor_state->set_needs_prepare_tiles(needs_prepare_tiles_); + minor_state->set_needs_begin_main_frame(needs_begin_main_frame_); + minor_state->set_needs_one_begin_impl_frame(needs_one_begin_impl_frame_); + minor_state->set_visible(visible_); + minor_state->set_begin_frame_source_paused(begin_frame_source_paused_); + minor_state->set_can_draw(can_draw_); + minor_state->set_resourceless_draw(resourceless_draw_); + minor_state->set_has_pending_tree(has_pending_tree_); + minor_state->set_pending_tree_is_ready_for_activation( + pending_tree_is_ready_for_activation_); + minor_state->set_active_tree_needs_first_draw(active_tree_needs_first_draw_); + minor_state->set_active_tree_is_ready_to_draw(active_tree_is_ready_to_draw_); + minor_state->set_did_create_and_initialize_first_layer_tree_frame_sink( + did_create_and_initialize_first_layer_tree_frame_sink_); + minor_state->set_tree_priority(TreePriorityToProtozeroEnum(tree_priority_)); + minor_state->set_scroll_handler_state( + ScrollHandlerStateToProtozeroEnum(scroll_handler_state_)); + minor_state->set_critical_begin_main_frame_to_activate_is_fast( + critical_begin_main_frame_to_activate_is_fast_); + minor_state->set_main_thread_missed_last_deadline( + main_thread_missed_last_deadline_); + minor_state->set_skip_next_begin_main_frame_to_reduce_latency( + skip_next_begin_main_frame_to_reduce_latency_); + minor_state->set_video_needs_begin_frames(video_needs_begin_frames_); + minor_state->set_defer_begin_main_frame(defer_begin_main_frame_); + minor_state->set_last_commit_had_no_updates(last_commit_had_no_updates_); + minor_state->set_did_draw_in_last_frame(did_draw_in_last_frame_); + minor_state->set_did_submit_in_last_frame(did_submit_in_last_frame_); + minor_state->set_needs_impl_side_invalidation(needs_impl_side_invalidation_); + minor_state->set_current_pending_tree_is_impl_side( + current_pending_tree_is_impl_side_); + minor_state->set_previous_pending_tree_was_impl_side( + previous_pending_tree_was_impl_side_); + minor_state->set_processing_animation_worklets_for_active_tree( + processing_animation_worklets_for_active_tree_); + minor_state->set_processing_animation_worklets_for_pending_tree( + processing_animation_worklets_for_pending_tree_); + minor_state->set_processing_paint_worklets_for_pending_tree( + processing_paint_worklets_for_pending_tree_); } bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { @@ -1373,8 +1410,7 @@ void SchedulerStateMachine::SetNeedsOneBeginImplFrame() { } void SchedulerStateMachine::NotifyReadyToCommit() { - DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::SENT) - << AsValue()->ToString(); + DCHECK_EQ(begin_main_frame_state_, BeginMainFrameState::SENT); begin_main_frame_state_ = BeginMainFrameState::READY_TO_COMMIT; // In commit_to_active_tree mode, commit should happen right after BeginFrame, // meaning when this function is called, next action should be commit. diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h index 198e2ff1749..fe25d098c34 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.h +++ b/chromium/cc/scheduler/scheduler_state_machine.h @@ -16,13 +16,7 @@ #include "cc/scheduler/scheduler_settings.h" #include "cc/tiles/tile_priority.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" - -namespace base { -namespace trace_event { -class ConvertableToTraceFormat; -class TracedValue; -} -} +#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h" namespace cc { @@ -30,7 +24,6 @@ enum class ScrollHandlerState { SCROLL_AFFECTS_SCROLL_HANDLER, SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER, }; -const char* ScrollHandlerStateToString(ScrollHandlerState state); // The SchedulerStateMachine decides how to coordinate main thread activites // like painting/running javascript with rendering and input activities on the @@ -59,8 +52,9 @@ class CC_EXPORT SchedulerStateMachine { WAITING_FOR_FIRST_COMMIT, WAITING_FOR_FIRST_ACTIVATION, }; - static const char* LayerTreeFrameSinkStateToString( - LayerTreeFrameSinkState state); + static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + LayerTreeFrameSinkState + LayerTreeFrameSinkStateToProtozeroEnum(LayerTreeFrameSinkState state); // Note: BeginImplFrameState does not cycle through these states in a fixed // order on all platforms. It's up to the scheduler to set these correctly. @@ -69,7 +63,9 @@ class CC_EXPORT SchedulerStateMachine { INSIDE_BEGIN_FRAME, INSIDE_DEADLINE, }; - static const char* BeginImplFrameStateToString(BeginImplFrameState state); + static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + BeginImplFrameState + BeginImplFrameStateToProtozeroEnum(BeginImplFrameState state); // The scheduler uses a deadline to wait for main thread updates before // submitting a compositor frame. BeginImplFrameDeadlineMode specifies when @@ -84,8 +80,14 @@ class CC_EXPORT SchedulerStateMachine { BLOCKED, // Deadline should be blocked indefinitely until the next frame // arrives. }; + // TODO(nuskos): Update Scheduler::ScheduleBeginImplFrameDeadline event to + // used typed macros so we can remove this ToString function. static const char* BeginImplFrameDeadlineModeToString( BeginImplFrameDeadlineMode mode); + static perfetto::protos::pbzero::ChromeCompositorSchedulerState:: + BeginImplFrameDeadlineMode + BeginImplFrameDeadlineModeToProtozeroEnum( + BeginImplFrameDeadlineMode mode); enum class BeginMainFrameState { IDLE, // A new BeginMainFrame can start. @@ -93,7 +95,9 @@ class CC_EXPORT SchedulerStateMachine { READY_TO_COMMIT, // A previously issued BeginMainFrame has been processed, // and is ready to commit. }; - static const char* BeginMainFrameStateToString(BeginMainFrameState state); + static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + BeginMainFrameState + BeginMainFrameStateToProtozeroEnum(BeginMainFrameState state); // When a redraw is forced, it goes through a complete commit -> activation -> // draw cycle. Until a redraw has been forced, it remains in IDLE state. @@ -103,8 +107,10 @@ class CC_EXPORT SchedulerStateMachine { WAITING_FOR_ACTIVATION, WAITING_FOR_DRAW, }; - static const char* ForcedRedrawOnTimeoutStateToString( - ForcedRedrawOnTimeoutState state); + static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState:: + ForcedRedrawOnTimeoutState + ForcedRedrawOnTimeoutStateToProtozeroEnum( + ForcedRedrawOnTimeoutState state); BeginMainFrameState begin_main_frame_state() const { return begin_main_frame_state_; @@ -136,10 +142,11 @@ class CC_EXPORT SchedulerStateMachine { NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL, NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON, }; - static const char* ActionToString(Action action); + static perfetto::protos::pbzero::ChromeCompositorSchedulerAction + ActionToProtozeroEnum(Action action); - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const; - void AsValueInto(base::trace_event::TracedValue* dict) const; + void AsProtozeroInto( + perfetto::protos::pbzero::ChromeCompositorStateMachine* state) const; Action NextAction() const; void WillSendBeginMainFrame(); diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc index 6e080e666fe..ec84d72a398 100644 --- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc @@ -20,22 +20,19 @@ // With: // Value of: actual() Actual: "ACTION_DRAW" // Expected: expected() Which is: "ACTION_NONE" -#define EXPECT_ENUM_EQ(enum_tostring, expected, actual) \ - EXPECT_STREQ(SchedulerStateMachine::enum_tostring(expected), \ - SchedulerStateMachine::enum_tostring(actual)) +#define EXPECT_ENUM_EQ(enum_tostring, expected, actual) \ + EXPECT_EQ(enum_tostring(expected), enum_tostring(actual)) #define EXPECT_IMPL_FRAME_STATE(expected) \ EXPECT_ENUM_EQ(BeginImplFrameStateToString, expected, \ - state.begin_impl_frame_state()) \ - << state.AsValue()->ToString() + state.begin_impl_frame_state()) #define EXPECT_MAIN_FRAME_STATE(expected) \ EXPECT_ENUM_EQ(BeginMainFrameStateToString, expected, \ state.BeginMainFrameState()) -#define EXPECT_ACTION(expected) \ - EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction()) \ - << state.AsValue()->ToString() +#define EXPECT_ACTION(expected) \ + EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction()) #define EXPECT_ACTION_UPDATE_STATE(action) \ EXPECT_ACTION(action); \ @@ -63,6 +60,69 @@ namespace cc { namespace { +const char* BeginImplFrameStateToString( + SchedulerStateMachine::BeginImplFrameState state) { + using BeginImplFrameState = SchedulerStateMachine::BeginImplFrameState; + switch (state) { + case BeginImplFrameState::IDLE: + return "BeginImplFrameState::IDLE"; + case BeginImplFrameState::INSIDE_BEGIN_FRAME: + return "BeginImplFrameState::INSIDE_BEGIN_FRAME"; + case BeginImplFrameState::INSIDE_DEADLINE: + return "BeginImplFrameState::INSIDE_DEADLINE"; + } + NOTREACHED(); + return "???"; +} +const char* BeginMainFrameStateToString( + SchedulerStateMachine::BeginMainFrameState state) { + using BeginMainFrameState = SchedulerStateMachine::BeginMainFrameState; + switch (state) { + case BeginMainFrameState::IDLE: + return "BeginMainFrameState::IDLE"; + case BeginMainFrameState::SENT: + return "BeginMainFrameState::SENT"; + case BeginMainFrameState::READY_TO_COMMIT: + return "BeginMainFrameState::READY_TO_COMMIT"; + } + NOTREACHED(); + return "???"; +} + +const char* ActionToString(SchedulerStateMachine::Action action) { + using Action = SchedulerStateMachine::Action; + switch (action) { + case Action::NONE: + return "Action::NONE"; + case Action::SEND_BEGIN_MAIN_FRAME: + return "Action::SEND_BEGIN_MAIN_FRAME"; + case Action::COMMIT: + return "Action::COMMIT"; + case Action::ACTIVATE_SYNC_TREE: + return "Action::ACTIVATE_SYNC_TREE"; + case Action::DRAW_IF_POSSIBLE: + return "Action::DRAW_IF_POSSIBLE"; + case Action::DRAW_FORCED: + return "Action::DRAW_FORCED"; + case Action::DRAW_ABORT: + return "Action::DRAW_ABORT"; + case Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION: + return "Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION"; + case Action::PREPARE_TILES: + return "Action::PREPARE_TILES"; + case Action::INVALIDATE_LAYER_TREE_FRAME_SINK: + return "Action::INVALIDATE_LAYER_TREE_FRAME_SINK"; + case Action::PERFORM_IMPL_SIDE_INVALIDATION: + return "Action::PERFORM_IMPL_SIDE_INVALIDATION"; + case Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL: + return "Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL"; + case Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON: + return "Action::NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON"; + } + NOTREACHED(); + return "???"; +} + const bool kAnimateOnly = false; const SchedulerStateMachine::BeginImplFrameState all_begin_impl_frame_states[] = @@ -799,8 +859,7 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) { // Case 2: needs_begin_main_frame=true state.SetNeedsBeginMainFrame(); EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE, - state.NextAction()) - << state.AsValue()->ToString(); + state.NextAction()); } } @@ -867,8 +926,7 @@ TEST(SchedulerStateMachineTest, TestNoBeginMainFrameStatesRedrawWhenInvisible) { // Case 2: needs_begin_main_frame=true. state.SetNeedsBeginMainFrame(); EXPECT_NE(SchedulerStateMachine::Action::DRAW_IF_POSSIBLE, - state.NextAction()) - << state.AsValue()->ToString(); + state.NextAction()); } } } diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index 5437a540cd1..7d1c8d81aa0 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -18,6 +18,7 @@ #include "base/test/test_mock_time_task_runner.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" +#include "cc/metrics/begin_main_frame_metrics.h" #include "cc/test/scheduler_test_common.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/test/begin_frame_args_test.h" @@ -50,7 +51,6 @@ class FakeSchedulerClient : public SchedulerClient, void Reset() { actions_.clear(); - states_.clear(); will_begin_impl_frame_causes_redraw_ = false; will_begin_impl_frame_requests_one_begin_impl_frame_ = false; invalidate_needs_redraw_ = true; @@ -69,7 +69,6 @@ class FakeSchedulerClient : public SchedulerClient, const std::vector<std::string> Actions() const { return std::vector<std::string>(actions_.begin(), actions_.end()); } - std::string StateForAction(int i) const { return states_[i]->ToString(); } base::TimeTicks posted_begin_impl_frame_deadline() const { return posted_begin_impl_frame_deadline_; } @@ -205,7 +204,6 @@ class FakeSchedulerClient : public SchedulerClient, base::AutoReset<bool> mark_inside(&inside_action_, true); invalidate_needs_redraw_ = needs_redraw; actions_.push_back("ScheduledActionInvalidateLayerTreeFrameSink"); - states_.push_back(scheduler_->AsValue()); } void ScheduledActionPerformImplSideInvalidation() override { EXPECT_FALSE(inside_action_); @@ -246,7 +244,6 @@ class FakeSchedulerClient : public SchedulerClient, void PushAction(const char* description) { actions_.push_back(description); - states_.push_back(scheduler_->AsValue()); } // FakeExternalBeginFrameSource::Client implementation. @@ -282,8 +279,6 @@ class FakeSchedulerClient : public SchedulerClient, viz::BeginFrameAck last_begin_frame_ack_; base::TimeTicks posted_begin_impl_frame_deadline_; std::vector<const char*> actions_; - std::vector<std::unique_ptr<base::trace_event::ConvertableToTraceFormat>> - states_; TestScheduler* scheduler_ = nullptr; base::TimeDelta frame_interval_; }; @@ -455,7 +450,7 @@ class SchedulerTest : public testing::Test { task_runner_->AdvanceMockTickClock(base::TimeDelta::FromMilliseconds(1)); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); scheduler_->NotifyReadyToDraw(); @@ -663,7 +658,7 @@ TEST_F(SchedulerTest, RequestCommit) { // NotifyReadyToCommit should trigger the commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_TRUE(scheduler_->begin_frames_expected()); client_->Reset(); @@ -778,7 +773,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { // Finish the first commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -807,7 +802,7 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { // Finishing the commit before the deadline should post a new deadline task // to trigger the deadline early. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); client_->Reset(); @@ -985,7 +980,7 @@ TEST_F(SchedulerTest, RequestCommitInsideDraw) { EXPECT_TRUE(scheduler_->CommitPending()); EXPECT_TRUE(client->needs_begin_frames()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_SCOPED(AdvanceFrame()); @@ -1380,7 +1375,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) { EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame"); client_->Reset(); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -1418,7 +1413,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) { EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame"); client_->Reset(); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -1450,7 +1445,7 @@ void SchedulerTest::AdvanceAndMissOneFrame() { task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", "ScheduledActionCommit", @@ -1714,7 +1709,7 @@ TEST_F(SchedulerTest, MainFrameNotSkippedAfterCanDrawChanges) { // Make us abort the upcoming draw. client_->Reset(); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree"); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); @@ -1759,7 +1754,7 @@ TEST_F(SchedulerTest, MainFrameNotSkippedWhenNoTimingHistory) { // Commit after the deadline. client_->Reset(); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree"); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); @@ -1789,7 +1784,7 @@ void SchedulerTest::ImplFrameSkippedAfterLateAck( client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); @@ -1834,7 +1829,7 @@ void SchedulerTest::ImplFrameSkippedAfterLateAck( client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree", @@ -1963,7 +1958,7 @@ void SchedulerTest::ImplFrameNotSkippedAfterLateAck() { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); @@ -1987,7 +1982,7 @@ void SchedulerTest::ImplFrameNotSkippedAfterLateAck() { client_->Reset(); scheduler_->DidReceiveCompositorFrameAck(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); @@ -2061,7 +2056,7 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) { task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); @@ -2077,7 +2072,7 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) { EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", @@ -2142,7 +2137,7 @@ TEST_F(SchedulerTest, MainFrameThenImplFrameSkippedAfterLateCommitAndLateAck) { SendNextBeginFrame(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); @@ -2177,7 +2172,7 @@ void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) { // NotifyReadyToCommit should trigger the commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -2231,7 +2226,7 @@ void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled( // NotifyReadyToCommit should trigger the pending commit. scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -2337,7 +2332,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterBeginFrameStarted) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree"); client_->Reset(); @@ -2383,7 +2378,7 @@ TEST_F(SchedulerTest, client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionActivateSyncTree", "ScheduledActionBeginLayerTreeFrameSinkCreation"); } @@ -2402,7 +2397,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterReadyToCommit) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -2458,7 +2453,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWithDelayBasedBeginFrameSource) { // NotifyReadyToCommit should trigger the commit. client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_TRUE(scheduler_->begin_frames_expected()); @@ -2494,7 +2489,7 @@ TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWhenIdle) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -2526,7 +2521,7 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); @@ -2552,7 +2547,7 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBeginFrameSourcePaused) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_TRUE(client_->IsInsideBeginImplFrame()); @@ -2739,7 +2734,7 @@ TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) { EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame"); client_->Reset(); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -2830,7 +2825,7 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Requested) { // Trigger a frame draw. EXPECT_SCOPED(AdvanceFrame()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", @@ -2866,7 +2861,7 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Unrequested) { // Trigger a frame draw. EXPECT_SCOPED(AdvanceFrame()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", @@ -2904,7 +2899,7 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoonOnlyOncePerFrame) { // Trigger a frame draw. EXPECT_SCOPED(AdvanceFrame()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", @@ -2945,7 +2940,7 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_AlreadyIdle) { // Trigger a frame draw. EXPECT_SCOPED(AdvanceFrame()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunPendingTasks(); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame", @@ -3303,7 +3298,7 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) { client_->last_begin_frame_ack()); client_->Reset(); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -3457,7 +3452,7 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) { client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); client_->Reset(); @@ -3515,7 +3510,7 @@ TEST_F(SchedulerTest, AuthoritativeVSyncInterval) { EXPECT_EQ(initial_interval, scheduler_->BeginImplFrameInterval()); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); scheduler_->NotifyReadyToActivate(); task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true)); @@ -3626,7 +3621,7 @@ TEST_F(SchedulerTest, ImplSideInvalidationsMergedWithCommit) { // commit. client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); EXPECT_FALSE(scheduler_->needs_impl_side_invalidation()); } @@ -4166,7 +4161,7 @@ TEST_F(SchedulerTest, // Commit before deadline but not ready to activate. client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("ScheduledActionCommit"); // Draw deadline. @@ -4215,7 +4210,7 @@ TEST_F(SchedulerTest, DontSkipMainFrameAfterClearingHistory) { EXPECT_SCOPED(AdvanceFrame()); scheduler_->SetNeedsBeginMainFrame(); scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks()); - scheduler_->NotifyReadyToCommit(); + scheduler_->NotifyReadyToCommit(nullptr); EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionCommit"); // But during the commit, the history is cleared. So the main frame should not diff --git a/chromium/cc/tiles/frame_viewer_instrumentation.h b/chromium/cc/tiles/frame_viewer_instrumentation.h index 7c4ad9df52f..38f1ed1811e 100644 --- a/chromium/cc/tiles/frame_viewer_instrumentation.h +++ b/chromium/cc/tiles/frame_viewer_instrumentation.h @@ -6,6 +6,7 @@ #define CC_TILES_FRAME_VIEWER_INSTRUMENTATION_H_ #include "base/trace_event/trace_event.h" +#include "cc/cc_export.h" #include "cc/tiles/tile_priority.h" namespace cc { @@ -42,7 +43,7 @@ class ScopedRasterTask { ScopedRasterTask& operator=(const ScopedRasterTask&) = delete; }; -bool IsTracingLayerTreeSnapshots(); +bool CC_EXPORT IsTracingLayerTreeSnapshots(); } // namespace frame_viewer_instrumentation } // namespace cc diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc index 198f910967d..17c49d2d3ae 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache.cc @@ -186,23 +186,26 @@ void SetYuvPixmapsFromSizeInfo(SkPixmap* pixmap_y, DCHECK(pixmap_y); DCHECK(pixmap_u); DCHECK(pixmap_v); - const size_t y_width = yuva_size_info.fWidthBytes[SkYUVAIndex::kY_Index]; + const size_t y_width_bytes = + yuva_size_info.fWidthBytes[SkYUVAIndex::kY_Index]; + const size_t y_width = yuva_size_info.fSizes[SkYUVAIndex::kY_Index].width(); const size_t y_height = yuva_size_info.fSizes[SkYUVAIndex::kY_Index].height(); - const size_t u_width = yuva_size_info.fWidthBytes[SkYUVAIndex::kU_Index]; + const size_t u_width_bytes = + yuva_size_info.fWidthBytes[SkYUVAIndex::kU_Index]; + const size_t u_width = yuva_size_info.fSizes[SkYUVAIndex::kU_Index].width(); const size_t u_height = yuva_size_info.fSizes[SkYUVAIndex::kU_Index].height(); - const size_t v_width = yuva_size_info.fWidthBytes[SkYUVAIndex::kV_Index]; + const size_t v_width_bytes = + yuva_size_info.fWidthBytes[SkYUVAIndex::kV_Index]; + const size_t v_width = yuva_size_info.fSizes[SkYUVAIndex::kV_Index].width(); const size_t v_height = yuva_size_info.fSizes[SkYUVAIndex::kV_Index].height(); const SkImageInfo y_decode_info = info.makeColorType(kGray_8_SkColorType).makeWH(y_width, y_height); const SkImageInfo u_decode_info = y_decode_info.makeWH(u_width, u_height); const SkImageInfo v_decode_info = y_decode_info.makeWH(v_width, v_height); yuva_size_info.computePlanes(memory_ptr, planes); - pixmap_y->reset(y_decode_info, planes[SkYUVAIndex::kY_Index], - y_decode_info.minRowBytes()); - pixmap_u->reset(u_decode_info, planes[SkYUVAIndex::kU_Index], - u_decode_info.minRowBytes()); - pixmap_v->reset(v_decode_info, planes[SkYUVAIndex::kV_Index], - v_decode_info.minRowBytes()); + pixmap_y->reset(y_decode_info, planes[SkYUVAIndex::kY_Index], y_width_bytes); + pixmap_u->reset(u_decode_info, planes[SkYUVAIndex::kU_Index], u_width_bytes); + pixmap_v->reset(v_decode_info, planes[SkYUVAIndex::kV_Index], v_width_bytes); } // Helper method to fill in |scaled_u_size| and |scaled_v_size| by computing @@ -280,8 +283,10 @@ bool DrawAndScaleImage(const DrawImage& draw_image, draw_image.filter_quality() == kNone_SkFilterQuality; SkImageInfo info = pixmap.info(); SkYUVASizeInfo yuva_size_info; + SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount]; if (do_yuv_decode) { - const bool yuva_info_initialized = paint_image.IsYuv(&yuva_size_info); + const bool yuva_info_initialized = + paint_image.IsYuv(&yuva_size_info, plane_indices); DCHECK(yuva_info_initialized); } SkISize supported_size = @@ -298,7 +303,7 @@ bool DrawAndScaleImage(const DrawImage& draw_image, SetYuvPixmapsFromSizeInfo(pixmap_y, pixmap_u, pixmap_v, yuva_size_info, planes, info, pixmap.writable_addr()); return paint_image.DecodeYuv(planes, draw_image.frame_index(), client_id, - yuva_size_info); + yuva_size_info, plane_indices); } return paint_image.Decode(pixmap.writable_addr(), &info, color_space, draw_image.frame_index(), client_id); @@ -346,11 +351,12 @@ bool DrawAndScaleImage(const DrawImage& draw_image, yuva_size_info.computePlanes(decode_pixmap.writable_addr(), planes); } bool initial_decode_failed = - do_yuv_decode ? !paint_image.DecodeYuv(planes, draw_image.frame_index(), - client_id, yuva_size_info) - : !paint_image.Decode(decode_pixmap.writable_addr(), - &decode_info, color_space, - draw_image.frame_index(), client_id); + do_yuv_decode + ? !paint_image.DecodeYuv(planes, draw_image.frame_index(), client_id, + yuva_size_info, plane_indices) + : !paint_image.Decode(decode_pixmap.writable_addr(), &decode_info, + color_space, draw_image.frame_index(), + client_id); if (initial_decode_failed) return false; @@ -611,6 +617,11 @@ class ImageUploadTaskImpl : public TileTask { void RunOnWorkerThread() override { TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu", "source_prepare_tiles_id", tracing_info_.prepare_tiles_id); + const auto* image_metadata = image_.paint_image().GetImageHeaderMetadata(); + const ImageType image_type = + image_metadata ? image_metadata->image_type : ImageType::kInvalid; + devtools_instrumentation::ScopedImageUploadTask image_upload_task( + &image_.paint_image(), ImageDecodeCache::ToScopedImageType(image_type)); cache_->UploadImageInTask(image_); } @@ -675,8 +686,10 @@ int GpuImageDecodeCache::ImageDataBase::UsageState() const { GpuImageDecodeCache::DecodedImageData::DecodedImageData( bool is_bitmap_backed, + bool can_do_hardware_accelerated_decode, bool do_hardware_accelerated_decode) : is_bitmap_backed_(is_bitmap_backed), + can_do_hardware_accelerated_decode_(can_do_hardware_accelerated_decode), do_hardware_accelerated_decode_(do_hardware_accelerated_decode) {} GpuImageDecodeCache::DecodedImageData::~DecodedImageData() { ResetData(); @@ -869,6 +882,7 @@ GpuImageDecodeCache::ImageData::ImageData( int upload_scale_mip_level, bool needs_mips, bool is_bitmap_backed, + bool can_do_hardware_accelerated_decode, bool do_hardware_accelerated_decode, bool is_yuv_format, SkYUVColorSpace yuv_cs) @@ -881,7 +895,9 @@ GpuImageDecodeCache::ImageData::ImageData( needs_mips(needs_mips), is_bitmap_backed(is_bitmap_backed), is_yuv(is_yuv_format), - decode(is_bitmap_backed, do_hardware_accelerated_decode) { + decode(is_bitmap_backed, + can_do_hardware_accelerated_decode, + do_hardware_accelerated_decode) { // Only fill out the base::Optional |yuv_color_space| if doing YUV decoding. // Otherwise it was filled out with a default "identity" value by the decoder. if (is_yuv) { @@ -1022,8 +1038,10 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "GpuImageDecodeCache::GetTaskForImageAndRef"); - if (SkipImage(draw_image)) - return TaskResult(false); + if (SkipImage(draw_image)) { + return TaskResult(false /* need_unref */, false /* is_at_raster_decode */, + false /* can_do_hardware_accelerated_decode */); + } base::AutoLock lock(lock_); const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image); @@ -1041,26 +1059,31 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( image_data = new_data.get(); } else if (image_data->decode.decode_failure) { // We have already tried and failed to decode this image, so just return. - return TaskResult(false); + return TaskResult(false /* need_unref */, false /* is_at_raster_decode */, + image_data->decode.can_do_hardware_accelerated_decode()); } else if (task_type == DecodeTaskType::kPartOfUploadTask && image_data->upload.task) { // We had an existing upload task, ref the image and return the task. image_data->ValidateBudgeted(); RefImage(draw_image, cache_key); - return TaskResult(image_data->upload.task); + return TaskResult(image_data->upload.task, + image_data->decode.can_do_hardware_accelerated_decode()); } else if (task_type == DecodeTaskType::kStandAloneDecodeTask && image_data->decode.stand_alone_task) { // We had an existing out of raster task, ref the image and return the task. image_data->ValidateBudgeted(); RefImage(draw_image, cache_key); - return TaskResult(image_data->decode.stand_alone_task); + DCHECK(!image_data->decode.can_do_hardware_accelerated_decode()); + return TaskResult(image_data->decode.stand_alone_task, + false /* can_do_hardware_accelerated_decode */); } // Ensure that the image we're about to decode/upload will fit in memory, if // not already budgeted. if (!image_data->is_budgeted && !EnsureCapacity(image_data->size)) { // Image will not fit, do an at-raster decode. - return TaskResult(false); + return TaskResult(false /* need_unref */, true /* is_at_raster_decode */, + image_data->decode.can_do_hardware_accelerated_decode()); } // If we had to create new image data, add it to our map now that we know it @@ -1077,7 +1100,8 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( DCHECK(image_data->is_budgeted); if (image_data->HasUploadedData() && TryLockImage(HaveContextLock::kNo, draw_image, image_data)) { - return TaskResult(true); + return TaskResult(true /* need_unref */, false /* is_at_raster_decode */, + image_data->decode.can_do_hardware_accelerated_decode()); } scoped_refptr<TileTask> task; @@ -1094,7 +1118,8 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type); } - return TaskResult(task); + return TaskResult(task, + image_data->decode.can_do_hardware_accelerated_decode()); } void GpuImageDecodeCache::UnrefImage(const DrawImage& draw_image) { @@ -2015,8 +2040,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, ClientImageTransferCacheEntry::GetNextId(); const gpu::SyncToken decode_sync_token = context_->RasterInterface()->ScheduleImageDecode( - base::make_span<const uint8_t>(encoded_data->bytes(), - encoded_data->size()), + base::make_span(encoded_data->bytes(), encoded_data->size()), output_size, transfer_cache_id, color_space ? gfx::ColorSpace(*color_space) : gfx::ColorSpace(), image_data->needs_mips); @@ -2269,6 +2293,7 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image, // gives us the result in the GPU process. Figure out what to do. const ImageHeaderMetadata* image_metadata = draw_image.paint_image().GetImageHeaderMetadata(); + bool can_do_hardware_accelerated_decode = false; bool do_hardware_accelerated_decode = false; if (allow_hardware_decode && mode == DecodedDataMode::kTransferCache && upload_scale_mip_level == 0 && @@ -2281,6 +2306,7 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image, DCHECK_EQ(image_metadata->image_size.height(), draw_image.paint_image().height()); + can_do_hardware_accelerated_decode = true; const bool is_jpeg = (image_metadata->image_type == ImageType::kJPEG); const bool is_webp = (image_metadata->image_type == ImageType::kWEBP); do_hardware_accelerated_decode = @@ -2301,7 +2327,6 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image, mode != DecodedDataMode::kCpu && !image_larger_than_max_texture; // TODO(crbug.com/910276): Change after alpha support. if (is_yuv) { - size_t y_size_bytes = image_info.width() * image_info.height(); const gfx::Size target_raster_size(image_info.width(), image_info.height()); gfx::Size unscaled_u_size( target_yuva_size_info.fSizes[SkYUVAIndex::kU_Index].width(), @@ -2314,17 +2339,25 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image, ComputeMippedUVPlaneSizes(target_raster_size, unscaled_u_size, unscaled_v_size, draw_image, &scaled_u_size, &scaled_v_size); - size_t u_size_bytes = base::checked_cast<size_t>(scaled_u_size.GetArea()); - size_t v_size_bytes = base::checked_cast<size_t>(scaled_v_size.GetArea()); + + size_t y_size_bytes = + target_yuva_size_info.fWidthBytes[SkYUVAIndex::kY_Index] * + target_yuva_size_info.fSizes[SkYUVAIndex::kY_Index].height(); + size_t u_size_bytes = + target_yuva_size_info.fWidthBytes[SkYUVAIndex::kU_Index] * + target_yuva_size_info.fSizes[SkYUVAIndex::kU_Index].height(); + size_t v_size_bytes = + target_yuva_size_info.fWidthBytes[SkYUVAIndex::kV_Index] * + target_yuva_size_info.fSizes[SkYUVAIndex::kV_Index].height(); data_size = y_size_bytes + u_size_bytes + v_size_bytes; } - return base::WrapRefCounted( - new ImageData(draw_image.paint_image().stable_id(), mode, data_size, - draw_image.target_color_space(), - CalculateDesiredFilterQuality(draw_image), - upload_scale_mip_level, needs_mips, is_bitmap_backed, - do_hardware_accelerated_decode, is_yuv, yuv_color_space)); + return base::WrapRefCounted(new ImageData( + draw_image.paint_image().stable_id(), mode, data_size, + draw_image.target_color_space(), + CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level, + needs_mips, is_bitmap_backed, can_do_hardware_accelerated_decode, + do_hardware_accelerated_decode, is_yuv, yuv_color_space)); } void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) { diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h index fdfd11497a1..4ee3ae8054e 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.h +++ b/chromium/cc/tiles/gpu_image_decode_cache.h @@ -249,6 +249,7 @@ class CC_EXPORT GpuImageDecodeCache // Stores the CPU-side decoded bits of an image and supporting fields. struct DecodedImageData : public ImageDataBase { explicit DecodedImageData(bool is_bitmap_backed, + bool can_do_hardware_accelerated_decode, bool do_hardware_accelerated_decode); ~DecodedImageData(); @@ -288,6 +289,10 @@ class CC_EXPORT GpuImageDecodeCache bool is_yuv() const { return image_yuv_planes_.has_value(); } + bool can_do_hardware_accelerated_decode() const { + return can_do_hardware_accelerated_decode_; + } + bool do_hardware_accelerated_decode() const { return do_hardware_accelerated_decode_; } @@ -319,6 +324,11 @@ class CC_EXPORT GpuImageDecodeCache // decoder. base::Optional<YUVSkImages> image_yuv_planes_; + // Keeps tracks of images that could go through hardware decode acceleration + // though they're possibly prevented from doing so because of a disabled + // feature flag. + bool can_do_hardware_accelerated_decode_; + // |do_hardware_accelerated_decode_| keeps track of images that should go // through hardware decode acceleration. Currently, this path is intended // only for Chrome OS and only for some JPEG images (see @@ -493,6 +503,7 @@ class CC_EXPORT GpuImageDecodeCache int upload_scale_mip_level, bool needs_mips, bool is_bitmap_backed, + bool can_do_hardware_accelerated_decode, bool do_hardware_accelerated_decode, bool is_yuv_format, SkYUVColorSpace yuv_cs); diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc index 329edf9d239..fd008a698af 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc @@ -184,7 +184,13 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface, bool CanDecodeWithHardwareAcceleration( const ImageHeaderMetadata* image_metadata) const override { - return advertise_accelerated_decoding_; + // Only advertise hardware accelerated decoding for the current use cases + // (JPEG and WebP). + if (image_metadata && (image_metadata->image_type == ImageType::kJPEG || + image_metadata->image_type == ImageType::kWEBP)) { + return advertise_accelerated_decoding_; + } + return false; } std::pair<TransferCacheEntryType, uint32_t> MakeEntryKey(uint32_t type, @@ -362,10 +368,11 @@ class GpuImageDecodeCacheTest do_yuv_decode_ = std::get<2>(GetParam()); } - std::unique_ptr<GpuImageDecodeCache> CreateCache() { + std::unique_ptr<GpuImageDecodeCache> CreateCache( + size_t memory_limit_bytes = kGpuMemoryLimitBytes) { return std::make_unique<GpuImageDecodeCache>( context_provider_.get(), use_transfer_cache_, color_type_, - kGpuMemoryLimitBytes, max_texture_size_, + memory_limit_bytes, max_texture_size_, PaintImage::kDefaultGeneratorClientId); } @@ -2998,6 +3005,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); ASSERT_TRUE(result.task); + EXPECT_TRUE(result.can_do_hardware_accelerated_decode); // Accelerated decodes should not produce decode tasks. ASSERT_TRUE(result.task->dependencies().empty()); @@ -3032,6 +3040,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); ASSERT_TRUE(result.task); + EXPECT_TRUE(result.can_do_hardware_accelerated_decode); // Accelerated decodes should not produce decode tasks. ASSERT_TRUE(result.task->dependencies().empty()); @@ -3069,6 +3078,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); ASSERT_TRUE(result.task); + EXPECT_TRUE(result.can_do_hardware_accelerated_decode); // Accelerated decodes should not produce decode tasks. ASSERT_TRUE(result.task->dependencies().empty()); @@ -3083,6 +3093,14 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, .Times(1); TestTileTaskRunner::ProcessTask(result.task.get()); + // Attempting to get another task for the image should result in no task + // because the decode is considered to have failed before. + ImageDecodeCache::TaskResult result_after_run = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_FALSE(result_after_run.need_unref); + EXPECT_FALSE(result_after_run.task); + EXPECT_TRUE(result_after_run.can_do_hardware_accelerated_decode); + // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); @@ -3107,6 +3125,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); EXPECT_TRUE(result.need_unref); ASSERT_TRUE(result.task); + EXPECT_FALSE(result.can_do_hardware_accelerated_decode); // A non-accelerated standalone decode should produce only a decode task. ASSERT_TRUE(result.task->dependencies().empty()); @@ -3128,6 +3147,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); ASSERT_TRUE(result.task); + EXPECT_FALSE(result.can_do_hardware_accelerated_decode); // A non-accelerated normal decode should produce a decode dependency. ASSERT_EQ(result.task->dependencies().size(), 1u); @@ -3151,6 +3171,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); ASSERT_TRUE(result.task); + EXPECT_TRUE(result.can_do_hardware_accelerated_decode); // Accelerated decodes should not produce decode tasks. ASSERT_TRUE(result.task->dependencies().empty()); @@ -3164,6 +3185,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); ASSERT_TRUE(another_result.task); + EXPECT_TRUE(another_result.can_do_hardware_accelerated_decode); EXPECT_EQ(another_result.task->dependencies().size(), 0u); ASSERT_TRUE(image.GetImageHeaderMetadata()); EXPECT_CALL(*raster_implementation(), @@ -3183,6 +3205,37 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, cache->UnrefImage(draw_image); } +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfullyAtRasterTime) { + // We force at-raster decodes by setting the cache memory limit to 0 bytes. + auto cache = CreateCache(0u /* memory_limit_bytes */); + const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB(); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = CreatePaintImageForDecodeAcceleration(); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_FALSE(result.need_unref); + EXPECT_FALSE(result.task); + EXPECT_TRUE(result.is_at_raster_decode); + EXPECT_TRUE(result.can_do_hardware_accelerated_decode); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, + _, gfx::ColorSpace(), _)) + .Times(1); + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); +} + INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsOOPR, GpuImageDecodeCacheWithAcceleratedDecodesTest, @@ -3222,6 +3275,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, // task without a decode dependency since the decode will be done in the GPU // process. In the alternative path (software decoding), the upload task // depends on a decode task that runs in the renderer. + EXPECT_EQ(advertise_accelerated_decoding_, + jpeg_task.can_do_hardware_accelerated_decode); if (advertise_accelerated_decoding_ && allow_accelerated_jpeg_decoding_) { ASSERT_TRUE(jpeg_task.task->dependencies().empty()); ASSERT_TRUE(jpeg_image.GetImageHeaderMetadata()); @@ -3235,8 +3290,31 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, ASSERT_TRUE(jpeg_task.task->dependencies()[0]); TestTileTaskRunner::ProcessTask(jpeg_task.task->dependencies()[0].get()); } - TestTileTaskRunner::ProcessTask(jpeg_task.task.get()); + TestTileTaskRunner::ScheduleTask(jpeg_task.task.get()); + + // After scheduling the task, trying to get another task for the image should + // result in the original task. + ImageDecodeCache::TaskResult jpeg_task_again = cache->GetTaskForImageAndRef( + jpeg_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(jpeg_task_again.need_unref); + EXPECT_EQ(jpeg_task_again.task.get(), jpeg_task.task.get()); + EXPECT_EQ(advertise_accelerated_decoding_, + jpeg_task_again.can_do_hardware_accelerated_decode); + + TestTileTaskRunner::RunTask(jpeg_task.task.get()); + TestTileTaskRunner::CompleteTask(jpeg_task.task.get()); testing::Mock::VerifyAndClearExpectations(raster_implementation()); + + // After running the tasks, trying to get another task for the image should + // result in no task. + jpeg_task = cache->GetTaskForImageAndRef(jpeg_draw_image, + ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(jpeg_task.need_unref); + EXPECT_FALSE(jpeg_task.task); + EXPECT_EQ(advertise_accelerated_decoding_, + jpeg_task.can_do_hardware_accelerated_decode); + cache->UnrefImage(jpeg_draw_image); + cache->UnrefImage(jpeg_draw_image); cache->UnrefImage(jpeg_draw_image); // Try a WebP image. @@ -3250,6 +3328,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, webp_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(webp_task.need_unref); ASSERT_TRUE(webp_task.task); + EXPECT_EQ(advertise_accelerated_decoding_, + webp_task.can_do_hardware_accelerated_decode); if (advertise_accelerated_decoding_ && allow_accelerated_webp_decoding_) { ASSERT_TRUE(webp_task.task->dependencies().empty()); ASSERT_TRUE(webp_image.GetImageHeaderMetadata()); @@ -3265,6 +3345,15 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, } TestTileTaskRunner::ProcessTask(webp_task.task.get()); testing::Mock::VerifyAndClearExpectations(raster_implementation()); + + // The image should have been cached. + webp_task = cache->GetTaskForImageAndRef(webp_draw_image, + ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(webp_task.need_unref); + EXPECT_FALSE(webp_task.task); + EXPECT_EQ(advertise_accelerated_decoding_, + webp_task.can_do_hardware_accelerated_decode); + cache->UnrefImage(webp_draw_image); cache->UnrefImage(webp_draw_image); // Try a PNG image (which should not be hardware accelerated). @@ -3278,6 +3367,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest, png_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(png_task.need_unref); ASSERT_TRUE(png_task.task); + EXPECT_FALSE(png_task.can_do_hardware_accelerated_decode); ASSERT_EQ(png_task.task->dependencies().size(), 1u); ASSERT_TRUE(png_task.task->dependencies()[0]); TestTileTaskRunner::ProcessTask(png_task.task->dependencies()[0].get()); diff --git a/chromium/cc/tiles/image_controller.cc b/chromium/cc/tiles/image_controller.cc index 9f600462eb8..0fe837a669a 100644 --- a/chromium/cc/tiles/image_controller.cc +++ b/chromium/cc/tiles/image_controller.cc @@ -150,9 +150,13 @@ void ImageController::ConvertImagesToTasks( std::vector<DrawImage>* sync_decoded_images, std::vector<scoped_refptr<TileTask>>* tasks, bool* has_at_raster_images, + bool* has_hardware_accelerated_jpeg_candidates, + bool* has_hardware_accelerated_webp_candidates, const ImageDecodeCache::TracingInfo& tracing_info) { DCHECK(cache_); *has_at_raster_images = false; + *has_hardware_accelerated_jpeg_candidates = false; + *has_hardware_accelerated_webp_candidates = false; for (auto it = sync_decoded_images->begin(); it != sync_decoded_images->end();) { // PaintWorklet images should not be included in this set; they have already @@ -161,7 +165,19 @@ void ImageController::ConvertImagesToTasks( ImageDecodeCache::TaskResult result = cache_->GetTaskForImageAndRef(*it, tracing_info); - *has_at_raster_images |= result.IsAtRaster(); + *has_at_raster_images |= result.is_at_raster_decode; + + ImageType image_type = + it->paint_image().GetImageHeaderMetadata() + ? it->paint_image().GetImageHeaderMetadata()->image_type + : ImageType::kInvalid; + *has_hardware_accelerated_jpeg_candidates |= + (result.can_do_hardware_accelerated_decode && + image_type == ImageType::kJPEG); + *has_hardware_accelerated_webp_candidates |= + (result.can_do_hardware_accelerated_decode && + image_type == ImageType::kWEBP); + if (result.task) tasks->push_back(std::move(result.task)); if (result.need_unref) @@ -185,9 +201,16 @@ std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages( std::vector<DrawImage> images, const ImageDecodeCache::TracingInfo& tracing_info) { std::vector<scoped_refptr<TileTask>> new_tasks; + // The images here are in a pre-decode area: we decode them in advance, but + // they're not dependencies for raster tasks. If these images do end up + // getting rasterized, we will still have a chance to record the raster + // scheduling delay UMAs when we create and run the raster task. bool has_at_raster_images = false; + bool has_hardware_accelerated_jpeg_candidates = false; + bool has_hardware_accelerated_webp_candidates = false; ConvertImagesToTasks(&images, &new_tasks, &has_at_raster_images, - tracing_info); + &has_hardware_accelerated_jpeg_candidates, + &has_hardware_accelerated_webp_candidates, tracing_info); UnrefImages(predecode_locked_images_); predecode_locked_images_ = std::move(images); return new_tasks; @@ -206,7 +229,10 @@ ImageController::ImageDecodeRequestId ImageController::QueueImageDecode( bool is_image_lazy = draw_image.paint_image().IsLazyGenerated(); // Get the tasks for this decode. - ImageDecodeCache::TaskResult result(false); + ImageDecodeCache::TaskResult result( + /*need_unref=*/false, + /*is_at_raster_decode=*/false, + /*can_do_hardware_accelerated_decode=*/false); if (is_image_lazy) result = cache_->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); // If we don't need to unref this, we don't actually have a task. diff --git a/chromium/cc/tiles/image_controller.h b/chromium/cc/tiles/image_controller.h index 1ec832d13c1..560226c00fd 100644 --- a/chromium/cc/tiles/image_controller.h +++ b/chromium/cc/tiles/image_controller.h @@ -44,10 +44,16 @@ class CC_EXPORT ImageController { // vector under certain conditions. // |tasks| is an output, which are the built tile tasks. // |has_at_raster_images| is an output parameter. + // |has_hardware_accelerated_jpeg_candidates| and + // |has_hardware_accelerated_webp_candidates| are output parameters that + // indicate if there are images in |sync_decoded_images| that could be decoded + // using hardware decode acceleration. // |tracing_info| is used in tracing or UMA only. void ConvertImagesToTasks(std::vector<DrawImage>* sync_decoded_images, std::vector<scoped_refptr<TileTask>>* tasks, bool* has_at_raster_images, + bool* has_hardware_accelerated_jpeg_candidates, + bool* has_hardware_accelerated_webp_candidates, const ImageDecodeCache::TracingInfo& tracing_info); void UnrefImages(const std::vector<DrawImage>& images); void ReduceMemoryUsage(); diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc index 17b20018fb2..fbe924af6fd 100644 --- a/chromium/cc/tiles/image_controller_unittest.cc +++ b/chromium/cc/tiles/image_controller_unittest.cc @@ -107,11 +107,16 @@ class TestableCache : public StubDecodeCache { if (image.paint_image() && image.paint_image().width() * image.paint_image().height() >= 1000 * 1000) { - return TaskResult(false); + return TaskResult(/*need_unref=*/false, /*is_at_raster_decode=*/true, + /*can_do_hardware_accelerated_decode=*/false); } ++number_of_refs_; - return TaskResult(task_to_use_); + if (task_to_use_) + return TaskResult(task_to_use_, + /*can_do_hardware_accelerated_decode=*/false); + return TaskResult(/*need_unref=*/true, /*is_at_raster_decode=*/false, + /*can_do_hardware_accelerated_decode=*/false); } TaskResult GetOutOfRasterDecodeTaskForImageAndRef( const DrawImage& image) override { diff --git a/chromium/cc/tiles/image_decode_cache.cc b/chromium/cc/tiles/image_decode_cache.cc index 9c68e3cc26c..0b085cc2335 100644 --- a/chromium/cc/tiles/image_decode_cache.cc +++ b/chromium/cc/tiles/image_decode_cache.cc @@ -8,11 +8,23 @@ namespace cc { -ImageDecodeCache::TaskResult::TaskResult(bool need_unref) - : need_unref(need_unref) {} - -ImageDecodeCache::TaskResult::TaskResult(scoped_refptr<TileTask> task) - : task(std::move(task)), need_unref(true) {} +ImageDecodeCache::TaskResult::TaskResult( + bool need_unref, + bool is_at_raster_decode, + bool can_do_hardware_accelerated_decode) + : need_unref(need_unref), + is_at_raster_decode(is_at_raster_decode), + can_do_hardware_accelerated_decode(can_do_hardware_accelerated_decode) {} + +ImageDecodeCache::TaskResult::TaskResult( + scoped_refptr<TileTask> task, + bool can_do_hardware_accelerated_decode) + : task(std::move(task)), + need_unref(true), + is_at_raster_decode(false), + can_do_hardware_accelerated_decode(can_do_hardware_accelerated_decode) { + DCHECK(this->task); +} ImageDecodeCache::TaskResult::TaskResult(const TaskResult& result) = default; diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h index f2451ca7e5a..6366a6276f6 100644 --- a/chromium/cc/tiles/image_decode_cache.h +++ b/chromium/cc/tiles/image_decode_cache.h @@ -87,15 +87,18 @@ class CC_EXPORT ImageDecodeCache { virtual ~ImageDecodeCache() {} struct CC_EXPORT TaskResult { - explicit TaskResult(bool need_unref); - explicit TaskResult(scoped_refptr<TileTask> task); + explicit TaskResult(bool need_unref, + bool is_at_raster_decode, + bool can_do_hardware_accelerated_decode); + explicit TaskResult(scoped_refptr<TileTask> task, + bool can_do_hardware_accelerated_decode); TaskResult(const TaskResult& result); ~TaskResult(); - bool IsAtRaster() const { return !task && !need_unref; } - scoped_refptr<TileTask> task; bool need_unref = false; + bool is_at_raster_decode = false; + bool can_do_hardware_accelerated_decode = false; }; // Fill in an TileTask which will decode the given image when run. In // case the image is already cached, fills in nullptr. Returns true if the diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc index cbe8511f196..a0077ff4e3d 100644 --- a/chromium/cc/tiles/software_image_decode_cache.cc +++ b/chromium/cc/tiles/software_image_decode_cache.cc @@ -6,6 +6,10 @@ #include <stdint.h> +#include <algorithm> +#include <string> +#include <utility> + #include "base/bind.h" #include "base/format_macros.h" #include "base/metrics/histogram_macros.h" @@ -205,10 +209,12 @@ SoftwareImageDecodeCache::GetTaskForImageAndRefInternal( // If the target size is empty, we can skip this image during draw (and thus // we don't need to decode it or ref it). if (key.target_size().IsEmpty()) - return TaskResult(false); + return TaskResult(/*need_unref=*/false, /*is_at_raster_decode=*/false, + /*can_do_hardware_accelerated_decode=*/false); if (!UseCacheForDrawImage(image)) - return TaskResult(false); + return TaskResult(/*need_unref=*/false, /*is_at_raster_decode=*/false, + /*can_do_hardware_accelerated_decode=*/false); base::AutoLock lock(lock_); @@ -221,7 +227,8 @@ SoftwareImageDecodeCache::GetTaskForImageAndRefInternal( if (decoded_it == decoded_images_.end()) { // There is no reason to create a new entry if we know it won't fit anyway. if (!new_image_fits_in_memory) - return TaskResult(false); + return TaskResult(/*need_unref=*/false, /*is_at_raster_decode=*/true, + /*can_do_hardware_accelerated_decode=*/false); cache_entry = AddCacheEntry(key); if (task_type == DecodeTaskType::USE_OUT_OF_RASTER_TASKS) cache_entry->mark_out_of_raster(); @@ -234,7 +241,8 @@ SoftwareImageDecodeCache::GetTaskForImageAndRefInternal( if (!new_image_fits_in_memory) { // We don't need to ref anything here because this image will be at // raster. - return TaskResult(false); + return TaskResult(/*need_unref=*/false, /*is_at_raster_decode=*/true, + /*can_do_hardware_accelerated_decode=*/false); } AddBudgetForImage(key, cache_entry); } @@ -247,7 +255,8 @@ SoftwareImageDecodeCache::GetTaskForImageAndRefInternal( // If we already have a locked entry, then we can just use that. Otherwise // we'll have to create a task. if (cache_entry->is_locked) - return TaskResult(true); + return TaskResult(/*need_unref=*/true, /*is_at_raster_decode=*/false, + /*can_do_hardware_accelerated_decode=*/false); scoped_refptr<TileTask>& task = task_type == DecodeTaskType::USE_IN_RASTER_TASKS @@ -259,7 +268,7 @@ SoftwareImageDecodeCache::GetTaskForImageAndRefInternal( task = base::MakeRefCounted<SoftwareImageDecodeTaskImpl>( this, key, image.paint_image(), task_type, tracing_info); } - return TaskResult(task); + return TaskResult(task, /*can_do_hardware_accelerated_decode=*/false); } void SoftwareImageDecodeCache::AddBudgetForImage(const CacheKey& key, @@ -267,7 +276,6 @@ void SoftwareImageDecodeCache::AddBudgetForImage(const CacheKey& key, TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::AddBudgetForImage", "key", key.ToString()); - lock_.AssertAcquired(); DCHECK(!entry->is_budgeted); DCHECK_GE(locked_images_budget_.AvailableMemoryBytes(), key.locked_bytes()); @@ -280,7 +288,6 @@ void SoftwareImageDecodeCache::RemoveBudgetForImage(const CacheKey& key, TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::RemoveBudgetForImage", "key", key.ToString()); - lock_.AssertAcquired(); DCHECK(entry->is_budgeted); locked_images_budget_.SubtractUsage(key.locked_bytes()); @@ -297,7 +304,6 @@ void SoftwareImageDecodeCache::UnrefImage(const DrawImage& image) { } void SoftwareImageDecodeCache::UnrefImage(const CacheKey& key) { - lock_.AssertAcquired(); auto decoded_image_it = decoded_images_.Peek(key); DCHECK(decoded_image_it != decoded_images_.end()); auto* entry = decoded_image_it->second.get(); @@ -340,7 +346,6 @@ SoftwareImageDecodeCache::DecodeImageIfNecessary(const CacheKey& key, TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::DecodeImageIfNecessary", "key", key.ToString()); - lock_.AssertAcquired(); DCHECK_GT(entry->ref_count, 0); if (key.target_size().IsEmpty()) @@ -550,7 +555,6 @@ DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDrawInternal( "SoftwareImageDecodeCache::GetDecodedImageForDrawInternal", "key", key.ToString()); - lock_.AssertAcquired(); auto decoded_it = decoded_images_.Get(key); CacheEntry* cache_entry = nullptr; if (decoded_it == decoded_images_.end()) @@ -695,13 +699,17 @@ void SoftwareImageDecodeCache::OnMemoryPressure( SoftwareImageDecodeCache::CacheEntry* SoftwareImageDecodeCache::AddCacheEntry( const CacheKey& key) { - lock_.AssertAcquired(); frame_key_to_image_keys_[key.frame_key()].push_back(key); auto it = decoded_images_.Put(key, std::make_unique<CacheEntry>()); it->second.get()->mark_cached(); return it->second.get(); } +size_t SoftwareImageDecodeCache::GetNumCacheEntriesForTesting() { + base::AutoLock lock(lock_); + return decoded_images_.size(); +} + // MemoryBudget ---------------------------------------------------------------- SoftwareImageDecodeCache::MemoryBudget::MemoryBudget(size_t limit_bytes) : limit_bytes_(limit_bytes), current_usage_bytes_(0u) {} diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h index 994194b9fcb..274528d95db 100644 --- a/chromium/cc/tiles/software_image_decode_cache.h +++ b/chromium/cc/tiles/software_image_decode_cache.h @@ -9,11 +9,13 @@ #include <memory> #include <unordered_map> +#include <vector> #include "base/containers/mru_cache.h" #include "base/memory/memory_pressure_listener.h" #include "base/memory/ref_counted.h" #include "base/numerics/safe_math.h" +#include "base/thread_annotations.h" #include "base/trace_event/memory_dump_provider.h" #include "cc/cc_export.h" #include "cc/paint/draw_image.h" @@ -72,7 +74,7 @@ class CC_EXPORT SoftwareImageDecodeCache bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) override; - size_t GetNumCacheEntriesForTesting() const { return decoded_images_.size(); } + size_t GetNumCacheEntriesForTesting(); private: using CacheEntry = Utils::CacheEntry; @@ -98,69 +100,67 @@ class CC_EXPORT SoftwareImageDecodeCache using ImageMRUCache = base:: HashingMRUCache<CacheKey, std::unique_ptr<CacheEntry>, CacheKeyHash>; - // Actually decode the image. Note that this function can (and should) be - // called with no lock acquired, since it can do a lot of work. Note that it - // can also return nullptr to indicate the decode failed. - std::unique_ptr<CacheEntry> DecodeImageInternal(const CacheKey& key, - const DrawImage& draw_image); - // Get the decoded draw image for the given key and paint_image. Note that - // this function has to be called with no lock acquired, since it will acquire - // its own locks and might call DecodeImageInternal above. Note that // when used internally, we still require that DrawWithImageFinished() is // called afterwards. - DecodedDrawImage GetDecodedImageForDrawInternal( - const CacheKey& key, - const PaintImage& paint_image); + DecodedDrawImage GetDecodedImageForDrawInternal(const CacheKey& key, + const PaintImage& paint_image) + EXCLUSIVE_LOCKS_REQUIRED(lock_); // Removes unlocked decoded images until the number of decoded images is // reduced within the given limit. - void ReduceCacheUsageUntilWithinLimit(size_t limit); + void ReduceCacheUsageUntilWithinLimit(size_t limit) + EXCLUSIVE_LOCKS_REQUIRED(lock_); - void OnMemoryPressure( - base::MemoryPressureListener::MemoryPressureLevel level); + void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel level) + LOCKS_EXCLUDED(lock_); // Helper method to get the different tasks. Note that this should be used as // if it was public (ie, all of the locks need to be properly acquired). TaskResult GetTaskForImageAndRefInternal(const DrawImage& image, const TracingInfo& tracing_info, - DecodeTaskType type); + DecodeTaskType type) + LOCKS_EXCLUDED(lock_); - CacheEntry* AddCacheEntry(const CacheKey& key); + CacheEntry* AddCacheEntry(const CacheKey& key) + EXCLUSIVE_LOCKS_REQUIRED(lock_); TaskProcessingResult DecodeImageIfNecessary(const CacheKey& key, const PaintImage& paint_image, - CacheEntry* cache_entry); - void AddBudgetForImage(const CacheKey& key, CacheEntry* entry); - void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry); - base::Optional<CacheKey> FindCachedCandidate(const CacheKey& key); + CacheEntry* cache_entry) + EXCLUSIVE_LOCKS_REQUIRED(lock_); + void AddBudgetForImage(const CacheKey& key, CacheEntry* entry) + EXCLUSIVE_LOCKS_REQUIRED(lock_); + void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry) + EXCLUSIVE_LOCKS_REQUIRED(lock_); + base::Optional<CacheKey> FindCachedCandidate(const CacheKey& key) + EXCLUSIVE_LOCKS_REQUIRED(lock_); - void UnrefImage(const CacheKey& key); + void UnrefImage(const CacheKey& key) EXCLUSIVE_LOCKS_REQUIRED(lock_); - // The members below this comment can only be accessed if the lock is held to - // ensure that they are safe to access on multiple threads. - // The exception is accessing |locked_images_budget_.total_limit_bytes()|, - // which is const and thread safe. base::Lock lock_; - // Decoded images and ref counts (predecode path). - ImageMRUCache decoded_images_; + ImageMRUCache decoded_images_ GUARDED_BY(lock_); - std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; + std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_ + GUARDED_BY(lock_); // A map of PaintImage::FrameKey to the ImageKeys for cached decodes of this // PaintImage. std::unordered_map<PaintImage::FrameKey, std::vector<CacheKey>, PaintImage::FrameKeyHash> - frame_key_to_image_keys_; + frame_key_to_image_keys_ GUARDED_BY(lock_); + // Should be GUARDED_BY(lock_), except that accessing + // |locked_images_budget_.total_limit_bytes()| is fine without the lock, as + // it is const and thread safe. MemoryBudget locked_images_budget_; const SkColorType color_type_; const PaintImage::GeneratorClientId generator_client_id_; - size_t max_items_in_cache_; + const size_t max_items_in_cache_; }; } // namespace cc diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc index 5ec8b2642fe..3fd32784f08 100644 --- a/chromium/cc/tiles/tile_manager.cc +++ b/chromium/cc/tiles/tile_manager.cc @@ -845,12 +845,6 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { } } - if (had_enough_memory_to_schedule_tiles_needed_now) { - int64_t tiles_gpu_memory_kb = memory_usage.memory_bytes() / 1024; - UMA_HISTOGRAM_MEMORY_KB("TileManager.TilesGPUMemoryUsage2", - tiles_gpu_memory_kb); - } - UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget", !had_enough_memory_to_schedule_tiles_needed_now); did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now; @@ -1135,11 +1129,14 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "TileManager::CreateRasterTask", "Tile", tile->id()); + const int msaa_sample_count = client_->GetMSAASampleCountForRaster( + prioritized_tile.raster_source()->GetDisplayItemList()); + // Get the resource. ResourcePool::InUsePoolResource resource; uint64_t resource_content_id = 0; gfx::Rect invalidated_rect = tile->invalidated_content_rect(); - if (UsePartialRaster() && tile->invalidated_id()) { + if (UsePartialRaster(msaa_sample_count) && tile->invalidated_id()) { resource = resource_pool_->TryAcquireResourceForPartialRaster( tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(), &invalidated_rect); @@ -1162,6 +1159,7 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( const bool skip_images = prioritized_tile.priority().resolution == LOW_RESOLUTION; playback_settings.use_lcd_text = tile->can_use_lcd_text(); + playback_settings.msaa_sample_count = msaa_sample_count; // Create and queue all image decode tasks that this tile depends on. Note // that we need to store the images for decode tasks in @@ -1185,8 +1183,12 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( prepare_tiles_count_, prioritized_tile.priority().priority_bin, ImageDecodeCache::TaskType::kInRaster); bool has_at_raster_images = false; - image_controller_.ConvertImagesToTasks(&sync_decoded_images, &decode_tasks, - &has_at_raster_images, tracing_info); + bool has_hardware_accelerated_jpeg_candidates = false; + bool has_hardware_accelerated_webp_candidates = false; + image_controller_.ConvertImagesToTasks( + &sync_decoded_images, &decode_tasks, &has_at_raster_images, + &has_hardware_accelerated_jpeg_candidates, + &has_hardware_accelerated_webp_candidates, tracing_info); // Notify |decoded_image_tracker_| after |image_controller_| to ensure we've // taken new refs on the images before releasing the predecode API refs. decoded_image_tracker_.OnImagesUsedInDraw(sync_decoded_images); @@ -1227,7 +1229,9 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( std::unique_ptr<RasterBuffer> raster_buffer = raster_buffer_provider_->AcquireBufferForRaster( - resource, resource_content_id, tile->invalidated_id()); + resource, resource_content_id, tile->invalidated_id(), + has_at_raster_images, has_hardware_accelerated_jpeg_candidates, + has_hardware_accelerated_webp_candidates); base::Optional<PlaybackImageProvider::Settings> settings; if (!skip_images) { @@ -1611,9 +1615,13 @@ TileManager::ScheduledTasksStateAsValue() const { return std::move(state); } -bool TileManager::UsePartialRaster() const { +bool TileManager::UsePartialRaster(int msaa_sample_count) const { + // Partial raster doesn't support MSAA, as the MSAA resolve is unaware of clip + // rects. + // TODO(crbug.com/629683): See if we can work around this limitation. return tile_manager_settings_.use_partial_raster && - raster_buffer_provider_->CanPartialRasterIntoProvidedResource(); + raster_buffer_provider_->CanPartialRasterIntoProvidedResource() && + msaa_sample_count == 0; } void TileManager::CheckPendingGpuWorkAndIssueSignals() { diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h index afa7d42ef37..c41a1355440 100644 --- a/chromium/cc/tiles/tile_manager.h +++ b/chromium/cc/tiles/tile_manager.h @@ -87,9 +87,14 @@ class CC_EXPORT TileManagerClient { // rasterized with missing images need to be invalidated. virtual void RequestImplSideInvalidationForCheckerImagedTiles() = 0; + // Returns the frame index to display for the given image on the given tree. virtual size_t GetFrameIndexForImage(const PaintImage& paint_image, WhichTree tree) const = 0; + // Returns the sample count to use if MSAA is enabled for a tile. + virtual int GetMSAASampleCountForRaster( + const scoped_refptr<DisplayItemList>& display_list) = 0; + protected: virtual ~TileManagerClient() {} }; @@ -202,7 +207,11 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { tiles[i]->desired_texture_size(), raster_buffer_provider_->GetResourceFormat(), client_->GetRasterColorSpace()); - raster_buffer_provider_->AcquireBufferForRaster(resource, 0, 0); + raster_buffer_provider_->AcquireBufferForRaster( + resource, 0, 0, + /*depends_on_at_raster_decodes=*/false, + /*depends_on_hardware_accelerated_jpeg_candidates=*/false, + /*depends_on_hardware_accelerated_webp_candidates=*/false); // The raster here never really happened, cuz tests. So just add an // arbitrary sync token. if (resource.gpu_backing()) { @@ -399,7 +408,7 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { std::unique_ptr<base::trace_event::ConvertableToTraceFormat> ScheduledTasksStateAsValue() const; - bool UsePartialRaster() const; + bool UsePartialRaster(int msaa_sample_count) const; void FlushAndIssueSignals(); void CheckPendingGpuWorkAndIssueSignals(); diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc index 56410fea4fc..dc0be3ff8fc 100644 --- a/chromium/cc/tiles/tile_manager_unittest.cc +++ b/chromium/cc/tiles/tile_manager_unittest.cc @@ -1531,7 +1531,10 @@ class TestSoftwareRasterBufferProvider : public FakeRasterBufferProviderImpl { std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override { if (!resource.software_backing()) { auto backing = std::make_unique<TestSoftwareBacking>(); backing->shared_bitmap_id = viz::SharedBitmap::GenerateId(); @@ -1969,7 +1972,10 @@ class VerifyResourceContentIdRasterBufferProvider std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override { EXPECT_EQ(expected_content_id_, resource_content_id); return nullptr; } @@ -2167,7 +2173,10 @@ class InvalidResourceRasterBufferProvider std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override { if (!resource.gpu_backing()) { auto backing = std::make_unique<StubGpuBacking>(); // Don't set a mailbox to signal invalid resource. @@ -2263,7 +2272,10 @@ class MockReadyToDrawRasterBufferProviderImpl std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override { if (!resource.software_backing()) resource.set_software_backing(std::make_unique<TestSoftwareBacking>()); return std::make_unique<FakeRasterBuffer>(); @@ -3251,7 +3263,10 @@ class VerifyImageProviderRasterBufferProvider std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, - uint64_t previous_content_id) override { + uint64_t previous_content_id, + bool depends_on_at_raster_decodes, + bool depends_on_hardware_accelerated_jpeg_candidates, + bool depends_on_hardware_accelerated_webp_candidates) override { buffer_count_++; return std::make_unique<VerifyImageProviderRasterBuffer>(); } diff --git a/chromium/cc/tiles/tile_priority.cc b/chromium/cc/tiles/tile_priority.cc index 7898163053e..606a8c64e0b 100644 --- a/chromium/cc/tiles/tile_priority.cc +++ b/chromium/cc/tiles/tile_priority.cc @@ -86,6 +86,21 @@ std::string TreePriorityToString(TreePriority prio) { } } +perfetto::protos::pbzero::ChromeCompositorStateMachine::MinorState::TreePriority +TreePriorityToProtozeroEnum(TreePriority priority) { + using pbzeroMinorState = + perfetto::protos::pbzero::ChromeCompositorStateMachine::MinorState; + switch (priority) { + case TreePriority::SAME_PRIORITY_FOR_BOTH_TREES: + return pbzeroMinorState::TREE_PRIORITY_SAME_PRIORITY_FOR_BOTH_TREES; + case TreePriority::SMOOTHNESS_TAKES_PRIORITY: + return pbzeroMinorState::TREE_PRIORITY_SMOOTHNESS_TAKES_PRIORITY; + case TreePriority::NEW_CONTENT_TAKES_PRIORITY: + return pbzeroMinorState::TREE_PRIORITY_NEW_CONTENT_TAKES_PRIORITY; + } + return pbzeroMinorState::TREE_PRIORITY_UNSPECIFIED; +} + void GlobalStateThatImpactsTilePriority::AsValueInto( base::trace_event::TracedValue* state) const { state->SetString("memory_limit_policy", diff --git a/chromium/cc/tiles/tile_priority.h b/chromium/cc/tiles/tile_priority.h index 6b0628aac30..34cd3bc0c5d 100644 --- a/chromium/cc/tiles/tile_priority.h +++ b/chromium/cc/tiles/tile_priority.h @@ -14,6 +14,7 @@ #include "base/trace_event/traced_value.h" #include "cc/cc_export.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h" namespace base { class Value; @@ -90,7 +91,11 @@ enum TreePriority { LAST_TREE_PRIORITY = NEW_CONTENT_TAKES_PRIORITY // Be sure to update TreePriorityAsValue when adding new fields. }; +// TODO(nuskos): remove TreePriorityToString once we have a utility function to +// take protozero to strings. std::string TreePriorityToString(TreePriority prio); +perfetto::protos::pbzero::ChromeCompositorStateMachine::MinorState::TreePriority +TreePriorityToProtozeroEnum(TreePriority priority); class GlobalStateThatImpactsTilePriority { public: diff --git a/chromium/cc/trees/browser_controls_params.cc b/chromium/cc/trees/browser_controls_params.cc new file mode 100644 index 00000000000..4c762b335b2 --- /dev/null +++ b/chromium/cc/trees/browser_controls_params.cc @@ -0,0 +1,26 @@ +// Copyright 2019 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. + +#include "cc/trees/browser_controls_params.h" + +namespace cc { + +bool BrowserControlsParams::operator==( + const BrowserControlsParams& other) const { + return top_controls_height == other.top_controls_height && + top_controls_min_height == other.top_controls_min_height && + bottom_controls_height == other.bottom_controls_height && + bottom_controls_min_height == other.bottom_controls_min_height && + animate_browser_controls_height_changes == + other.animate_browser_controls_height_changes && + browser_controls_shrink_blink_size == + other.browser_controls_shrink_blink_size; +} + +bool BrowserControlsParams::operator!=( + const BrowserControlsParams& other) const { + return !(*this == other); +} + +} // namespace cc diff --git a/chromium/cc/trees/browser_controls_params.h b/chromium/cc/trees/browser_controls_params.h new file mode 100644 index 00000000000..7ef5326c9b7 --- /dev/null +++ b/chromium/cc/trees/browser_controls_params.h @@ -0,0 +1,44 @@ +// Copyright 2019 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_TREES_BROWSER_CONTROLS_PARAMS_H_ +#define CC_TREES_BROWSER_CONTROLS_PARAMS_H_ + +#include "cc/cc_export.h" + +namespace cc { + +struct CC_EXPORT BrowserControlsParams { + BrowserControlsParams() = default; + BrowserControlsParams(const BrowserControlsParams& other) = default; + ~BrowserControlsParams() = default; + + // The height of the top controls (always 0 on platforms where URL-bar hiding + // isn't supported). + float top_controls_height = 0.f; + + // The minimum visible height of the top controls. + float top_controls_min_height = 0.f; + + // The height of the bottom controls. + float bottom_controls_height = 0.f; + + // The minimum visible height of the bottom controls. + float bottom_controls_min_height = 0.f; + + // Whether or not the changes to the browser controls heights should be + // animated. + bool animate_browser_controls_height_changes = false; + + // Whether or not Blink's viewport size should be shrunk by the height of the + // URL-bar (always false on platforms where URL-bar hiding isn't supported). + bool browser_controls_shrink_blink_size = false; + + bool operator==(const BrowserControlsParams& other) const; + bool operator!=(const BrowserControlsParams& other) const; +}; + +} // namespace cc + +#endif // CC_TREES_BROWSER_CONTROLS_PARAMS_H_ diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc index d2636625dfb..42d0fe8a76c 100644 --- a/chromium/cc/trees/damage_tracker_unittest.cc +++ b/chromium/cc/trees/damage_tracker_unittest.cc @@ -63,6 +63,7 @@ void ClearDamageForAllSurfaces(LayerImpl* root) { for (auto* layer : *root->layer_tree_impl()) { if (GetRenderSurface(layer)) GetRenderSurface(layer)->damage_tracker()->DidDrawDamagedArea(); + layer->ResetChangeTracking(); } } @@ -254,7 +255,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) { // CASE 1: Setting the update rect should cause the corresponding damage to // the surface. ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); + child->UnionUpdateRect(gfx::Rect(10, 11, 12, 13)); EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of update_rect (10, 11) @@ -268,7 +269,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) { // CASE 2: The same update rect twice in a row still produces the same // damage. ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); + child->UnionUpdateRect(gfx::Rect(10, 11, 12, 13)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( &root_damage_rect)); @@ -278,7 +279,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) { // CASE 3: Setting a different update rect should cause damage on the new // update region, but no additional exposed old region. ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(20, 25, 1, 2)); + child->UnionUpdateRect(gfx::Rect(20, 25, 1, 2)); EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of update_rect (20, 25) @@ -355,7 +356,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { // corresponding damage to the surface. ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(5, 6, 12, 13)); - child->SetUpdateRect(gfx::Rect(15, 16, 14, 10)); + child->UnionUpdateRect(gfx::Rect(15, 16, 14, 10)); EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of unified layer @@ -370,7 +371,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { // produces the same damage. ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); - child->SetUpdateRect(gfx::Rect(10, 11, 14, 15)); + child->UnionUpdateRect(gfx::Rect(10, 11, 14, 15)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( &root_damage_rect)); @@ -380,7 +381,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { // damage on the new damaged region, but no additional exposed old region. ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(20, 25, 2, 3)); - child->SetUpdateRect(gfx::Rect(5, 10, 7, 8)); + child->UnionUpdateRect(gfx::Rect(5, 10, 7, 8)); EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of unified layer damage @@ -402,7 +403,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) { CreateEffectNode(child).render_surface_reason = RenderSurfaceReason::kTest; EmulateDrawingOneFrame(root); ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); + child->UnionUpdateRect(gfx::Rect(10, 11, 12, 13)); root->layer_tree_impl()->SetOpacityMutated(child->element_id(), 0.5f); EmulateDrawingOneFrame(root); @@ -560,7 +561,7 @@ TEST_F(DamageTrackerTest, child1_->SetDrawsContent(true); ClearDamageForAllSurfaces(root); child1_->AddDamageRect(gfx::Rect(105, 106, 12, 15)); - child1_->SetUpdateRect(gfx::Rect(115, 116, 12, 15)); + child1_->UnionUpdateRect(gfx::Rect(115, 116, 12, 15)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root) ->damage_tracker() @@ -573,7 +574,7 @@ TEST_F(DamageTrackerTest, // corresponding damage to the surface. ClearDamageForAllSurfaces(root); child2_->AddDamageRect(gfx::Rect(11, 11, 12, 15)); - child2_->SetUpdateRect(gfx::Rect(12, 12, 12, 15)); + child2_->UnionUpdateRect(gfx::Rect(12, 12, 12, 15)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root) ->damage_tracker() @@ -586,7 +587,7 @@ TEST_F(DamageTrackerTest, // the corresponding damage to the surface. ClearDamageForAllSurfaces(root); grand_child1_->AddDamageRect(gfx::Rect(1, 0, 2, 5)); - grand_child1_->SetUpdateRect(gfx::Rect(2, 1, 2, 5)); + grand_child1_->UnionUpdateRect(gfx::Rect(2, 1, 2, 5)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root) ->damage_tracker() @@ -762,7 +763,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBlurredSurface) { // Setting the update rect should cause the corresponding damage to the // surface, blurred based on the size of the blur filter. ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(1, 2, 3, 4)); + child->UnionUpdateRect(gfx::Rect(1, 2, 3, 4)); EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of update_rect (1, 2) @@ -822,7 +823,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) { // CASE 1: Setting the update rect should damage the whole surface (for now) ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(1, 1)); + child->UnionUpdateRect(gfx::Rect(1, 1)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -911,7 +912,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedImageFilter) { // Setting the update rect should damage the whole surface (for now) ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(30, 30)); + child->UnionUpdateRect(gfx::Rect(30, 30)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -970,7 +971,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForHighDPIImageFilter) { // Setting the update rect should damage only the affected area (original, // outset by 3 * blur sigma * DSF). ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(30, 30)); + child->UnionUpdateRect(gfx::Rect(30, 30)); EmulateDrawingOneFrame(root, device_scale_factor); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1002,7 +1003,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { // blur filter. Note that child1_'s render surface has a size of // 206x208 due to contributions from grand_child1_ and grand_child2_. ClearDamageForAllSurfaces(root); - root->SetUpdateRect(gfx::Rect(297, 297, 2, 2)); + root->UnionUpdateRect(gfx::Rect(297, 297, 2, 2)); EmulateDrawingOneFrame(root); gfx::Rect root_damage_rect; @@ -1022,7 +1023,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { // blur filter. Since the damage extends to the right/bottom outside // of the blurred layer, only the left/top should end up expanded. ClearDamageForAllSurfaces(root); - root->SetUpdateRect(gfx::Rect(297, 297, 30, 30)); + root->UnionUpdateRect(gfx::Rect(297, 297, 30, 30)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1039,7 +1040,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { // CASE 3: Setting this update rect outside the blurred content_bounds of the // blurred child1_ will not cause it to be expanded. ClearDamageForAllSurfaces(root); - root->SetUpdateRect(gfx::Rect(30, 30, 2, 2)); + root->UnionUpdateRect(gfx::Rect(30, 30, 2, 2)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1054,7 +1055,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { // outside the original content_bounds of the blurred child1_ will // cause it to be expanded. ClearDamageForAllSurfaces(root); - root->SetUpdateRect(gfx::Rect(99, 99, 1, 1)); + root->UnionUpdateRect(gfx::Rect(99, 99, 1, 1)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1070,7 +1071,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { // CASE 5: Setting the update rect on child2_, which is above child1_, will // not get blurred by child1_, so it does not need to get expanded. ClearDamageForAllSurfaces(root); - child2_->SetUpdateRect(gfx::Rect(1, 1)); + child2_->UnionUpdateRect(gfx::Rect(1, 1)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1085,7 +1086,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackdropBlurredChild) { // that any pixels needed for the blur are redrawn in the current // frame. ClearDamageForAllSurfaces(root); - child1_->SetUpdateRect(gfx::Rect(1, 1)); + child1_->UnionUpdateRect(gfx::Rect(1, 1)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1235,8 +1236,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) { // - child1_ update rect in surface space: gfx::Rect(100, 100, 1, 2); // - child2_ update rect in surface space: gfx::Rect(400, 380, 3, 4); ClearDamageForAllSurfaces(root); - child1->SetUpdateRect(gfx::Rect(1, 2)); - child2->SetUpdateRect(gfx::Rect(3, 4)); + child1->UnionUpdateRect(gfx::Rect(1, 2)); + child2->UnionUpdateRect(gfx::Rect(3, 4)); EmulateDrawingOneFrame(root); gfx::Rect root_damage_rect; EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( @@ -1536,7 +1537,7 @@ TEST_F(DamageTrackerTest, VerifyNoDamageForUpdateRectThatDoesNotDrawContent) { // In our specific tree, the update rect of child1_ should not cause any // damage to any surface because it does not actually draw content. ClearDamageForAllSurfaces(root); - child1_->SetUpdateRect(gfx::Rect(1, 2)); + child1_->UnionUpdateRect(gfx::Rect(1, 2)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(child1_)->damage_tracker()->GetDamageRectIfValid( &child_damage_rect)); @@ -1589,7 +1590,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) { // CASE 1: the update_rect on a mask layer should damage the rect. ClearDamageForAllSurfaces(root); - mask_layer->SetUpdateRect(gfx::Rect(1, 2, 3, 4)); + mask_layer->UnionUpdateRect(gfx::Rect(1, 2, 3, 4)); EmulateDrawingOneFrame(root); gfx::Rect child_damage_rect; EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid( @@ -1676,7 +1677,7 @@ TEST_F(DamageTrackerTest, DamageWhenAddedExternally) { // it is included with any other partial damage. // ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); + child->UnionUpdateRect(gfx::Rect(10, 11, 12, 13)); GetRenderSurface(root)->damage_tracker()->AddDamageNextUpdate( gfx::Rect(15, 16, 32, 33)); EmulateDrawingOneFrame(root); @@ -1732,7 +1733,7 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) { LayerImpl* child = child_layers_[0]; ClearDamageForAllSurfaces(root); - child->SetUpdateRect(gfx::Rect(10.f, 11.f, 1.f, 2.f)); + child->UnionUpdateRect(gfx::Rect(10.f, 11.f, 1.f, 2.f)); EmulateDrawingOneFrame(root); // Sanity check damage after the first frame; this isnt the actual test yet. @@ -1746,7 +1747,7 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) { // New damage, without having cleared the previous damage, should be unioned // to the previous one. - child->SetUpdateRect(gfx::Rect(20, 25, 1, 2)); + child->UnionUpdateRect(gfx::Rect(20, 25, 1, 2)); EmulateDrawingOneFrame(root); EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid( &root_damage_rect)); diff --git a/chromium/cc/trees/debug_rect_history.cc b/chromium/cc/trees/debug_rect_history.cc index ca985285ffb..2fee9221061 100644 --- a/chromium/cc/trees/debug_rect_history.cc +++ b/chromium/cc/trees/debug_rect_history.cc @@ -50,6 +50,9 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame( if (debug_state.show_non_fast_scrollable_rects) SaveNonFastScrollableRects(tree_impl); + if (debug_state.show_main_thread_scrolling_reason_rects) + SaveMainThreadScrollingReasonRects(tree_impl); + if (debug_state.show_layout_shift_regions) SaveLayoutShiftRects(hud_layer); @@ -205,4 +208,23 @@ void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) { } } +void DebugRectHistory::SaveMainThreadScrollingReasonRects( + LayerTreeImpl* tree_impl) { + const auto& scroll_tree = tree_impl->property_trees()->scroll_tree; + for (auto* layer : *tree_impl) { + if (layer->scrollable()) { + if (const auto* scroll_node = + scroll_tree.Node(layer->scroll_tree_index())) { + if (auto reasons = scroll_node->main_thread_scrolling_reasons) { + debug_rects_.push_back(DebugRect( + MAIN_THREAD_SCROLLING_REASON_RECT_TYPE, + MathUtil::MapEnclosingClippedRect(layer->ScreenSpaceTransform(), + gfx::Rect(layer->bounds())), + kTouchActionNone, reasons)); + } + } + } + } +} + } // namespace cc diff --git a/chromium/cc/trees/debug_rect_history.h b/chromium/cc/trees/debug_rect_history.h index d9b6da071b9..a24b5d8ee88 100644 --- a/chromium/cc/trees/debug_rect_history.h +++ b/chromium/cc/trees/debug_rect_history.h @@ -46,6 +46,7 @@ enum DebugRectType { WHEEL_EVENT_HANDLER_RECT_TYPE, SCROLL_EVENT_HANDLER_RECT_TYPE, NON_FAST_SCROLLABLE_RECT_TYPE, + MAIN_THREAD_SCROLLING_REASON_RECT_TYPE, ANIMATION_BOUNDS_RECT_TYPE, LAYOUT_SHIFT_RECT_TYPE, }; @@ -53,19 +54,24 @@ enum DebugRectType { struct DebugRect { DebugRect(DebugRectType new_type, const gfx::Rect& new_rect, - TouchAction new_touch_action) - : type(new_type), rect(new_rect), touch_action(new_touch_action) { + TouchAction new_touch_action = kTouchActionNone, + uint32_t main_thread_scrolling_reasons = 0) + : type(new_type), + rect(new_rect), + touch_action(new_touch_action), + main_thread_scrolling_reasons(main_thread_scrolling_reasons) { if (type != TOUCH_EVENT_HANDLER_RECT_TYPE) DCHECK_EQ(touch_action, kTouchActionNone); + if (type != MAIN_THREAD_SCROLLING_REASON_RECT_TYPE) + DCHECK(!main_thread_scrolling_reasons); } - DebugRect(DebugRectType new_type, const gfx::Rect& new_rect) - : DebugRect(new_type, new_rect, kTouchActionNone) {} - DebugRectType type; gfx::Rect rect; // Valid when |type| is |TOUCH_EVENT_HANDLER_RECT_TYPE|, otherwise default to // |kTouchActionNone|. TouchAction touch_action; + // Valid when |type| is |MAIN_THREAD_SCROLLING_REASON_RECT_TYPE|, otherwise 0. + uint32_t main_thread_scrolling_reasons; }; // This class maintains a history of rects of various types that can be used @@ -105,6 +111,7 @@ class DebugRectHistory { void SaveScrollEventHandlerRectsCallback(LayerImpl* layer); void SaveNonFastScrollableRects(LayerTreeImpl* layer); void SaveNonFastScrollableRectsCallback(LayerImpl* layer); + void SaveMainThreadScrollingReasonRects(LayerTreeImpl*); std::vector<DebugRect> debug_rects_; }; diff --git a/chromium/cc/trees/draw_properties_unittest.cc b/chromium/cc/trees/draw_properties_unittest.cc index 93acf2883ce..070ef175267 100644 --- a/chromium/cc/trees/draw_properties_unittest.cc +++ b/chromium/cc/trees/draw_properties_unittest.cc @@ -21,7 +21,6 @@ #include "cc/layers/content_layer_client.h" #include "cc/layers/effect_tree_layer_list_iterator.h" #include "cc/layers/layer.h" -#include "cc/layers/layer_client.h" #include "cc/layers/layer_impl.h" #include "cc/layers/render_surface_impl.h" #include "cc/test/animation_test_common.h" @@ -6160,8 +6159,7 @@ TEST_F(DrawPropertiesTest, ViewportBoundsDeltaAffectVisibleContentRect) { LayerTreeImpl* active_tree = host_impl()->active_tree(); active_tree->SetDeviceViewportRect(device_viewport_rect); - active_tree->set_browser_controls_shrink_blink_size(true); - active_tree->SetTopControlsHeight(50); + active_tree->SetBrowserControlsParams({50, 0, 0, 0, false, true}); active_tree->PushPageScaleFromMainThread(1.0f, 1.0f, 1.0f); LayerImpl* root = root_layer(); @@ -6171,12 +6169,12 @@ TEST_F(DrawPropertiesTest, ViewportBoundsDeltaAffectVisibleContentRect) { LayerImpl* scroll_layer = InnerViewportScrollLayer(); scroll_layer->SetDrawsContent(true); - active_tree->SetCurrentBrowserControlsShownRatio(1.0f); + active_tree->SetCurrentBrowserControlsShownRatio(1.0f, 1.0f); active_tree->UpdateViewportContainerSizes(); UpdateActiveTreeDrawProperties(); EXPECT_EQ(gfx::Rect(container_size), scroll_layer->visible_layer_rect()); - active_tree->SetCurrentBrowserControlsShownRatio(0.0f); + active_tree->SetCurrentBrowserControlsShownRatio(0.0f, 0.0f); active_tree->UpdateViewportContainerSizes(); UpdateActiveTreeDrawProperties(); diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index 09cd244629c..55391d95054 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -43,7 +43,6 @@ #include "cc/layers/painted_scrollbar_layer.h" #include "cc/paint/paint_worklet_layer_painter.h" #include "cc/resources/ui_resource_manager.h" -#include "cc/tiles/frame_viewer_instrumentation.h" #include "cc/trees/clip_node.h" #include "cc/trees/draw_property_utils.h" #include "cc/trees/effect_node.h" @@ -69,7 +68,7 @@ namespace { static base::AtomicSequenceNumber s_layer_tree_host_sequence_number; static base::AtomicSequenceNumber s_image_decode_sequence_number; -} +} // namespace namespace cc { namespace { @@ -301,8 +300,7 @@ void LayerTreeHost::RequestMainFrameUpdate(bool report_cc_metrics) { // code that is logically a main thread operation, e.g. deletion of a Layer, // should be delayed until the LayerTreeHost::CommitComplete, which will run // after the commit, but on the main thread. -void LayerTreeHost::FinishCommitOnImplThread( - LayerTreeHostImpl* host_impl) { +void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { DCHECK(task_runner_provider_->IsImplThread()); TRACE_EVENT0("cc,benchmark", "LayerTreeHost::FinishCommitOnImplThread"); @@ -458,22 +456,6 @@ void LayerTreeHost::PushPropertyTreesTo(LayerTreeImpl* tree_impl) { void LayerTreeHost::WillCommit() { swap_promise_manager_.WillCommit(); client_->WillCommit(); - - if (frame_viewer_instrumentation::IsTracingLayerTreeSnapshots()) { - bool is_new_trace; - TRACE_EVENT_IS_NEW_TRACE(&is_new_trace); - if (is_new_trace) { - // We'll be dumping layer trees as part of trace, so make sure - // PushPropertiesTo() propagates layer debug info to the impl side -- - // otherwise this won't happen for the layers that remain unchanged since - // tracing started. - for (auto* layer : *this) - layer->SetNeedsPushProperties(); - } - - for (Layer* layer : LayersThatShouldPushProperties()) - layer->UpdateDebugInfo(); - } } void LayerTreeHost::UpdateDeferMainFrameUpdateInternal() { @@ -533,8 +515,7 @@ void LayerTreeHost::DidFailToInitializeLayerTreeFrameSink() { client_->DidFailToInitializeLayerTreeFrameSink(); } -std::unique_ptr<LayerTreeHostImpl> -LayerTreeHost::CreateLayerTreeHostImpl( +std::unique_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl( LayerTreeHostImplClient* client) { DCHECK(task_runner_provider_->IsImplThread()); @@ -557,8 +538,6 @@ LayerTreeHost::CreateLayerTreeHostImpl( ukm_recorder_factory_.reset(); } - host_impl->SetContentHasSlowPaths(content_has_slow_paths_); - host_impl->SetContentHasNonAAPaint(content_has_non_aa_paint_); task_graph_runner_ = nullptr; input_handler_weak_ptr_ = host_impl->AsWeakPtr(); return host_impl; @@ -649,8 +628,7 @@ void LayerTreeHost::SetNeedsCommitWithForcedRedraw() { proxy_->SetNeedsCommit(); } -void LayerTreeHost::SetAnimationEvents( - std::unique_ptr<MutatorEvents> events) { +void LayerTreeHost::SetAnimationEvents(std::unique_ptr<MutatorEvents> events) { DCHECK(task_runner_provider_->IsMainThread()); mutator_host_->SetAnimationEvents(std::move(events)); @@ -661,8 +639,7 @@ void LayerTreeHost::SetAnimationEvents( SetNeedsAnimate(); } -void LayerTreeHost::SetDebugState( - const LayerTreeDebugState& debug_state) { +void LayerTreeHost::SetDebugState(const LayerTreeDebugState& debug_state) { LayerTreeDebugState new_debug_state = LayerTreeDebugState::Unite(settings_.initial_debug_state, debug_state); @@ -677,8 +654,7 @@ void LayerTreeHost::SetDebugState( SetNeedsCommit(); } -void LayerTreeHost::ApplyPageScaleDeltaFromImplSide( - float page_scale_delta) { +void LayerTreeHost::ApplyPageScaleDeltaFromImplSide(float page_scale_delta) { DCHECK(CommitRequested()); if (page_scale_delta == 1.f) return; @@ -778,13 +754,6 @@ void LayerTreeHost::RecordGpuRasterizationHistogram( // mostly used for debugging purposes. UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationEnabled", gpu_rasterization_enabled); - if (gpu_rasterization_enabled) { - UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationSuitableContent", - !content_has_slow_paths_); - UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationSlowPathsWithNonAAPaint", - content_has_slow_paths_ && content_has_non_aa_paint_); - } - gpu_rasterization_histogram_recorded_ = true; } @@ -862,31 +831,7 @@ bool LayerTreeHost::DoUpdateLayers() { LayerList update_layer_list; draw_property_utils::FindLayersThatNeedUpdates(this, &update_layer_list); - - bool painted_content_has_slow_paths = false; - bool painted_content_has_non_aa_paint = false; - bool did_paint_content = - PaintContent(update_layer_list, &painted_content_has_slow_paths, - &painted_content_has_non_aa_paint); - - // |painted_content_has_non_aa_paint| is a correctness (not performance) - // modifier, if it changes we immediately update. To prevent churn, this flag - // is sticky. - content_has_non_aa_paint_ |= painted_content_has_non_aa_paint; - - // If no slow-path content has appeared for a required number of frames, - // update the flag. - if (!painted_content_has_slow_paths) { - ++num_consecutive_frames_without_slow_paths_; - if (num_consecutive_frames_without_slow_paths_ >= - kNumFramesToConsiderBeforeRemovingSlowPathFlag) { - content_has_slow_paths_ = false; - } - } else { - num_consecutive_frames_without_slow_paths_ = 0; - content_has_slow_paths_ = true; - } - + bool did_paint_content = PaintContent(update_layer_list); return did_paint_content; } @@ -897,6 +842,7 @@ void LayerTreeHost::ApplyViewportChanges(const ScrollAndScaleSet& info) { if (inner_viewport_scroll_delta.IsZero() && info.page_scale_delta == 1.f && info.elastic_overscroll_delta.IsZero() && !info.top_controls_delta && + !info.bottom_controls_delta && !info.browser_controls_constraint_changed && !info.scroll_gesture_did_end && info.is_pinch_gesture_active == is_pinch_gesture_active_from_impl_) { @@ -914,6 +860,14 @@ void LayerTreeHost::ApplyViewportChanges(const ScrollAndScaleSet& info) { inner_scroll_layer->CurrentScrollOffset() + inner_viewport_scroll_delta); } + if (IsUsingLayerLists()) { + auto& scroll_tree = property_trees()->scroll_tree; + scroll_tree.NotifyDidScroll( + inner_scroll->element_id, + scroll_tree.current_scroll_offset(inner_scroll->element_id) + + inner_viewport_scroll_delta, + info.inner_viewport_scroll.snap_target_element_ids); + } } ApplyPageScaleDeltaFromImplSide(info.page_scale_delta); @@ -924,8 +878,8 @@ void LayerTreeHost::ApplyViewportChanges(const ScrollAndScaleSet& info) { client_->ApplyViewportChanges( {inner_viewport_scroll_delta, info.elastic_overscroll_delta, info.page_scale_delta, info.is_pinch_gesture_active, - info.top_controls_delta, info.browser_controls_constraint, - info.scroll_gesture_did_end}); + info.top_controls_delta, info.bottom_controls_delta, + info.browser_controls_constraint, info.scroll_gesture_did_end}); SetNeedsUpdateLayers(); } @@ -949,6 +903,7 @@ void LayerTreeHost::SendOverscrollAndScrollEndEventsFromImplSide( void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { DCHECK(info); + TRACE_EVENT0("cc", "LayerTreeHost::ApplyScrollAndScale"); for (auto& swap_promise : info->swap_promises) { TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(swap_promise->TraceId()), @@ -958,19 +913,28 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { } if (root_layer_) { - for (size_t i = 0; i < info->scrolls.size(); ++i) { - Layer* layer = LayerByElementId(info->scrolls[i].element_id); - if (!layer) - continue; - layer->SetScrollOffsetFromImplSide(layer->CurrentScrollOffset() + - info->scrolls[i].scroll_delta); - SetNeedsUpdateLayers(); + auto& scroll_tree = property_trees()->scroll_tree; + for (auto& scroll : info->scrolls) { + if (Layer* layer = LayerByElementId(scroll.element_id)) { + layer->SetScrollOffsetFromImplSide(layer->CurrentScrollOffset() + + scroll.scroll_delta); + SetNeedsUpdateLayers(); + } + if (IsUsingLayerLists()) { + TRACE_EVENT_INSTANT2( + "cc", "NotifyDidScroll", TRACE_EVENT_SCOPE_THREAD, "cur_y", + scroll_tree.current_scroll_offset(scroll.element_id).y(), "delta", + scroll.scroll_delta.y()); + scroll_tree.NotifyDidScroll( + scroll.element_id, + scroll_tree.current_scroll_offset(scroll.element_id) + + scroll.scroll_delta, + scroll.snap_target_element_ids); + } } - for (size_t i = 0; i < info->scrollbars.size(); ++i) { - Layer* layer = LayerByElementId(info->scrollbars[i].element_id); - if (!layer) - continue; - layer->SetScrollbarsHiddenFromImplSide(info->scrollbars[i].hidden); + for (auto& scrollbar : info->scrollbars) { + scroll_tree.NotifyDidChangeScrollbarsHidden(scrollbar.element_id, + scrollbar.hidden); } } @@ -992,15 +956,13 @@ void LayerTreeHost::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { client_->RecordEndOfFrameMetrics(frame_begin_time); } -const base::WeakPtr<InputHandler>& LayerTreeHost::GetInputHandler() - const { +const base::WeakPtr<InputHandler>& LayerTreeHost::GetInputHandler() const { return input_handler_weak_ptr_; } -void LayerTreeHost::UpdateBrowserControlsState( - BrowserControlsState constraints, - BrowserControlsState current, - bool animate) { +void LayerTreeHost::UpdateBrowserControlsState(BrowserControlsState constraints, + BrowserControlsState current, + bool animate) { // Browser controls are only used in threaded mode but Blink layout tests may // call into this. The single threaded version is a no-op. proxy_->UpdateBrowserControlsState(constraints, current, animate); @@ -1094,8 +1056,6 @@ void LayerTreeHost::SetRootLayer(scoped_refptr<Layer> root_layer) { // Reset gpu rasterization tracking. // This flag is sticky until a new tree comes along. - content_has_slow_paths_ = false; - content_has_non_aa_paint_ = false; gpu_rasterization_histogram_recorded_ = false; force_use_property_tree_builder_ = false; @@ -1244,25 +1204,23 @@ void LayerTreeHost::SetViewportVisibleRect(const gfx::Rect& visible_rect) { viewport_visible_rect_ = visible_rect; } -void LayerTreeHost::SetBrowserControlsHeight(float top_height, - float bottom_height, - bool shrink) { - if (top_controls_height_ == top_height && - bottom_controls_height_ == bottom_height && - browser_controls_shrink_blink_size_ == shrink) +void LayerTreeHost::SetBrowserControlsParams( + const BrowserControlsParams& params) { + if (browser_controls_params_ == params) return; - top_controls_height_ = top_height; - bottom_controls_height_ = bottom_height; - browser_controls_shrink_blink_size_ = shrink; + browser_controls_params_ = params; SetNeedsCommit(); } -void LayerTreeHost::SetBrowserControlsShownRatio(float ratio) { - if (top_controls_shown_ratio_ == ratio) +void LayerTreeHost::SetBrowserControlsShownRatio(float top_ratio, + float bottom_ratio) { + if (top_controls_shown_ratio_ == top_ratio && + bottom_controls_shown_ratio_ == bottom_ratio) return; - top_controls_shown_ratio_ = ratio; + top_controls_shown_ratio_ = top_ratio; + bottom_controls_shown_ratio_ = bottom_ratio; SetNeedsCommit(); } @@ -1438,15 +1396,11 @@ Layer* LayerTreeHost::LayerById(int id) const { return iter != layer_id_map_.end() ? iter->second : nullptr; } -bool LayerTreeHost::PaintContent(const LayerList& update_layer_list, - bool* content_has_slow_paths, - bool* content_has_non_aa_paint) { +bool LayerTreeHost::PaintContent(const LayerList& update_layer_list) { base::AutoReset<bool> painting(&in_paint_layer_contents_, true); bool did_paint_content = false; for (const auto& layer : update_layer_list) { did_paint_content |= layer->Update(); - *content_has_slow_paths |= layer->HasSlowPaths(); - *content_has_non_aa_paint |= layer->HasNonAAPaint(); } return did_paint_content; } @@ -1519,6 +1473,10 @@ void LayerTreeHost::UpdateHudLayer(bool show_hud_info) { } } +bool LayerTreeHost::is_hud_layer(const Layer* layer) const { + return hud_layer() == layer; +} + void LayerTreeHost::SetNeedsFullTreeSync() { needs_full_tree_sync_ = true; property_trees_.needs_rebuild = true; @@ -1560,12 +1518,10 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) { tree_impl->PushPageScaleFromMainThread( page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_); - tree_impl->set_browser_controls_shrink_blink_size( - browser_controls_shrink_blink_size_); - tree_impl->SetTopControlsHeight(top_controls_height_); - tree_impl->SetBottomControlsHeight(bottom_controls_height_); + tree_impl->SetBrowserControlsParams(browser_controls_params_); tree_impl->set_overscroll_behavior(overscroll_behavior_); - tree_impl->PushBrowserControlsFromMainThread(top_controls_shown_ratio_); + tree_impl->PushBrowserControlsFromMainThread(top_controls_shown_ratio_, + bottom_controls_shown_ratio_); tree_impl->elastic_overscroll()->PushMainToPending(elastic_overscroll_); if (tree_impl->IsActiveTree()) tree_impl->elastic_overscroll()->PushPendingToActive(); @@ -1602,6 +1558,8 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) { if (top_controls_shown_ratio_ > 0.0f && top_controls_shown_ratio_ < 1.0f) { tree_impl->UpdateViewportContainerSizes(); } + + tree_impl->set_display_transform_hint(display_transform_hint_); } void LayerTreeHost::PushSurfaceRangesTo(LayerTreeImpl* tree_impl) { @@ -1615,8 +1573,6 @@ void LayerTreeHost::PushSurfaceRangesTo(LayerTreeImpl* tree_impl) { void LayerTreeHost::PushLayerTreeHostPropertiesTo( LayerTreeHostImpl* host_impl) { - host_impl->SetContentHasSlowPaths(content_has_slow_paths_); - host_impl->SetContentHasNonAAPaint(content_has_non_aa_paint_); host_impl->set_external_pinch_gesture_active( is_external_pinch_gesture_active_); RecordGpuRasterizationHistogram(host_impl); diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index 104cc541e97..64df3a33fc8 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -35,6 +35,7 @@ #include "cc/layers/layer_list_iterator.h" #include "cc/metrics/begin_main_frame_metrics.h" #include "cc/paint/node_id.h" +#include "cc/trees/browser_controls_params.h" #include "cc/trees/compositor_mode.h" #include "cc/trees/layer_tree_frame_sink.h" #include "cc/trees/layer_tree_host_client.h" @@ -49,6 +50,7 @@ #include "components/viz/common/surfaces/local_surface_id_allocation.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/overlay_transform.h" namespace gfx { struct PresentationFeedback; @@ -333,7 +335,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { }; // Sets the collection of viewport property ids, defined to allow viewport - // pinch-zoom etc. on the compositor thread. + // pinch-zoom etc. on the compositor thread. This is set only on the + // main-frame's compositor, i.e., will be unset in OOPIF and UI compositors. void RegisterViewportPropertyIds(const ViewportPropertyIds&); LayerTreeHost::ViewportPropertyIds ViewportPropertyIdsForTesting() const { @@ -382,10 +385,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { gfx::Rect device_viewport_rect() const { return device_viewport_rect_; } - void SetBrowserControlsHeight(float top_height, - float bottom_height, - bool shrink); - void SetBrowserControlsShownRatio(float ratio); + void SetBrowserControlsParams(const BrowserControlsParams& params); + void SetBrowserControlsShownRatio(float top_ratio, float bottom_ratio); void SetOverscrollBehavior(const OverscrollBehavior& overscroll_behavior); const OverscrollBehavior& overscroll_behavior() const { @@ -402,6 +403,13 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void set_background_color(SkColor color) { background_color_ = color; } SkColor background_color() const { return background_color_; } + void set_display_transform_hint(gfx::OverlayTransform hint) { + display_transform_hint_ = hint; + } + gfx::OverlayTransform display_transform_hint() const { + return display_transform_hint_; + } + void StartPageScaleAnimation(const gfx::Vector2d& target_offset, bool use_anchor, float scale, @@ -478,9 +486,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void UnregisterLayer(Layer* layer); Layer* LayerById(int id) const; - bool PaintContent(const LayerList& update_layer_list, - bool* content_has_slow_paths, - bool* content_has_non_aa_paint); + bool PaintContent(const LayerList& update_layer_list); bool in_paint_layer_contents() const { return in_paint_layer_contents_; } void SetHasCopyRequest(bool has_copy_request); @@ -510,6 +516,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // position. If a HUD layer exists but is no longer needed, it is destroyed. void UpdateHudLayer(bool show_hud_info); HeadsUpDisplayLayer* hud_layer() const { return hud_layer_.get(); } + bool is_hud_layer(const Layer*) const; virtual void SetNeedsFullTreeSync(); bool needs_full_tree_sync() const { return needs_full_tree_sync_; } @@ -671,6 +678,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // NodeId in |content| and return true, otherwise return false. bool CaptureContent(std::vector<NodeId>* content); + std::unique_ptr<BeginMainFrameMetrics> begin_main_frame_metrics() { + return std::move(begin_main_frame_metrics_); + } + protected: LayerTreeHost(InitParams params, CompositorMode mode); @@ -750,8 +761,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool visible_ = false; - bool content_has_slow_paths_ = false; - bool content_has_non_aa_paint_ = false; bool gpu_rasterization_histogram_recorded_ = false; // If set, then page scale animation has completed, but the client hasn't been @@ -773,12 +782,11 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { ViewportPropertyIds viewport_property_ids_; - float top_controls_height_ = 0.f; - float top_controls_shown_ratio_ = 0.f; - bool browser_controls_shrink_blink_size_ = false; OverscrollBehavior overscroll_behavior_; - float bottom_controls_height_ = 0.f; + BrowserControlsParams browser_controls_params_; + float top_controls_shown_ratio_ = 0.f; + float bottom_controls_shown_ratio_ = 0.f; float device_scale_factor_ = 1.f; float painted_device_scale_factor_ = 1.f; @@ -803,6 +811,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { SkColor background_color_ = SK_ColorWHITE; + // Display transform hint to tag generated compositor frames. + gfx::OverlayTransform display_transform_hint_ = gfx::OVERLAY_TRANSFORM_NONE; + LayerSelection selection_; gfx::Rect device_viewport_rect_; diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h index 8cf1a5682a0..b6298911142 100644 --- a/chromium/cc/trees/layer_tree_host_client.h +++ b/chromium/cc/trees/layer_tree_host_client.h @@ -41,9 +41,13 @@ struct ApplyViewportChangesArgs { // subframe compositors to throttle their re-rastering during the gesture. bool is_pinch_gesture_active; - // How much the browser controls have been shown or hidden. The ratio runs + // How much the top controls have been shown or hidden. The ratio runs // between 0 (hidden) and 1 (full-shown). This is additive. - float browser_controls_delta; + float top_controls_delta; + + // How much the bottom controls have been shown or hidden. The ratio runs + // between 0 (hidden) and 1 (full-shown). This is additive. + float bottom_controls_delta; // Whether the browser controls have been locked to fully hidden or shown or // whether they can be freely moved. diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index 0dd3041f319..18ae9c1f1af 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -313,7 +313,7 @@ LayerTreeHostImpl::LayerTreeHostImpl( // LTHI always has an active tree. active_tree_ = std::make_unique<LayerTreeImpl>( this, new SyncedProperty<ScaleGroup>, new SyncedBrowserControls, - new SyncedElasticOverscroll); + new SyncedBrowserControls, new SyncedElasticOverscroll); active_tree_->property_trees()->is_active = true; viewport_ = Viewport::Create(this); @@ -823,7 +823,7 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingViewport() const { auto* node = CurrentlyScrollingNode(); if (!node) return false; - return node == viewport()->MainScrollNode(); + return viewport().ShouldScroll(*node); } bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt( @@ -850,12 +850,6 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt( if (scrolling_node == test_scroll_node) return true; - // For active scrolling state treat the inner/outer viewports interchangeably. - if (scrolling_node->scrolls_inner_viewport || - scrolling_node->scrolls_outer_viewport) { - return test_scroll_node == OuterViewportScrollNode(); - } - return false; } @@ -1697,10 +1691,11 @@ void LayerTreeHostImpl::BlockImplSideInvalidationRequestsForTesting( void LayerTreeHostImpl::ResetTreesForTesting() { if (active_tree_) active_tree_->DetachLayers(); - active_tree_ = - std::make_unique<LayerTreeImpl>(this, active_tree()->page_scale_factor(), - active_tree()->top_controls_shown_ratio(), - active_tree()->elastic_overscroll()); + active_tree_ = std::make_unique<LayerTreeImpl>( + this, active_tree()->page_scale_factor(), + active_tree()->top_controls_shown_ratio(), + active_tree()->bottom_controls_shown_ratio(), + active_tree()->elastic_overscroll()); active_tree_->property_trees()->is_active = true; active_tree_->property_trees()->clear(); if (pending_tree_) @@ -1861,6 +1856,21 @@ size_t LayerTreeHostImpl::GetFrameIndexForImage(const PaintImage& paint_image, paint_image.stable_id(), tree); } +int LayerTreeHostImpl::GetMSAASampleCountForRaster( + const scoped_refptr<DisplayItemList>& display_list) { + constexpr int kMinNumberOfSlowPathsForMSAA = 6; + if (display_list->NumSlowPaths() < kMinNumberOfSlowPathsForMSAA) + return 0; + + if (!can_use_msaa_) + return 0; + + if (display_list->HasNonAAPaint() && !supports_disable_msaa_) + return 0; + + return RequestedMSAASampleCount(); +} + void LayerTreeHostImpl::NotifyReadyToActivate() { // The TileManager may call this method while the pending tree is still being // painted, as it isn't aware of the ongoing paint. We shouldn't tell the @@ -2058,6 +2068,10 @@ void LayerTreeHostImpl::OnDraw(const gfx::Transform& transform, // external viewport to be set otherwise. DCHECK(active_tree_->internal_device_viewport().origin().IsOrigin()); +#if DCHECK_IS_ON() + base::AutoReset<bool> reset_sync_draw(&doing_sync_draw_, true); +#endif + if (skip_draw) { client_->OnDrawForLayerTreeFrameSink(resourceless_software_draw_, true); return; @@ -2135,10 +2149,11 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() { metadata.min_page_scale_factor = active_tree_->min_page_scale_factor(); - metadata.top_controls_height = - browser_controls_offset_manager_->TopControlsHeight(); - metadata.top_controls_shown_ratio = - browser_controls_offset_manager_->TopControlsShownRatio(); + if (browser_controls_offset_manager_->TopControlsHeight() > 0) { + metadata.top_controls_visible_height.emplace( + browser_controls_offset_manager_->TopControlsHeight() * + browser_controls_offset_manager_->TopControlsShownRatio()); + } metadata.local_surface_id_allocation_time = child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() @@ -2150,6 +2165,8 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() { gfx::ScrollOffsetToVector2dF(active_tree_->TotalScrollOffset()); } + metadata.display_transform_hint = active_tree_->display_transform_hint(); + return metadata; } @@ -2184,19 +2201,43 @@ RenderFrameMetadata LayerTreeHostImpl::MakeRenderFrameMetadata( metadata.min_page_scale_factor = active_tree_->min_page_scale_factor(); metadata.max_page_scale_factor = active_tree_->max_page_scale_factor(); metadata.root_layer_size = active_tree_->ScrollableSize(); - if (const auto* outer_viewport_scroll_node = OuterViewportScrollNode()) { + if (InnerViewportScrollNode()) { + DCHECK(OuterViewportScrollNode()); metadata.root_overflow_y_hidden = - !outer_viewport_scroll_node->user_scrollable_vertical; - } - const auto* inner_viewport_scroll_node = InnerViewportScrollNode(); - if (inner_viewport_scroll_node) { - metadata.root_overflow_y_hidden |= - !inner_viewport_scroll_node->user_scrollable_vertical; + !OuterViewportScrollNode()->user_scrollable_vertical || + !InnerViewportScrollNode()->user_scrollable_vertical; } metadata.has_transparent_background = frame->render_passes.back()->has_transparent_background; #endif + if (last_draw_render_frame_metadata_) { + const float last_root_scroll_offset_y = + last_draw_render_frame_metadata_->root_scroll_offset + .value_or(gfx::Vector2dF()) + .y(); + + const float new_root_scroll_offset_y = + metadata.root_scroll_offset.value().y(); + + if (!MathUtil::IsWithinEpsilon(last_root_scroll_offset_y, + new_root_scroll_offset_y)) { + viz::VerticalScrollDirection new_vertical_scroll_direction = + (last_root_scroll_offset_y < new_root_scroll_offset_y) + ? viz::VerticalScrollDirection::kDown + : viz::VerticalScrollDirection::kUp; + + // Changes in vertical scroll direction happen instantaneously. This being + // the case, a new vertical scroll direction should only be present in the + // singular metadata for the render frame in which the direction change + // occurred. If the vertical scroll direction detected here matches that + // which we've previously cached, then this frame is not the instant in + // which the direction change occurred and is therefore not propagated. + if (last_vertical_scroll_direction_ != new_vertical_scroll_direction) + metadata.new_vertical_scroll_direction = new_vertical_scroll_direction; + } + } + bool allocate_new_local_surface_id = #if !defined(OS_ANDROID) last_draw_render_frame_metadata_ && @@ -2241,6 +2282,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) { frame_trackers_.NotifyImplFrameCausedNoDamage(frame->begin_frame_ack); TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoDamage", TRACE_EVENT_SCOPE_THREAD); active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS); + active_tree()->ResetAllChangeTracking(); return false; } @@ -2253,6 +2295,21 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) { std::move(compositor_frame), /*hit_test_data_changed=*/false, debug_state_.show_hit_test_borders); +#if DCHECK_IS_ON() + if (!doing_sync_draw_) { + // The throughput computation (in |FrameSequenceTracker|) depends on the + // compositor-frame submission to happen while a BeginFrameArgs is 'active' + // (i.e. between calls to WillBeginImplFrame() and DidFinishImplFrame()). + // Verify that this is the case. + // No begin-frame is available when doing sync draws, so avoid doing this + // check in that case. + const auto& bfargs = current_begin_frame_tracker_.Current(); + const auto& ack = compositor_frame.metadata.begin_frame_ack; + DCHECK_EQ(bfargs.source_id, ack.source_id); + DCHECK_EQ(bfargs.sequence_number, ack.sequence_number); + } +#endif + frame_trackers_.NotifySubmitFrame( compositor_frame.metadata.frame_token, frame->has_missing_content, frame->begin_frame_ack, frame->origin_begin_main_frame_args); @@ -2357,6 +2414,17 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame( if (render_frame_metadata_observer_) { last_draw_render_frame_metadata_ = MakeRenderFrameMetadata(frame); + + // We cache the value of any new vertical scroll direction so that we can + // accurately determine when the next change in vertical scroll direction + // occurs. Note that |kNull| is only used to indicate the absence of a + // vertical scroll direction and should therefore be ignored. + if (last_draw_render_frame_metadata_->new_vertical_scroll_direction != + viz::VerticalScrollDirection::kNull) { + last_vertical_scroll_direction_ = + last_draw_render_frame_metadata_->new_vertical_scroll_direction; + } + render_frame_metadata_observer_->OnRenderFrameSubmission( *last_draw_render_frame_metadata_, &metadata, active_tree()->TakeForceSendMetadataRequest()); @@ -2430,20 +2498,6 @@ int LayerTreeHostImpl::RequestedMSAASampleCount() const { return settings_.gpu_rasterization_msaa_sample_count; } -void LayerTreeHostImpl::SetContentHasSlowPaths(bool flag) { - if (content_has_slow_paths_ != flag) { - content_has_slow_paths_ = flag; - need_update_gpu_rasterization_status_ = true; - } -} - -void LayerTreeHostImpl::SetContentHasNonAAPaint(bool flag) { - if (content_has_non_aa_paint_ != flag) { - content_has_non_aa_paint_ = flag; - need_update_gpu_rasterization_status_ = true; - } -} - void LayerTreeHostImpl::GetGpuRasterizationCapabilities( bool* gpu_rasterization_enabled, bool* gpu_rasterization_supported, @@ -2534,23 +2588,14 @@ bool LayerTreeHostImpl::UpdateGpuRasterizationStatus() { &max_msaa_samples, &supports_disable_msaa); bool use_gpu = false; - bool use_msaa = false; - bool using_msaa_for_slow_paths = - requested_msaa_samples > 0 && - max_msaa_samples >= requested_msaa_samples && - (!content_has_non_aa_paint_ || supports_disable_msaa); + bool can_use_msaa = + requested_msaa_samples > 0 && max_msaa_samples >= requested_msaa_samples; + if (settings_.gpu_rasterization_forced) { use_gpu = true; gpu_rasterization_status_ = GpuRasterizationStatus::ON_FORCED; - use_msaa = content_has_slow_paths_ && using_msaa_for_slow_paths; - if (use_msaa) { - gpu_rasterization_status_ = GpuRasterizationStatus::MSAA_CONTENT; - } } else if (!gpu_rasterization_enabled) { gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE; - } else if (content_has_slow_paths_ && using_msaa_for_slow_paths) { - use_gpu = use_msaa = true; - gpu_rasterization_status_ = GpuRasterizationStatus::MSAA_CONTENT; } else { use_gpu = true; gpu_rasterization_status_ = GpuRasterizationStatus::ON; @@ -2562,18 +2607,24 @@ bool LayerTreeHostImpl::UpdateGpuRasterizationStatus() { // be created due to losing the GL context, force use of software // raster. use_gpu = false; - use_msaa = false; + can_use_msaa_ = false; + supports_disable_msaa_ = false; gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE; } } - if (use_gpu == use_gpu_rasterization_ && use_msaa == use_msaa_) + // Changes in MSAA settings require that we re-raster resources for the + // settings to take effect. But we don't need to trigger any raster + // invalidation in this case since these settings change only if the context + // changed. In this case we already re-allocate and re-raster all resources. + if (use_gpu == use_gpu_rasterization_ && can_use_msaa == can_use_msaa_ && + supports_disable_msaa == supports_disable_msaa_) { return false; + } - // Note that this must happen first, in case the rest of the calls want to - // query the new state of |use_gpu_rasterization_|. use_gpu_rasterization_ = use_gpu; - use_msaa_ = use_msaa; + can_use_msaa_ = can_use_msaa; + supports_disable_msaa_ = supports_disable_msaa; return true; } @@ -2728,9 +2779,6 @@ static void PopulateHitTestRegion(viz::HitTestRegion* hit_test_region, base::Optional<viz::HitTestRegionList> LayerTreeHostImpl::BuildHitTestData() { TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildHitTestData"); - if (!settings_.build_hit_test_data) - return {}; - base::Optional<viz::HitTestRegionList> hit_test_region_list(base::in_place); hit_test_region_list->flags = viz::HitTestRegionFlags::kHitTestMine | viz::HitTestRegionFlags::kHitTestMouse | @@ -2875,7 +2923,7 @@ bool LayerTreeHostImpl::IsActivelyScrolling() const { // are actually animating. So assume there are none. if (settings_.ignore_root_layer_flings && IsCurrentlyScrollingViewport()) return false; - return did_lock_scrolling_layer_; + return true; } void LayerTreeHostImpl::CreatePendingTree() { @@ -2886,6 +2934,7 @@ void LayerTreeHostImpl::CreatePendingTree() { pending_tree_ = std::make_unique<LayerTreeImpl>( this, active_tree()->page_scale_factor(), active_tree()->top_controls_shown_ratio(), + active_tree()->bottom_controls_shown_ratio(), active_tree()->elastic_overscroll()); } pending_tree_fully_painted_ = false; @@ -2971,6 +3020,10 @@ void LayerTreeHostImpl::ActivateSyncTree() { active_tree_->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing); + // The previous scrolling node no longer exists in the new tree. + if (!active_tree_->CurrentlyScrollingNode()) + ClearCurrentlyScrollingNode(); + // Now that we've synced everything from the pending tree to the active // tree, rename the pending tree the recycle tree so we can reuse it on the // next sync. @@ -3002,8 +3055,8 @@ void LayerTreeHostImpl::ActivateSyncTree() { if (InnerViewportScrollNode()) { active_tree_->property_trees()->scroll_tree.ClampScrollToMaxScrollOffset( InnerViewportScrollNode(), active_tree_.get()); - } - if (OuterViewportScrollNode()) { + + DCHECK(OuterViewportScrollNode()); active_tree_->property_trees()->scroll_tree.ClampScrollToMaxScrollOffset( OuterViewportScrollNode(), active_tree_.get()); } @@ -3236,11 +3289,10 @@ LayerTreeHostImpl::CreateRasterBufferProvider() { if (use_gpu_rasterization_) { DCHECK(worker_context_provider); - int msaa_sample_count = use_msaa_ ? RequestedMSAASampleCount() : 0; return std::make_unique<GpuRasterBufferProvider>( compositor_context_provider, worker_context_provider, settings_.resource_settings.use_gpu_memory_buffer_resources, - msaa_sample_count, tile_format, settings_.max_gpu_raster_tile_size, + tile_format, settings_.max_gpu_raster_tile_size, settings_.unpremultiply_and_dither_low_bit_depth_tiles, use_oop_rasterization_); } @@ -3280,10 +3332,6 @@ void LayerTreeHostImpl::SetPaintWorkletLayerPainter( paint_worklet_painter_ = std::move(painter); } -ScrollNode* LayerTreeHostImpl::ViewportMainScrollNode() { - return viewport()->MainScrollNode(); -} - void LayerTreeHostImpl::QueueImageDecode(int request_id, const PaintImage& image) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), @@ -3471,9 +3519,9 @@ bool LayerTreeHostImpl::InitializeFrameSink( use_oop_rasterization_ = false; } - // Since the new context may be capable of MSAA, update status here. We don't - // need to check the return value since we are recreating all resources - // already. + // Since the new context may support GPU raster or be capable of MSAA, update + // status here. We don't need to check the return value since we are + // recreating all resources already. SetNeedUpdateGpuRasterizationStatus(); UpdateGpuRasterizationStatus(); @@ -3528,17 +3576,32 @@ float LayerTreeHostImpl::TopControlsHeight() const { return active_tree_->top_controls_height(); } +float LayerTreeHostImpl::TopControlsMinHeight() const { + return active_tree_->top_controls_min_height(); +} + float LayerTreeHostImpl::BottomControlsHeight() const { return active_tree_->bottom_controls_height(); } -void LayerTreeHostImpl::SetCurrentBrowserControlsShownRatio(float ratio) { - if (active_tree_->SetCurrentBrowserControlsShownRatio(ratio)) +float LayerTreeHostImpl::BottomControlsMinHeight() const { + return active_tree_->bottom_controls_min_height(); +} + +void LayerTreeHostImpl::SetCurrentBrowserControlsShownRatio( + float top_ratio, + float bottom_ratio) { + if (active_tree_->SetCurrentBrowserControlsShownRatio(top_ratio, + bottom_ratio)) DidChangeBrowserControlsPosition(); } -float LayerTreeHostImpl::CurrentBrowserControlsShownRatio() const { - return active_tree_->CurrentBrowserControlsShownRatio(); +float LayerTreeHostImpl::CurrentTopControlsShownRatio() const { + return active_tree_->CurrentTopControlsShownRatio(); +} + +float LayerTreeHostImpl::CurrentBottomControlsShownRatio() const { + return active_tree_->CurrentBottomControlsShownRatio(); } void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) { @@ -3599,13 +3662,13 @@ InputHandler::ScrollStatus LayerTreeHostImpl::TryScroll( return scroll_status; } - // The outer viewport should be scrolled even if it has no scroll extent + // The a viewport node should be scrolled even if it has no scroll extent // since it'll scroll using the Viewport class which will generate browser // controls movement and overscroll delta. gfx::ScrollOffset max_scroll_offset = scroll_tree.MaxScrollOffset(scroll_node->id); if (max_scroll_offset.x() <= 0 && max_scroll_offset.y() <= 0 && - !scroll_node->scrolls_outer_viewport) { + !viewport().ShouldScroll(*scroll_node)) { TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored. Technically scrollable," " but has no affordance in either direction."); @@ -3713,32 +3776,7 @@ ScrollNode* LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint( if (!impl_scroll_node) return nullptr; - // Blink has a notion of a "root scroller", which is the scroller in a page - // that is considered to host the main content. Typically this will be the - // document/LayoutView contents; however, in some situations Blink may choose - // a sub-scroller (div, iframe) that should scroll with "viewport" behavior. - // The "root scroller" is the node designated as the outer viewport in CC. - // See third_party/blink/renderer/core/page/scrolling/README.md for details. - // - // "Viewport" scrolling ensures generation of overscroll events, top controls - // movement, as well as correct multi-viewport panning in pinch-zoom and - // other scenarios. We use the viewport's outer scroll node to represent the - // viewport in the scroll chain and apply scroll delta using CC's Viewport - // class. - // - // Scrolling from position: fixed layers will chain directly up to the inner - // viewport. Whether that should use the outer viewport (and thus the - // Viewport class) to scroll or not depends on the root scroller scenario - // because we don't want setting a root scroller to change the scroll chain - // order. The |prevent_viewport_scrolling_from_inner| bit is used to - // communicate that context. - DCHECK(!impl_scroll_node->prevent_viewport_scrolling_from_inner || - impl_scroll_node->scrolls_inner_viewport); - bool should_use_viewport = - OuterViewportScrollNode() && impl_scroll_node->scrolls_inner_viewport && - !impl_scroll_node->prevent_viewport_scrolling_from_inner; - if (should_use_viewport) - impl_scroll_node = OuterViewportScrollNode(); + impl_scroll_node = GetNodeToScroll(impl_scroll_node); // Ensure that final scroll node scrolls on impl thread (crbug.com/625100) ScrollStatus status = @@ -3788,16 +3826,14 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl( TRACE_EVENT_INSTANT1("cc", "SetCurrentlyScrollingNode ScrollBeginImpl", TRACE_EVENT_SCOPE_THREAD, "isNull", scrolling_node ? false : true); - active_tree_->SetCurrentlyScrollingNode(scrolling_node); // TODO(majidvp): get rid of touch_scrolling_ and set is_direct_manipulation // in input_handler_proxy instead. touch_scrolling_ = type == InputHandler::TOUCHSCREEN; wheel_scrolling_ = type == InputHandler::WHEEL; middle_click_autoscrolling_ = type == InputHandler::AUTOSCROLL; scroll_state->set_is_direct_manipulation(touch_scrolling_); - // Invoke |DistributeScrollDelta| even with zero delta and velocity to ensure - // scroll customization callbacks are invoked. - DistributeScrollDelta(scroll_state); + + LatchToScroller(scroll_state, scrolling_node); // If the CurrentlyScrollingNode doesn't exist after distributing scroll // delta, no scroller can scroll in the given delta hint direction(s). @@ -3813,9 +3849,11 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl( // If the viewport is scrolling and it cannot consume any delta hints, the // scroll event will need to get bubbled if the viewport is for a guest or // oopif. - if (active_tree_->CurrentlyScrollingNode() == ViewportMainScrollNode() && - !viewport()->CanScroll(*scroll_state)) { - scroll_status.bubble = true; + if (ScrollNode* node = active_tree_->CurrentlyScrollingNode()) { + if (viewport().ShouldScroll(*node) && + !viewport().CanScroll(*node, *scroll_state)) { + scroll_status.bubble = true; + } } frame_trackers_.StartSequence(wheel_scrolling_ @@ -3868,6 +3906,9 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( ScrollNode* scrolling_node = nullptr; bool scroll_on_main_thread = false; + // TODO(bokan): This appears Mac-specific - from + // https://codereview.chromium.org/2486673008 Suspect it is unnecessary - a + // fling should just produce GSUs without an intermediate GSB and GSE. if (scroll_state->is_in_inertial_phase()) scrolling_node = CurrentlyScrollingNode(); @@ -3908,11 +3949,10 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( ElementId current_native_scrolling_element = scroll_state->data()->current_native_scrolling_element(); - if (current_native_scrolling_element.GetStableId() != 0) { + if (current_native_scrolling_element) { auto& scroll_tree = active_tree_->property_trees()->scroll_tree; scrolling_node = scroll_tree.FindNodeFromElementId(current_native_scrolling_element); - did_lock_scrolling_layer_ = true; } else { scrolling_node = FindScrollNodeForDeviceViewportPoint( device_viewport_point, layer_impl, &scroll_on_main_thread, @@ -3942,6 +3982,38 @@ bool LayerTreeHostImpl::IsTouchDraggingScrollbar( type == InputHandler::TOUCHSCREEN; } +ScrollNode* LayerTreeHostImpl::GetNodeToScroll(ScrollNode* node) const { + // Blink has a notion of a "root scroller", which is the scroller in a page + // that is considered to host the main content. Typically this will be the + // document/LayoutView contents; however, in some situations Blink may choose + // a sub-scroller (div, iframe) that should scroll with "viewport" behavior. + // The "root scroller" is the node designated as the outer viewport in CC. + // See third_party/blink/renderer/core/page/scrolling/README.md for details. + // + // "Viewport" scrolling ensures generation of overscroll events, top controls + // movement, as well as correct multi-viewport panning in pinch-zoom and + // other scenarios. We use the viewport's outer scroll node to represent the + // viewport in the scroll chain and apply scroll delta using CC's Viewport + // class. + // + // Scrolling from position: fixed layers will chain directly up to the inner + // viewport. Whether that should use the outer viewport (and thus the + // Viewport class) to scroll or not depends on the root scroller scenario + // because we don't want setting a root scroller to change the scroll chain + // order. The |prevent_viewport_scrolling_from_inner| bit is used to + // communicate that context. + DCHECK(!node->prevent_viewport_scrolling_from_inner || + node->scrolls_inner_viewport); + + if (node->scrolls_inner_viewport && + !node->prevent_viewport_scrolling_from_inner) { + DCHECK(OuterViewportScrollNode()); + return OuterViewportScrollNode(); + } + + return node; +} + // Initial scroll hit testing can be unreliable in the presence of squashed // layers. In this case, we fall back to main thread scrolling. This function // compares |layer_impl| returned from a regular hit test to the layer @@ -3954,9 +4026,8 @@ bool LayerTreeHostImpl::IsTouchDraggingScrollbar( // (since they don't scroll with the outer viewport), however, scrolls from the // fixed layer still chain to the outer viewport. It's also possible for a node // to have the inner viewport as its ancestor without going through the outer -// viewport; however, it will still scroll using the viewport(). Hence, this -// method needs to use the same scroll chaining logic we use in ApplyScroll by -// looking at Viewport::ShouldScroll. +// viewport; however, it may still scroll using the viewport(). Hence, this +// method must use the same scroll chaining logic we use in ApplyScroll. bool LayerTreeHostImpl::IsInitialScrollHitTestReliable( LayerImpl* layer_impl, LayerImpl* first_scrolling_layer_or_scrollbar) { @@ -3975,13 +4046,7 @@ bool LayerTreeHostImpl::IsInitialScrollHitTestReliable( for (; scroll_tree.parent(scroll_node); scroll_node = scroll_tree.parent(scroll_node)) { if (scroll_node->scrollable) { - // Ensure we use scroll chaining behavior for the inner viewport node. - if (scroll_node->scrolls_inner_viewport && - !scroll_node->prevent_viewport_scrolling_from_inner) { - closest_scroll_node = viewport()->MainScrollNode(); - } else { - closest_scroll_node = scroll_node; - } + closest_scroll_node = GetNodeToScroll(scroll_node); break; } } @@ -4009,7 +4074,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimatedBegin( InputHandler::ScrollStatus scroll_status; scroll_status.main_thread_scrolling_reasons = MainThreadScrollingReason::kNotScrollingOnMain; - deferred_scroll_end_state_.reset(); + deferred_scroll_end_ = false; ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree; ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode(); if (scroll_node) { @@ -4035,10 +4100,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimatedBegin( if (scroll_status.thread == SCROLL_ON_IMPL_THREAD) { scroll_animating_latched_element_id_ = ElementId(); scroll_animating_overscroll_target_element_id_ = ElementId(); - ScrollStateData scroll_state_end_data; - scroll_state_end_data.is_ending = true; - ScrollState scroll_state_end(scroll_state_end_data); - ScrollEndImpl(&scroll_state_end); + ScrollEndImpl(); } return scroll_status; } @@ -4207,9 +4269,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated( continue; } - bool scrolls_main_viewport_scroll_layer = - scroll_node == viewport()->MainScrollNode(); - if (scrolls_main_viewport_scroll_layer) { + if (viewport().ShouldScroll(*scroll_node)) { // Flash the overlay scrollbar even if the scroll dalta is 0. if (settings_.scrollbar_flash_after_any_scroll_update) { FlashAllScrollbars(false); @@ -4219,9 +4279,11 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated( if (animation_controller) animation_controller->WillUpdateScroll(); } + } + if (scroll_node->scrolls_outer_viewport) { gfx::Vector2dF scrolled = - viewport()->ScrollAnimated(pending_delta, delayed_by); + viewport().ScrollAnimated(pending_delta, delayed_by); // Viewport::ScrollAnimated returns pending_delta as long as it starts // an animation. did_scroll_x_for_scroll_gesture_ |= scrolled.x() != 0; @@ -4285,8 +4347,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated( client_->SetNeedsCommitOnImplThread(); } - scroll_state.set_is_ending(true); - ScrollEndImpl(&scroll_state); + ScrollEndImpl(); if (scroll_status.thread == SCROLL_ON_IMPL_THREAD) { // Update scroll_status.thread to SCROLL_IGNORED when there is no ongoing // scroll animation, we can scroll on impl thread and yet, we couldn't @@ -4362,6 +4423,10 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollNodeWithViewportSpaceDelta( return gfx::Vector2dF(); } + bool scrolls_outer_viewport = scroll_node->scrolls_outer_viewport; + TRACE_EVENT2("cc", "ScrollNodeWithViewportSpaceDelta", "delta_y", + local_scroll_delta.y(), "is_outer", scrolls_outer_viewport); + // Apply the scroll delta. gfx::ScrollOffset previous_offset = scroll_tree->current_scroll_offset(scroll_node->element_id); @@ -4370,6 +4435,9 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollNodeWithViewportSpaceDelta( scroll_tree->current_scroll_offset(scroll_node->element_id) - previous_offset; + TRACE_EVENT_INSTANT1("cc", "ConsumedDelta", TRACE_EVENT_SCOPE_THREAD, "y", + scrolled.y()); + // Get the end point in the layer's content space so we can apply its // ScreenSpaceTransform. gfx::PointF actual_local_end_point = @@ -4397,6 +4465,10 @@ static gfx::Vector2dF ScrollNodeWithLocalDelta( const gfx::Vector2dF& local_delta, float page_scale_factor, LayerTreeImpl* layer_tree_impl) { + bool scrolls_outer_viewport = scroll_node->scrolls_outer_viewport; + TRACE_EVENT2("cc", "ScrollNodeWithLocalDelta", "delta_y", local_delta.y(), + "is_outer", scrolls_outer_viewport); + ScrollTree& scroll_tree = layer_tree_impl->property_trees()->scroll_tree; gfx::ScrollOffset previous_offset = scroll_tree.current_scroll_offset(scroll_node->element_id); @@ -4408,6 +4480,8 @@ static gfx::Vector2dF ScrollNodeWithLocalDelta( previous_offset; gfx::Vector2dF consumed_scroll(scrolled.x(), scrolled.y()); consumed_scroll.Scale(page_scale_factor); + TRACE_EVENT_INSTANT1("cc", "ConsumedDelta", TRACE_EVENT_SCOPE_THREAD, "y", + consumed_scroll.y()); return consumed_scroll; } @@ -4440,38 +4514,39 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollSingleNode( active_tree()); } -void LayerTreeHostImpl::ApplyScroll(ScrollNode* scroll_node, - ScrollState* scroll_state) { - DCHECK(scroll_node && scroll_state); +void LayerTreeHostImpl::ScrollLatchedScroller(ScrollState* scroll_state) { + DCHECK(CurrentlyScrollingNode() && scroll_state); + ScrollNode* scroll_node = CurrentlyScrollingNode(); gfx::Point viewport_point(scroll_state->position_x(), scroll_state->position_y()); const gfx::Vector2dF delta(scroll_state->delta_x(), scroll_state->delta_y()); + TRACE_EVENT2("cc", "LayerTreeHostImpl::ScrollLatchedScroller", "delta_x", + delta.x(), "delta_y", delta.y()); gfx::Vector2dF applied_delta; gfx::Vector2dF delta_applied_to_content; // TODO(tdresser): Use a more rational epsilon. See crbug.com/510550 for // details. const float kEpsilon = 0.1f; - if (viewport()->ShouldScroll(*scroll_node)) { - // |scroll_outer_vieiwport| will only ever be false if the scroll chains up - // to the viewport without going through the outer viewport scroll node. + if (viewport().ShouldScroll(*scroll_node)) { + // |scrolls_outer_vieiwport| will only ever be false if the scroll chains + // up to the viewport without going through the outer viewport scroll node. // This is because we normally terminate the scroll chain at the outer // viewport node. For example, if we start scrolling from an element // that's not a descendant of the root scroller. In these cases we want to // scroll *only* the inner viewport -- to allow panning while zoomed -- but // still use Viewport::ScrollBy to also move browser controls if needed. - bool scroll_outer_viewport = scroll_node->scrolls_outer_viewport; - Viewport::ScrollResult result = viewport()->ScrollBy( + Viewport::ScrollResult result = viewport().ScrollBy( delta, viewport_point, scroll_state->is_direct_manipulation(), - !wheel_scrolling_, scroll_outer_viewport); + !wheel_scrolling_, scroll_node->scrolls_outer_viewport); applied_delta = result.consumed_delta; delta_applied_to_content = result.content_scrolled_delta; } else { - applied_delta = ScrollSingleNode( - scroll_node, delta, viewport_point, - scroll_state->is_direct_manipulation(), - &scroll_state->layer_tree_impl()->property_trees()->scroll_tree); + applied_delta = + ScrollSingleNode(scroll_node, delta, viewport_point, + scroll_state->is_direct_manipulation(), + &active_tree_->property_trees()->scroll_tree); } // If the layer wasn't able to move, try the next one in the hierarchy. @@ -4486,7 +4561,7 @@ void LayerTreeHostImpl::ApplyScroll(ScrollNode* scroll_node, return; } - if (!viewport()->ShouldScroll(*scroll_node)) { + if (!viewport().ShouldScroll(*scroll_node)) { // If the applied delta is within 45 degrees of the input // delta, bail out to make it easier to scroll just one layer // in one direction without affecting any of its parents. @@ -4510,45 +4585,38 @@ void LayerTreeHostImpl::ApplyScroll(ScrollNode* scroll_node, scroll_state->set_current_native_scrolling_node(scroll_node); } -void LayerTreeHostImpl::DistributeScrollDelta(ScrollState* scroll_state) { - // TODO(majidvp): in Blink we compute scroll chain only at scroll begin which - // is not the case here. We eventually want to have the same behaviour on both - // sides but it may become a non issue if we get rid of scroll chaining (see - // crbug.com/526462) +void LayerTreeHostImpl::LatchToScroller(ScrollState* scroll_state, + ScrollNode* starting_node) { std::list<ScrollNode*> current_scroll_chain; ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree; - ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode(); - ScrollNode* viewport_scroll_node = ViewportMainScrollNode(); - if (did_lock_scrolling_layer_) { - DCHECK(scroll_node); + ScrollNode* scroll_node = nullptr; + if (scroll_state->data()->current_native_scrolling_element()) { + DCHECK(starting_node); + DCHECK_EQ(starting_node->element_id, + scroll_state->data()->current_native_scrolling_element()); // Needed for non-animated scrolls. - current_scroll_chain.push_front(scroll_node); - } else if (scroll_node) { - // TODO(bokan): The loop checks for a null parent but don't we still want to - // distribute to the root scroll node? - for (; scroll_tree.parent(scroll_node); - scroll_node = scroll_tree.parent(scroll_node)) { - if (scroll_node == viewport_scroll_node) { - // Don't chain scrolls past the outer viewport scroll layer. Once we - // reach that, we should scroll the viewport which is represented by the - // main viewport scroll layer. - DCHECK(viewport_scroll_node); - current_scroll_chain.push_front(viewport_scroll_node); + scroll_node = starting_node; + } else { + for (ScrollNode* cur_node = starting_node; cur_node; + cur_node = scroll_tree.parent(cur_node)) { + if (viewport().ShouldScroll(*cur_node)) { + // Don't chain scrolls past a viewport node. Once we reach that, we + // should scroll using the appropriate viewport node which may not be + // |cur_node|. + scroll_node = GetNodeToScroll(cur_node); break; } - if (!scroll_node->scrollable) + if (!cur_node->scrollable) continue; - if (middle_click_autoscrolling_) { - current_scroll_chain.push_front(scroll_node); + if (middle_click_autoscrolling_ || + CanConsumeDelta(*cur_node, *scroll_state)) { + scroll_node = cur_node; break; } - if (CanConsumeDelta(*scroll_node, *scroll_state)) - current_scroll_chain.push_front(scroll_node); - float delta_x = scroll_state->is_beginning() ? scroll_state->delta_x_hint() : scroll_state->delta_x(); @@ -4556,28 +4624,23 @@ void LayerTreeHostImpl::DistributeScrollDelta(ScrollState* scroll_state) { ? scroll_state->delta_y_hint() : scroll_state->delta_y(); - if (!CanPropagate(scroll_node, delta_x, delta_y)) { - // We should add the first node with non-auto overscroll-behavior to - // the scroll chain regardlessly, as it's the only node we can latch to. - if (current_scroll_chain.empty() || - current_scroll_chain.front() != scroll_node) { - current_scroll_chain.push_front(scroll_node); - } + if (!CanPropagate(cur_node, delta_x, delta_y)) { + // If we reach a node with non-auto overscroll-behavior and we still + // haven't latched, we must latch to it. Consider a fully scrolled node + // with non-auto overscroll-behavior: we are not allowed to further + // chain scroll delta passed to it in the current direction but if we + // reverse direction we should scroll it so we must be latched to it. + scroll_node = cur_node; scroll_state->set_is_scroll_chain_cut(true); break; } } } - scroll_node = - current_scroll_chain.empty() ? nullptr : current_scroll_chain.back(); - TRACE_EVENT_INSTANT1("cc", "SetCurrentlyScrollingNode DistributeScrollDelta", + TRACE_EVENT_INSTANT1("cc", "SetCurrentlyScrollingNode LatchToScroller", TRACE_EVENT_SCOPE_THREAD, "isNull", scroll_node ? false : true); active_tree_->SetCurrentlyScrollingNode(scroll_node); - scroll_state->set_scroll_chain_and_layer_tree(current_scroll_chain, - active_tree()); - scroll_state->DistributeToScrollChainDescendant(); } bool LayerTreeHostImpl::CanConsumeDelta(const ScrollNode& scroll_node, @@ -4671,12 +4734,10 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( float initial_top_controls_offset = browser_controls_offset_manager_->ControlsTopOffset(); - scroll_state->set_delta_consumed_for_scroll_sequence( - did_lock_scrolling_layer_); scroll_state->set_is_direct_manipulation(touch_scrolling_); scroll_state->set_current_native_scrolling_node(scroll_node); - DistributeScrollDelta(scroll_state); + ScrollLatchedScroller(scroll_state); ScrollNode* current_scrolling_node = scroll_state->current_native_scrolling_node(); @@ -4684,8 +4745,6 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( TRACE_EVENT_SCOPE_THREAD, "isNull", current_scrolling_node ? false : true); active_tree_->SetCurrentlyScrollingNode(current_scrolling_node); - did_lock_scrolling_layer_ = - scroll_state->delta_consumed_for_scroll_sequence(); bool did_scroll_x = scroll_state->caused_scroll_x(); bool did_scroll_y = scroll_state->caused_scroll_y(); @@ -4712,7 +4771,7 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( gfx::Vector2dF unused_root_delta; if (current_scrolling_node && - current_scrolling_node == ViewportMainScrollNode()) { + viewport().ShouldScroll(*current_scrolling_node)) { unused_root_delta = gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y()); } @@ -4779,15 +4838,15 @@ void LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset( "offset_x", root_content_offset.x(), "offset_y", root_content_offset.y()); gfx::Vector2dF physical_delta = ContentToPhysical( - root_content_offset.DeltaFrom(viewport()->TotalScrollOffset()), + root_content_offset.DeltaFrom(viewport().TotalScrollOffset()), active_tree()->page_scale_factor_for_scroll()); bool changed = !viewport() - ->ScrollBy(physical_delta, - /*viewport_point=*/gfx::Point(), - /*is_direct_manipulation=*/false, - /*affect_browser_controls=*/false, - /*scroll_outer_viewport=*/true) + .ScrollBy(physical_delta, + /*viewport_point=*/gfx::Point(), + /*is_direct_manipulation=*/false, + /*affect_browser_controls=*/false, + /*scroll_outer_viewport=*/true) .consumed_delta.IsZero(); if (!changed) return; @@ -4806,7 +4865,6 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() { if (!scroll_node || !scroll_node->snap_container_data.has_value()) return false; - const SnapContainerData& data = scroll_node->snap_container_data.value(); gfx::ScrollOffset current_position = GetVisualScrollOffset(*scroll_node); std::unique_ptr<SnapSelectionStrategy> strategy = @@ -4814,16 +4872,10 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() { current_position, did_scroll_x_for_scroll_gesture_, did_scroll_y_for_scroll_gesture_); gfx::ScrollOffset snap_position; - if (!data.FindSnapPosition(*strategy, &snap_position)) + if (!FindSnapPositionAndSetTarget(scroll_node, *strategy, &snap_position)) return false; - gfx::Vector2dF delta = - ScrollOffsetToVector2dF(snap_position - current_position); - bool scrolls_main_viewport_scroll_layer = - scroll_node == ViewportMainScrollNode(); - - bool did_animate = false; - if (scrolls_main_viewport_scroll_layer) { + if (viewport().ShouldScroll(*scroll_node)) { // Flash the overlay scrollbar even if the scroll dalta is 0. if (settings_.scrollbar_flash_after_any_scroll_update) { FlashAllScrollbars(false); @@ -4833,10 +4885,16 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() { if (animation_controller) animation_controller->WillUpdateScroll(); } + } + + gfx::Vector2dF delta = + ScrollOffsetToVector2dF(snap_position - current_position); + bool did_animate = false; + if (scroll_node->scrolls_outer_viewport) { gfx::Vector2dF scaled_delta(delta); scaled_delta.Scale(active_tree()->page_scale_factor_for_scroll()); gfx::Vector2dF consumed_delta = - viewport()->ScrollAnimated(scaled_delta, base::TimeDelta()); + viewport().ScrollAnimated(scaled_delta, base::TimeDelta()); did_animate = !consumed_delta.IsZero(); } else { did_animate = ScrollAnimationCreate(scroll_node, delta, base::TimeDelta()); @@ -4846,23 +4904,42 @@ bool LayerTreeHostImpl::SnapAtScrollEnd() { return did_animate; } +bool LayerTreeHostImpl::FindSnapPositionAndSetTarget( + ScrollNode* scroll_node, + const SnapSelectionStrategy& strategy, + gfx::ScrollOffset* snap_position) const { + SnapContainerData& data = scroll_node->snap_container_data.value(); + + TargetSnapAreaElementIds snap_targets; + bool did_find_target = + data.FindSnapPosition(strategy, snap_position, &snap_targets); + + // Even if a target was not found we still need to invalidate the target snap + // area element ids. + if (data.SetTargetSnapAreaElementIds( + did_find_target ? snap_targets : TargetSnapAreaElementIds())) { + client_->SetNeedsCommitOnImplThread(); + } + + return did_find_target; +} + gfx::ScrollOffset LayerTreeHostImpl::GetVisualScrollOffset( const ScrollNode& scroll_node) const { - if (&scroll_node == viewport()->MainScrollNode()) - return viewport()->TotalScrollOffset(); + if (scroll_node.scrolls_outer_viewport) + return viewport().TotalScrollOffset(); return active_tree()->property_trees()->scroll_tree.current_scroll_offset( scroll_node.element_id); } -bool LayerTreeHostImpl::GetSnapFlingInfo( +bool LayerTreeHostImpl::GetSnapFlingInfoAndSetSnapTarget( const gfx::Vector2dF& natural_displacement_in_viewport, gfx::Vector2dF* out_initial_position, - gfx::Vector2dF* out_target_position) const { - const ScrollNode* scroll_node = CurrentlyScrollingNode(); + gfx::Vector2dF* out_target_position) { + ScrollNode* scroll_node = CurrentlyScrollingNode(); if (!scroll_node || !scroll_node->snap_container_data.has_value()) return false; - const SnapContainerData& data = scroll_node->snap_container_data.value(); float scale_factor = active_tree()->page_scale_factor_for_scroll(); gfx::Vector2dF natural_displacement_in_content = gfx::ScaleVector2d(natural_displacement_in_viewport, 1.f / scale_factor); @@ -4874,7 +4951,7 @@ bool LayerTreeHostImpl::GetSnapFlingInfo( std::unique_ptr<SnapSelectionStrategy> strategy = SnapSelectionStrategy::CreateForEndAndDirection( current_offset, gfx::ScrollOffset(natural_displacement_in_content)); - if (!data.FindSnapPosition(*strategy, &snap_offset)) + if (!FindSnapPositionAndSetTarget(scroll_node, *strategy, &snap_offset)) return false; *out_target_position = ScrollOffsetToVector2dF(snap_offset); @@ -4886,7 +4963,6 @@ bool LayerTreeHostImpl::GetSnapFlingInfo( void LayerTreeHostImpl::ClearCurrentlyScrollingNode() { TRACE_EVENT0("cc", "LayerTreeHostImpl::ClearCurrentlyScrollingNode"); active_tree_->ClearCurrentlyScrollingNode(); - did_lock_scrolling_layer_ = false; scroll_affects_scroll_handler_ = false; accumulated_root_overscroll_ = gfx::Vector2dF(); did_scroll_x_for_scroll_gesture_ = false; @@ -4894,10 +4970,7 @@ void LayerTreeHostImpl::ClearCurrentlyScrollingNode() { is_animating_for_snap_ = false; } -void LayerTreeHostImpl::ScrollEndImpl(ScrollState* scroll_state) { - DCHECK(scroll_state); - DCHECK(scroll_state->delta_x() == 0 && scroll_state->delta_y() == 0); - +void LayerTreeHostImpl::ScrollEndImpl() { // In smooth-scrolling path when the GSE arrives after scroll animation // completion, CurrentlyScrollingNode() is already cleared due to // ScrollEndImpl call inside ScrollOffsetAnimationFinished. In this case @@ -4906,7 +4979,6 @@ void LayerTreeHostImpl::ScrollEndImpl(ScrollState* scroll_state) { if (!last_scroller_element_id_ && CurrentlyScrollingNode()) last_scroller_element_id_ = CurrentlyScrollingNode()->element_id; - DistributeScrollDelta(scroll_state); browser_controls_offset_manager_->ScrollEnd(); ClearCurrentlyScrollingNode(); frame_trackers_.StopSequence(wheel_scrolling_ @@ -4914,15 +4986,15 @@ void LayerTreeHostImpl::ScrollEndImpl(ScrollState* scroll_state) { : FrameSequenceTrackerType::kTouchScroll); } -void LayerTreeHostImpl::ScrollEnd(ScrollState* scroll_state, bool should_snap) { +void LayerTreeHostImpl::ScrollEnd(bool should_snap) { if ((should_snap && SnapAtScrollEnd()) || mutator_host_->IsImplOnlyScrollAnimating()) { - DCHECK(!deferred_scroll_end_state_.has_value()); - deferred_scroll_end_state_ = *scroll_state; + DCHECK(!deferred_scroll_end_); + deferred_scroll_end_ = true; return; } - ScrollEndImpl(scroll_state); - deferred_scroll_end_state_.reset(); + ScrollEndImpl(); + deferred_scroll_end_ = false; scroll_gesture_did_end_ = true; client_->SetNeedsCommitOnImplThread(); } @@ -5003,9 +5075,11 @@ InputHandlerPointerResult LayerTreeHostImpl::MouseMoveAt( scroll_element_id = scroll_node->element_id; // Scrollbars for the viewport are registered with the outer viewport layer. - if (InnerViewportScrollNode() && OuterViewportScrollNode() && - scroll_element_id == InnerViewportScrollNode()->element_id) + if (InnerViewportScrollNode() && + scroll_element_id == InnerViewportScrollNode()->element_id) { + DCHECK(OuterViewportScrollNode()); scroll_element_id = OuterViewportScrollNode()->element_id; + } } ScrollbarAnimationController* new_animation_controller = @@ -5058,7 +5132,7 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, if (!InnerViewportScrollNode()) return; has_pinch_zoomed_ = true; - viewport()->PinchUpdate(magnify_delta, anchor); + viewport().PinchUpdate(magnify_delta, anchor); client_->SetNeedsCommitOnImplThread(); SetNeedsRedraw(); client_->RenewTreePriority(); @@ -5074,7 +5148,7 @@ void LayerTreeHostImpl::PinchGestureEnd(const gfx::Point& anchor, pinch_gesture_end_should_clear_scrolling_node_ = false; ClearCurrentlyScrollingNode(); } - viewport()->PinchEnd(anchor, snap_to_min); + viewport().PinchEnd(anchor, snap_to_min); browser_controls_offset_manager_->PinchEnd(); client_->SetNeedsCommitOnImplThread(); // When a pinch ends, we may be displaying content cached at incorrect scales, @@ -5123,6 +5197,8 @@ std::unique_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() { scroll_info->page_scale_delta == 1.f); scroll_info->top_controls_delta = active_tree()->top_controls_shown_ratio()->PullDeltaForMainThread(); + scroll_info->bottom_controls_delta = + active_tree()->bottom_controls_shown_ratio()->PullDeltaForMainThread(); scroll_info->elastic_overscroll_delta = active_tree_->elastic_overscroll()->PullDeltaForMainThread(); scroll_info->swap_promises.swap(swap_promises_for_main_thread_scroll_update_); @@ -5207,8 +5283,7 @@ bool LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) { gfx::ScrollOffset next_scroll = gfx::ScrollOffset( page_scale_animation_->ScrollOffsetAtTime(monotonic_time)); - DCHECK(viewport()); - viewport()->ScrollByInnerFirst(next_scroll.DeltaFrom(scroll_total)); + viewport().ScrollByInnerFirst(next_scroll.DeltaFrom(scroll_total)); if (page_scale_animation_->IsAnimationCompleteAtTime(monotonic_time)) { page_scale_animation_ = nullptr; @@ -5222,12 +5297,12 @@ bool LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) { } bool LayerTreeHostImpl::AnimateBrowserControls(base::TimeTicks time) { - if (!browser_controls_offset_manager_->has_animation()) + if (!browser_controls_offset_manager_->HasAnimation()) return false; gfx::Vector2dF scroll_delta = browser_controls_offset_manager_->Animate(time); - if (browser_controls_offset_manager_->has_animation()) + if (browser_controls_offset_manager_->HasAnimation()) SetNeedsOneBeginImplFrame(); if (active_tree_->TotalScrollOffset().y() == 0.f) @@ -5236,12 +5311,11 @@ bool LayerTreeHostImpl::AnimateBrowserControls(base::TimeTicks time) { if (scroll_delta.IsZero()) return false; - DCHECK(viewport()); - viewport()->ScrollBy(scroll_delta, - /*viewport_point=*/gfx::Point(), - /*is_wheel_scroll=*/false, - /*affect_browser_controls=*/false, - /*scroll_outer_viewport=*/true); + viewport().ScrollBy(scroll_delta, + /*viewport_point=*/gfx::Point(), + /*is_wheel_scroll=*/false, + /*affect_browser_controls=*/false, + /*scroll_outer_viewport=*/true); client_->SetNeedsCommitOnImplThread(); client_->RenewTreePriority(); return true; @@ -5320,9 +5394,10 @@ void LayerTreeHostImpl::RegisterScrollbarAnimationController( scrollbar_opacity); } -void LayerTreeHostImpl::UnregisterScrollbarAnimationController( +void LayerTreeHostImpl::DidUnregisterScrollbarLayer( ElementId scroll_element_id) { scrollbar_animation_controllers_.erase(scroll_element_id); + scrollbar_controller_->DidUnregisterScrollbar(scroll_element_id); } ScrollbarAnimationController* @@ -5331,7 +5406,8 @@ LayerTreeHostImpl::ScrollbarAnimationControllerForElementId( // The viewport layers have only one set of scrollbars. On Android, these are // registered with the inner viewport, otherwise they're registered with the // outer viewport. If a controller for one exists, the other shouldn't. - if (InnerViewportScrollNode() && OuterViewportScrollNode()) { + if (InnerViewportScrollNode()) { + DCHECK(OuterViewportScrollNode()); if (scroll_element_id == InnerViewportScrollNode()->element_id || scroll_element_id == OuterViewportScrollNode()->element_id) { auto itr = scrollbar_animation_controllers_.find( @@ -6020,15 +6096,12 @@ void LayerTreeHostImpl::ScrollOffsetAnimationFinished() { // Call scrollEnd with the deferred scroll end state when the scroll animation // completes after GSE arrival. - if (deferred_scroll_end_state_.has_value()) { - ScrollEnd(&deferred_scroll_end_state_.value(), false); + if (deferred_scroll_end_) { + ScrollEnd(/*should_snap=*/false); return; } - // TODO(majidvp): We should pass in the original starting scroll position here - ScrollStateData scroll_state_data; - ScrollState scroll_state(scroll_state_data); - ScrollEndImpl(&scroll_state); + ScrollEndImpl(); } void LayerTreeHostImpl::NotifyAnimationWorkletStateChange( @@ -6130,6 +6203,7 @@ void LayerTreeHostImpl::InitializeUkm( std::unique_ptr<ukm::UkmRecorder> recorder) { DCHECK(!ukm_manager_); ukm_manager_ = std::make_unique<UkmManager>(std::move(recorder)); + frame_trackers_.SetUkmManager(ukm_manager_.get()); } void LayerTreeHostImpl::SetActiveURL(const GURL& url, ukm::SourceId source_id) { diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h index 4242cd1e415..930a307f785 100644 --- a/chromium/cc/trees/layer_tree_host_impl.h +++ b/chromium/cc/trees/layer_tree_host_impl.h @@ -106,7 +106,6 @@ enum class GpuRasterizationStatus { ON, ON_FORCED, OFF_DEVICE, - MSAA_CONTENT, }; enum class ImplThreadPhase { @@ -271,12 +270,11 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, const gfx::Point& viewport_point, const gfx::Vector2dF& scroll_delta, base::TimeDelta delayed_by = base::TimeDelta()) override; - void ApplyScroll(ScrollNode* scroll_node, ScrollState* scroll_state); InputHandlerScrollResult ScrollBy(ScrollState* scroll_state) override; void RequestUpdateForSynchronousInputHandler() override; void SetSynchronousInputHandlerRootScrollOffset( const gfx::ScrollOffset& root_content_offset) override; - void ScrollEnd(ScrollState* scroll_state, bool should_snap = false) override; + void ScrollEnd(bool should_snap = false) override; InputHandlerPointerResult MouseDown(const gfx::PointF& viewport_point, bool shift_modifier) override; @@ -316,9 +314,13 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, // BrowserControlsOffsetManagerClient implementation. float TopControlsHeight() const override; + float TopControlsMinHeight() const override; float BottomControlsHeight() const override; - void SetCurrentBrowserControlsShownRatio(float offset) override; - float CurrentBrowserControlsShownRatio() const override; + float BottomControlsMinHeight() const override; + void SetCurrentBrowserControlsShownRatio(float top_ratio, + float bottom_ratio) override; + float CurrentTopControlsShownRatio() const override; + float CurrentBottomControlsShownRatio() const override; void DidChangeBrowserControlsPosition() override; bool HaveRootScrollNode() const override; void SetNeedsCommit() override; @@ -448,7 +450,7 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, void RegisterScrollbarAnimationController(ElementId scroll_element_id, float initial_opacity); - void UnregisterScrollbarAnimationController(ElementId scroll_element_id); + void DidUnregisterScrollbarLayer(ElementId scroll_element_id); ScrollbarAnimationController* ScrollbarAnimationControllerForElementId( ElementId scroll_element_id) const; void FlashAllScrollbars(bool did_scroll); @@ -472,6 +474,8 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, void RequestImplSideInvalidationForCheckerImagedTiles() override; size_t GetFrameIndexForImage(const PaintImage& paint_image, WhichTree tree) const override; + int GetMSAASampleCountForRaster( + const scoped_refptr<DisplayItemList>& display_list) override; // ScrollbarAnimationControllerClient implementation. void PostDelayedScrollbarAnimationTask(base::OnceClosure task, @@ -522,15 +526,12 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, virtual bool InitializeFrameSink(LayerTreeFrameSink* layer_tree_frame_sink); TileManager* tile_manager() { return &tile_manager_; } - void SetContentHasSlowPaths(bool flag); - void SetContentHasNonAAPaint(bool flag); void GetGpuRasterizationCapabilities(bool* gpu_rasterization_enabled, bool* gpu_rasterization_supported, int* max_msaa_samples, bool* supports_disable_msaa); bool use_gpu_rasterization() const { return use_gpu_rasterization_; } bool use_oop_rasterization() const { return use_oop_rasterization_; } - bool use_msaa() const { return use_msaa_; } GpuRasterizationStatus gpu_rasterization_status() const { return gpu_rasterization_status_; @@ -678,9 +679,10 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, // visual and layout offsets of the viewport. gfx::ScrollOffset GetVisualScrollOffset(const ScrollNode& scroll_node) const; - bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement_in_viewport, - gfx::Vector2dF* out_initial_position, - gfx::Vector2dF* out_target_position) const override; + bool GetSnapFlingInfoAndSetSnapTarget( + const gfx::Vector2dF& natural_displacement_in_viewport, + gfx::Vector2dF* out_initial_position, + gfx::Vector2dF* out_target_position) override; // Returns the amount of delta that can be applied to scroll_node, taking // page scale into account. @@ -763,13 +765,6 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, return paint_worklet_painter_.get(); } - // The viewport has two scroll nodes, corresponding to the visual and layout - // viewports. However, when we compute the scroll chain we include only one - // of these -- we call that the "main" scroll node. When scrolling it, we - // scroll using the Viewport class which knows how to distribute scroll - // between the two. - ScrollNode* ViewportMainScrollNode(); - void QueueImageDecode(int request_id, const PaintImage& image); std::vector<std::pair<int, bool>> TakeCompletedImageDecodeRequests(); @@ -804,6 +799,8 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, return paint_worklet_tracker_; } + bool can_use_msaa() const { return can_use_msaa_; } + protected: LayerTreeHostImpl( const LayerTreeSettings& settings, @@ -842,6 +839,10 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, void CollectScrollDeltas(ScrollAndScaleSet* scroll_info) const; void CollectScrollbarUpdates(ScrollAndScaleSet* scroll_info) const; + // Returns the ScrollNode we should use to scroll, accounting for viewport + // scroll chaining rules. + ScrollNode* GetNodeToScroll(ScrollNode* node) const; + // Transforms viewport start point and scroll delta to local start point and // local delta, respectively. If the transformation of either the start or end // point of a scroll is clipped, the function returns false. @@ -891,7 +892,7 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, bool UpdateGpuRasterizationStatus(); void UpdateTreeResourcesForGpuRasterizationIfNeeded(); - Viewport* viewport() const { return viewport_.get(); } + Viewport& viewport() const { return *viewport_.get(); } InputHandler::ScrollStatus ScrollBeginImpl( ScrollState* scroll_state, @@ -903,7 +904,8 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, bool IsInitialScrollHitTestReliable( LayerImpl* layer, LayerImpl* first_scrolling_layer_or_drawn_scrollbar); - void DistributeScrollDelta(ScrollState* scroll_state); + void LatchToScroller(ScrollState* scroll_state, ScrollNode* starting_node); + void ScrollLatchedScroller(ScrollState* scroll_state); bool AnimatePageScale(base::TimeTicks monotonic_time); bool AnimateScrollbars(base::TimeTicks monotonic_time); @@ -956,12 +958,19 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, const gfx::Vector2dF& scroll_delta, base::TimeDelta delayed_by); - void ScrollEndImpl(ScrollState* scroll_state); + void ScrollEndImpl(); // Creates an animation curve and returns true if we need to update the // scroll position to a snap point. Otherwise returns false. bool SnapAtScrollEnd(); + // Returns true if a target snap position was found. + // Updates the scrolling node's snap container data's target snap points + // accordingly to the found target. + bool FindSnapPositionAndSetTarget(ScrollNode* scroll_node, + const SnapSelectionStrategy& strategy, + gfx::ScrollOffset* snap_position) const; + void SetContextVisibility(bool is_visible); void ImageDecodeFinished(int request_id, bool decode_succeeded); @@ -1035,12 +1044,12 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, std::unique_ptr<viz::ContextCacheController::ScopedVisibility> worker_context_visibility_; + bool can_use_msaa_ = false; + bool supports_disable_msaa_ = false; + bool need_update_gpu_rasterization_status_ = false; - bool content_has_slow_paths_ = false; - bool content_has_non_aa_paint_ = false; bool use_gpu_rasterization_ = false; bool use_oop_rasterization_ = false; - bool use_msaa_ = false; GpuRasterizationStatus gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE; std::unique_ptr<RasterBufferProvider> raster_buffer_provider_; @@ -1061,7 +1070,6 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, std::unique_ptr<LayerTreeImpl> recycle_tree_; InputHandlerClient* input_handler_client_ = nullptr; - bool did_lock_scrolling_layer_ = false; bool touch_scrolling_ = false; bool wheel_scrolling_ = false; bool middle_click_autoscrolling_ = false; @@ -1237,6 +1245,12 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, base::Optional<RenderFrameMetadata> last_draw_render_frame_metadata_; viz::ChildLocalSurfaceIdAllocator child_local_surface_id_allocator_; + // Indicates the direction of the last vertical scroll of the root layer. + // Until the first vertical scroll occurs, this value is |kNull|. Note that + // once this value is updated, it will never return to |kNull|. + viz::VerticalScrollDirection last_vertical_scroll_direction_ = + viz::VerticalScrollDirection::kNull; + std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; PresentationTimeCallbackBuffer presentation_time_callbacks_; @@ -1259,10 +1273,10 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, ElementId last_scroller_element_id_; // Scroll animation can finish either before or after GSE arrival. - // deferred_scroll_end_state_ is set when the GSE has arrvied before scroll - // animation completion. ScrollEnd will get called with this deferred state - // once the animation is over. - base::Optional<ScrollState> deferred_scroll_end_state_; + // deferred_scroll_end_ is set when the GSE has arrvied before scroll + // animation completion. ScrollEnd will get called once the animation is + // over. + bool deferred_scroll_end_ = false; // PaintWorklet painting is controlled from the LayerTreeHostImpl, dispatched // to the worklet thread via |paint_worklet_painter_|. @@ -1273,6 +1287,11 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler, // not we are in that state. bool pending_tree_fully_painted_ = false; +#if DCHECK_IS_ON() + // Use to track when doing a synchronous draw. + bool doing_sync_draw_ = false; +#endif + // Provides support for PaintWorklets which depend on input properties that // are being animated by the compositor (aka 'animated' PaintWorklets). // Responsible for storing animated custom property values and for diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc index 986eca85577..2d897103570 100644 --- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc @@ -279,7 +279,7 @@ class LayerTreeHostImplTest : public testing::Test, host_impl_->SetVisible(true); bool init = host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get()); host_impl_->active_tree()->SetDeviceViewportRect(gfx::Rect(10, 10)); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 1); host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( viz::LocalSurfaceIdAllocation( viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), @@ -451,9 +451,10 @@ class LayerTreeHostImplTest : public testing::Test, gfx::Size scroll_content_size = gfx::Size(345, 3800); gfx::Size scrollbar_size = gfx::Size(15, 600); - LayerImpl* root = SetupRootLayer<LayerImpl>(layer_tree_impl, content_size); + SetupViewportLayersNoScrolls(content_size); + LayerImpl* outer_scroll = OuterViewportScrollLayer(); LayerImpl* scroll = - AddScrollableLayer(root, content_size, scroll_content_size); + AddScrollableLayer(outer_scroll, content_size, scroll_content_size); auto* squash2 = AddLayer<LayerImpl>(layer_tree_impl); squash2->SetBounds(gfx::Size(140, 300)); @@ -470,7 +471,7 @@ class LayerTreeHostImplTest : public testing::Test, auto* squash1 = AddLayer<LayerImpl>(layer_tree_impl); squash1->SetBounds(gfx::Size(140, 300)); - CopyProperties(root, squash1); + CopyProperties(outer_scroll, squash1); squash1->SetOffsetToTransformParent(gfx::Vector2dF(220, 0)); if (transparent_layer) { CreateEffectNode(squash1).opacity = 0.0f; @@ -488,22 +489,25 @@ class LayerTreeHostImplTest : public testing::Test, // The point hits squash1 layer and also scroll layer, because scroll layer // is not an ancestor of squash1 layer, we cannot scroll on impl thread. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(230, 150)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(230, 150), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); ASSERT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, status.main_thread_scrolling_reasons); // The point hits squash1 layer and also scrollbar layer. - status = host_impl_->ScrollBegin(BeginState(gfx::Point(350, 150)).get(), - InputHandler::WHEEL); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(350, 150), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); ASSERT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest, status.main_thread_scrolling_reasons); // The point hits squash2 layer and also scroll layer, because scroll layer // is an ancestor of squash2 layer, we should scroll on impl. - status = host_impl_->ScrollBegin(BeginState(gfx::Point(230, 450)).get(), - InputHandler::WHEEL); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(230, 450), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); } @@ -549,7 +553,7 @@ class LayerTreeHostImplTest : public testing::Test, scrollbar->SetElementId(LayerIdToElementIdForTesting(scrollbar->id())); SetupScrollbarLayerCommon(scroll_layer, scrollbar); auto& effect = CreateEffectNode(scrollbar); - effect.opacity = 0.f; + effect.opacity = 0; effect.has_potential_opacity_animation = true; } @@ -557,7 +561,7 @@ class LayerTreeHostImplTest : public testing::Test, PaintedScrollbarLayerImpl* scrollbar) { SetupScrollbarLayerCommon(scroll_layer, scrollbar); scrollbar->SetHitTestable(true); - CreateEffectNode(scrollbar).opacity = 1.f; + CreateEffectNode(scrollbar).opacity = 1; } LayerImpl* InnerViewportScrollLayer() { @@ -567,11 +571,14 @@ class LayerTreeHostImplTest : public testing::Test, return host_impl_->active_tree()->OuterViewportScrollLayerForTesting(); } - std::unique_ptr<ScrollState> BeginState(const gfx::Point& point) { + std::unique_ptr<ScrollState> BeginState(const gfx::Point& point, + const gfx::Vector2dF& delta_hint) { ScrollStateData scroll_state_data; scroll_state_data.is_beginning = true; scroll_state_data.position_x = point.x(); scroll_state_data.position_y = point.y(); + scroll_state_data.delta_x_hint = delta_hint.x(); + scroll_state_data.delta_y_hint = delta_hint.y(); std::unique_ptr<ScrollState> scroll_state( new ScrollState(scroll_state_data)); return scroll_state; @@ -589,20 +596,16 @@ class LayerTreeHostImplTest : public testing::Test, return scroll_state; } - std::unique_ptr<ScrollState> EndState() { - ScrollStateData scroll_state_data; - scroll_state_data.is_ending = true; - std::unique_ptr<ScrollState> scroll_state( - new ScrollState(scroll_state_data)); - return scroll_state; - } - void DrawFrame() { PrepareForUpdateDrawProperties(host_impl_->active_tree()); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } RenderFrameMetadata StartDrawAndProduceRenderFrameMetadata() { @@ -701,7 +704,7 @@ class LayerTreeHostImplTest : public testing::Test, ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(300, 300)); SnapAreaData area_data(ScrollSnapAlign(SnapAlignment::kStart), - gfx::RectF(50, 50, 100, 100), false); + gfx::RectF(50, 50, 100, 100), false, ElementId(10)); container_data.AddSnapAreaData(area_data); GetScrollNode(overflow)->snap_container_data.emplace(container_data); DrawFrame(); @@ -709,6 +712,11 @@ class LayerTreeHostImplTest : public testing::Test, return overflow; } + base::Optional<SnapContainerData> GetSnapContainerData(LayerImpl* layer) { + return GetScrollNode(layer) ? GetScrollNode(layer)->snap_container_data + : base::nullopt; + } + void ClearLayersAndPropertyTrees(LayerTreeImpl* layer_tree_impl) { layer_tree_impl->SetRootLayerForTesting(nullptr); layer_tree_impl->DetachLayers(); @@ -815,9 +823,9 @@ class LayerTreeHostImplTimelinesTest : public LayerTreeHostImplTest { class TestInputHandlerClient : public InputHandlerClient { public: TestInputHandlerClient() - : page_scale_factor_(0.f), - min_page_scale_factor_(-1.f), - max_page_scale_factor_(-1.f) {} + : page_scale_factor_(0), + min_page_scale_factor_(-1), + max_page_scale_factor_(-1) {} ~TestInputHandlerClient() override = default; // InputHandlerClient implementation. @@ -1041,13 +1049,15 @@ TEST_F(CommitToPendingTreeLayerTreeHostImplTest, TEST_F(LayerTreeHostImplTest, ScrollBeforeRootLayerAttached) { InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 1)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, status.main_thread_scrolling_reasons); - status = host_impl_->RootScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL); + status = host_impl_->RootScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 1)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, status.main_thread_scrolling_reasons); @@ -1058,7 +1068,8 @@ TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) { DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1066,7 +1077,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) { EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, 10))); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); @@ -1077,22 +1088,24 @@ TEST_F(LayerTreeHostImplTest, ScrollActiveOnlyAfterScrollMovement) { DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_FALSE(host_impl_->IsActivelyScrolling()); + EXPECT_TRUE(host_impl_->IsActivelyScrolling()); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); EXPECT_TRUE(host_impl_->IsActivelyScrolling()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsActivelyScrolling()); } TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) { // We should not crash when trying to scroll an empty layer tree. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, status.main_thread_scrolling_reasons); @@ -1113,7 +1126,8 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) { // We should not crash when trying to scroll after the renderer initialization // fails. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1124,10 +1138,14 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { DrawFrame(); // We should not crash if the tree is replaced while we are scrolling. + gfx::ScrollOffset scroll_delta(0, 10); EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(gfx::Point(), + gfx::ScrollOffsetToVector2dF(scroll_delta)) + .get(), + InputHandler::WHEEL) .thread); ClearLayersAndPropertyTrees(host_impl_->active_tree()); @@ -1136,17 +1154,43 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { // We should still be scrolling, because the scrolled layer also exists in the // new tree. - gfx::ScrollOffset scroll_delta(0, 10); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF(scroll_delta)) .get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), scroll_delta)); } +TEST_F(LayerTreeHostImplTest, ActivateTreeScrollingNodeDisappeared) { + SetupViewportLayersOuterScrolls(gfx::Size(100, 100), gfx::Size(1000, 1000)); + + auto status = host_impl_->ScrollBegin( + BeginState(gfx::Point(30, 30), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); + EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, + status.main_thread_scrolling_reasons); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); + EXPECT_TRUE(host_impl_->active_tree()->CurrentlyScrollingNode()); + EXPECT_TRUE(host_impl_->IsActivelyScrolling()); + + // Create the pending tree containing only the root layer. + CreatePendingTree(); + PropertyTrees pending_property_trees; + pending_property_trees.sequence_number = + host_impl_->active_tree()->property_trees()->sequence_number + 1; + host_impl_->pending_tree()->SetPropertyTrees(&pending_property_trees); + SetupRootLayer<LayerImpl>(host_impl_->pending_tree(), gfx::Size(100, 100)); + host_impl_->ActivateSyncTree(); + + // The scroll should stop. + EXPECT_FALSE(host_impl_->active_tree()->CurrentlyScrollingNode()); + EXPECT_FALSE(host_impl_->IsActivelyScrolling()); +} + TEST_F(LayerTreeHostImplTest, ScrollBlocksOnWheelEventHandlers) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); auto* scroll = InnerViewportScrollLayer(); @@ -1167,11 +1211,12 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnWheelEventHandlers) { // But they don't influence the actual handling of the scroll gestures. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplTest, ScrollBlocksOnTouchEventHandlers) { @@ -1199,11 +1244,12 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnTouchEventHandlers) { // But they don't influence the actual handling of the scroll gestures. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN); + BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_EQ(InputHandler::TouchStartOrMoveEventListenerType::HANDLER, host_impl_->EventListenerTypeForTouchStartOrMoveAt( @@ -1229,13 +1275,15 @@ TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) { DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, status.main_thread_scrolling_reasons); - status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, status.main_thread_scrolling_reasons); @@ -1256,9 +1304,9 @@ TEST_F(LayerTreeHostImplTest, ScrolledOverlappingDrawnScrollbarLayer) { gfx::Size scroll_content_size = gfx::Size(345, 3800); gfx::Size scrollbar_size = gfx::Size(15, 600); - LayerImpl* root = SetupDefaultRootLayer(content_size); - LayerImpl* scroll = - AddScrollableLayer(root, content_size, scroll_content_size); + SetupViewportLayersNoScrolls(content_size); + LayerImpl* scroll = AddScrollableLayer(OuterViewportScrollLayer(), + content_size, scroll_content_size); auto* drawn_scrollbar = AddLayer<PaintedScrollbarLayerImpl>( layer_tree_impl, VERTICAL, false, true); @@ -1278,16 +1326,18 @@ TEST_F(LayerTreeHostImplTest, ScrolledOverlappingDrawnScrollbarLayer) { // The point hits squash layer and also scrollbar layer, but because the // scrollbar layer is a drawn scrollbar, we cannot scroll on the impl thread. - auto status = host_impl_->ScrollBegin(BeginState(gfx::Point(350, 150)).get(), - InputHandler::WHEEL); + auto status = host_impl_->ScrollBegin( + BeginState(gfx::Point(350, 150), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, status.main_thread_scrolling_reasons); // The point hits the drawn scrollbar layer completely and should scroll on // the impl thread. - status = host_impl_->ScrollBegin(BeginState(gfx::Point(350, 500)).get(), - InputHandler::WHEEL); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(350, 500), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1303,22 +1353,25 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) { // All scroll types inside the non-fast scrollable region should fail. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(25, 25)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(25, 25), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, status.main_thread_scrolling_reasons); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25))); - status = host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(), - InputHandler::TOUCHSCREEN); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(25, 25), gfx::Vector2d(0, 10)).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, status.main_thread_scrolling_reasons); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25))); // All scroll types outside this region should succeed. - status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), - InputHandler::WHEEL); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(75, 75), gfx::Vector2d(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1326,17 +1379,18 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) { EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75))); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25))); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75))); - status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), - InputHandler::TOUCHSCREEN); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(75, 75), gfx::Vector2d(0, 10)).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75))); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75))); } @@ -1345,7 +1399,7 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) { LayerImpl* outer_scroll = OuterViewportScrollLayer(); outer_scroll->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50)); - SetPostTranslation(outer_scroll, gfx::Vector2dF(-25.f, 0.f)); + SetPostTranslation(outer_scroll, gfx::Vector2dF(-25, 0)); outer_scroll->SetDrawsContent(true); DrawFrame(); @@ -1353,18 +1407,20 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) { // This point would fall into the non-fast scrollable region except that we've // moved the layer left by 25 pixels. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(40, 10)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(40, 10), gfx::Vector2d(0, 1)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10))); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 1)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // This point is still inside the non-fast region. - status = host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::WHEEL); + status = host_impl_->ScrollBegin( + BeginState(gfx::Point(10, 10), gfx::Vector2d(0, 1)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, status.main_thread_scrolling_reasons); @@ -1376,10 +1432,10 @@ TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) { DrawFrame(); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), InputHandler::TOUCHSCREEN); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); } @@ -1389,10 +1445,10 @@ TEST_F(LayerTreeHostImplTest, ScrollHandlerPresent) { DrawFrame(); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), InputHandler::TOUCHSCREEN); EXPECT_TRUE(host_impl_->scroll_affects_scroll_handler()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); } @@ -1401,7 +1457,8 @@ TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) { DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN); + BeginState(gfx::Point(), gfx::Vector2d(-10, 0)).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1475,19 +1532,26 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnX) { LayerImpl* overflow = CreateLayerForSnapping(); gfx::Point pointer_position(10, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + gfx::Vector2dF x_delta(20, 0); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); - gfx::Vector2dF x_delta(20, 0); host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - host_impl_->ScrollEnd(EndState().get(), true); + host_impl_->ScrollEnd(true); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); + base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); BeginImplFrameAndAnimate(begin_frame_args, start_time); @@ -1497,25 +1561,33 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnX) { begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1000)); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 0), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); } TEST_F(LayerTreeHostImplTest, ScrollSnapOnY) { LayerImpl* overflow = CreateLayerForSnapping(); gfx::Point pointer_position(10, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + gfx::Vector2dF y_delta(0, 20); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, y_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); - gfx::Vector2dF y_delta(0, 20); host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - host_impl_->ScrollEnd(EndState().get(), true); + host_impl_->ScrollEnd(true); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); BeginImplFrameAndAnimate(begin_frame_args, start_time); @@ -1525,25 +1597,33 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnY) { begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1000)); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 50), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); } TEST_F(LayerTreeHostImplTest, ScrollSnapOnBoth) { LayerImpl* overflow = CreateLayerForSnapping(); gfx::Point pointer_position(10, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + gfx::Vector2dF delta(20, 20); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); - gfx::Vector2dF delta(20, 20); host_impl_->ScrollBy(UpdateState(pointer_position, delta).get()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - host_impl_->ScrollEnd(EndState().get(), true); + host_impl_->ScrollEnd(true); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); BeginImplFrameAndAnimate(begin_frame_args, start_time); @@ -1553,6 +1633,8 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapOnBoth) { begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1000)); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); } TEST_F(LayerTreeHostImplTest, ScrollSnapAfterAnimatedScroll) { @@ -1567,6 +1649,9 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapAfterAnimatedScroll) { EXPECT_EQ(overflow->scroll_tree_index(), host_impl_->CurrentlyScrollingNode()->id); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); + base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); viz::BeginFrameArgs begin_frame_args = @@ -1582,37 +1667,44 @@ TEST_F(LayerTreeHostImplTest, ScrollSnapAfterAnimatedScroll) { EXPECT_GT(20, current_offset.x()); EXPECT_LT(0, current_offset.y()); EXPECT_GT(20, current_offset.y()); + EXPECT_EQ(TargetSnapAreaElementIds(), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); - // Animating for the snap. + // The scroll animation is finished, so the snap target should be set now and + // the snap animation should begin. BeginImplFrameAndAnimate( begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1000)); EXPECT_TRUE(host_impl_->is_animating_for_snap_for_testing()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); // Finish the animation. BeginImplFrameAndAnimate( begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(1500)); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), overflow->CurrentScrollOffset()); EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); } TEST_F(LayerTreeHostImplTest, SnapAnimationCancelledByScroll) { LayerImpl* overflow = CreateLayerForSnapping(); gfx::Point pointer_position(10, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + gfx::Vector2dF x_delta(20, 0); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); - gfx::Vector2dF x_delta(20, 0); host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get()); EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing()); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - host_impl_->ScrollEnd(EndState().get(), true); + host_impl_->ScrollEnd(true); base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); BeginImplFrameAndAnimate(begin_frame_args, start_time); @@ -1626,12 +1718,12 @@ TEST_F(LayerTreeHostImplTest, SnapAnimationCancelledByScroll) { EXPECT_LT(20, current_offset.x()); EXPECT_EQ(0, current_offset.y()); - // Interrup the snap animation with ScrollBegin. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + // Interrupt the snap animation with ScrollBegin. + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing()); BeginImplFrameAndAnimate(begin_frame_args, start_time + base::TimeDelta::FromMilliseconds(150)); @@ -1644,21 +1736,21 @@ TEST_F(LayerTreeHostImplTest, LayerImpl* overflow = CreateLayerForSnapping(); gfx::Point pointer_position(10, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + gfx::Vector2dF x_delta(50, 0); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); // There is a snap target at 50, scroll to it directly. - gfx::Vector2dF x_delta(50, 0); host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get()); EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing()); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - host_impl_->ScrollEnd(EndState().get(), true); + host_impl_->ScrollEnd(true); base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); BeginImplFrameAndAnimate(begin_frame_args, start_time); @@ -1672,34 +1764,38 @@ TEST_F(LayerTreeHostImplTest, start_time + base::TimeDelta::FromMilliseconds(100)); EXPECT_FALSE(host_impl_->is_animating_for_snap_for_testing()); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 0), overflow->CurrentScrollOffset()); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId()), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); } -TEST_F(LayerTreeHostImplTest, GetSnapFlingInfoWhenZoomed) { +TEST_F(LayerTreeHostImplTest, GetSnapFlingInfoAndSetSnapTargetWhenZoomed) { LayerImpl* overflow = CreateLayerForSnapping(); // Scales the page to its 1/5. - host_impl_->active_tree()->PushPageScaleFromMainThread(0.2f, 0.1f, 5.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(0.2f, 0.1f, 5); // Should be (10, 10) in the scroller's coordinate. gfx::Point pointer_position(2, 2); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + gfx::Vector2dF delta(4, 4); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); // Should be (20, 20) in the scroller's coordinate. - gfx::Vector2dF delta(4, 4); InputHandlerScrollResult result = host_impl_->ScrollBy(UpdateState(pointer_position, delta).get()); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), overflow->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(4, 4), result.current_visual_offset); gfx::Vector2dF initial_offset, target_offset; - EXPECT_TRUE(host_impl_->GetSnapFlingInfo(gfx::Vector2dF(10, 10), - &initial_offset, &target_offset)); + EXPECT_TRUE(host_impl_->GetSnapFlingInfoAndSetSnapTarget( + gfx::Vector2dF(10, 10), &initial_offset, &target_offset)); EXPECT_VECTOR_EQ(gfx::Vector2dF(4, 4), initial_offset); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), target_offset); + EXPECT_EQ(TargetSnapAreaElementIds(ElementId(10), ElementId(10)), + GetSnapContainerData(overflow)->GetTargetSnapAreaElementIds()); } TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { @@ -1716,21 +1812,21 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { DrawFrame(); gfx::Point pointer_position(50, 50); + gfx::Vector2dF x_delta(-10, 0); + gfx::Vector2dF y_delta(0, -10); + gfx::Vector2dF diagonal_delta(-10, -10); // OverscrollBehaviorTypeAuto shouldn't prevent scroll propagation. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(30, 30), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset()); - gfx::Vector2dF x_delta(-10, 0); - gfx::Vector2dF y_delta(0, -10); - gfx::Vector2dF diagonal_delta(-10, -10); host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); @@ -1742,31 +1838,31 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { // OverscrollBehaviorContain on x should prevent propagations of scroll // on x. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); // OverscrollBehaviorContain on x shouldn't prevent propagations of // scroll on y. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, y_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 30), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); @@ -1775,13 +1871,14 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(pointer_position, diagonal_delta).get(), + InputHandler::WHEEL) .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(pointer_position, diagonal_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); @@ -1794,31 +1891,31 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { // OverscrollBehaviorContain on y shouldn't prevent propagations of // scroll on x. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(pointer_position, x_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); // OverscrollBehaviorContain on y should prevent propagations of scroll // on y. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, y_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); @@ -1827,13 +1924,14 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(pointer_position, diagonal_delta).get(), + InputHandler::WHEEL) .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(pointer_position, diagonal_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); @@ -1845,11 +1943,11 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { DrawFrame(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(pointer_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(pointer_position, x_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), overflow->CurrentScrollOffset()); @@ -1857,7 +1955,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollBehaviorPreventsPropagation) { host_impl_->ScrollBy(UpdateState(pointer_position, -x_delta).get()); host_impl_->ScrollBy(UpdateState(pointer_position, y_delta).get()); host_impl_->ScrollBy(UpdateState(pointer_position, -y_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset()); } @@ -1875,18 +1973,18 @@ TEST_F(LayerTreeHostImplTest, ScrollWithUserUnscrollableLayers) { DrawFrame(); gfx::Point scroll_position(10, 10); + gfx::Vector2dF scroll_delta(10, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(scroll_position, scroll_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset()); - gfx::Vector2dF scroll_delta(10, 10); host_impl_->ScrollBy(UpdateState(scroll_position, scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset()); @@ -1894,32 +1992,32 @@ TEST_F(LayerTreeHostImplTest, ScrollWithUserUnscrollableLayers) { DrawFrame(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(scroll_position, scroll_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(scroll_position, scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset()); GetScrollNode(overflow)->user_scrollable_vertical = false; DrawFrame(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(scroll_position).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(scroll_position, scroll_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(scroll_position, scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset()); } @@ -1933,7 +2031,8 @@ TEST_F(LayerTreeHostImplTest, ForceMainThreadScrollWithoutScrollLayer) { DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(25, 25)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(25, 25), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, status.main_thread_scrolling_reasons); @@ -2008,9 +2107,9 @@ TEST_F(CommitToPendingTreeLayerTreeHostImplTest, // Add a translate from 6,7 to 8,9. TransformOperations start; - start.AppendTranslate(6.f, 7.f, 0.f); + start.AppendTranslate(6, 7, 0); TransformOperations end; - end.AppendTranslate(8.f, 9.f, 0.f); + end.AppendTranslate(8, 9, 0); AddAnimatedTransformToElementWithAnimation(child->element_id(), timeline(), 4.0, start, end); UpdateDrawProperties(host_impl_->active_tree()); @@ -2101,9 +2200,9 @@ TEST_F(LayerTreeHostImplTest, AnimationSchedulingOnLayerDestruction) { // Add a translate animation. TransformOperations start; - start.AppendTranslate(6.f, 7.f, 0.f); + start.AppendTranslate(6, 7, 0); TransformOperations end; - end.AppendTranslate(8.f, 9.f, 0.f); + end.AppendTranslate(8, 9, 0); AddAnimatedTransformToElementWithAnimation(child->element_id(), timeline(), 4.0, start, end); UpdateDrawProperties(host_impl_->active_tree()); @@ -2174,8 +2273,8 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { LayerImpl* scroll_layer = InnerViewportScrollLayer(); EXPECT_EQ(gfx::Size(50, 50), root_layer()->bounds()); - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 1.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 1; // The impl-based pinch zoom should adjust the max scroll position. { @@ -2184,14 +2283,18 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); - float page_scale_delta = 2.f; + float page_scale_delta = 2; - host_impl_->ScrollBegin(BeginState(gfx::Point(50, 50)).get(), - InputHandler::TOUCHSCREEN); + // TODO(bokan): What are the delta_hints for a GSB that's sent for a pinch + // gesture that doesn't cause (initial) scrolling? + // https://crbug.com/1030262 + host_impl_->ScrollBegin( + BeginState(gfx::Point(50, 50), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(gfx::Point(50, 50), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); @@ -2213,22 +2316,23 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); - float page_scale_delta = 2.f; - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + float page_scale_delta = 2; + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); gfx::Vector2d scroll_delta(0, 10); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2260,7 +2364,7 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollbarGeometry) { // Setup LayerTreeImpl* active_tree = host_impl_->active_tree(); - active_tree->PushPageScaleFromMainThread(1.f, minimum_scale, 4.f); + active_tree->PushPageScaleFromMainThread(1, minimum_scale, 4); // When Chrome on Android loads a non-mobile page, it resizes the main // frame (outer viewport) such that it matches the width of the content, @@ -2285,7 +2389,7 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollbarGeometry) { host_impl_->active_tree()->DidBecomeActive(); // Zoom out to the minimum scale. The scrollbars shoud not be scrollable. - host_impl_->active_tree()->SetPageScaleOnActiveTree(0.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(0); EXPECT_FALSE(v_scrollbar->CanScrollOrientation()); EXPECT_FALSE(h_scrollbar->CanScrollOrientation()); @@ -2298,7 +2402,7 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollbarGeometry) { TEST_F(LayerTreeHostImplTest, ViewportScrollOrder) { LayerTreeSettings settings = DefaultSettings(); CreateHostImpl(settings, CreateLayerTreeFrameSink()); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.25f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.25f, 4); const gfx::Size content_size(1000, 1000); const gfx::Size viewport_size(500, 500); @@ -2313,12 +2417,13 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollOrder) { EXPECT_VECTOR_EQ(gfx::Vector2dF(500, 500), outer_scroll_layer->MaxScrollOffset()); - host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(250, 250), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); - host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0)); + host_impl_->PinchGestureUpdate(2, gfx::Point(0, 0)); host_impl_->PinchGestureEnd(gfx::Point(0, 0), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Sanity check - we're zoomed in, starting from the origin. EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), @@ -2327,11 +2432,12 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollOrder) { inner_scroll_layer->CurrentScrollOffset()); // Scroll down - only the inner viewport should scroll. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), inner_scroll_layer->CurrentScrollOffset()); @@ -2340,11 +2446,12 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollOrder) { // Scroll down - outer viewport should start scrolling after the inner is at // its maximum. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000.f, 1000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(250, 250), inner_scroll_layer->CurrentScrollOffset()); @@ -2355,7 +2462,7 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollOrder) { // Make sure scrolls smaller than a unit applied to the viewport don't get // dropped. crbug.com/539334. TEST_F(LayerTreeHostImplTest, ScrollViewportWithFractionalAmounts) { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); const gfx::Size content_size(1000, 1000); const gfx::Size viewport_size(500, 500); @@ -2374,28 +2481,30 @@ TEST_F(LayerTreeHostImplTest, ScrollViewportWithFractionalAmounts) { EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll_layer->CurrentScrollOffset()); // Scroll only the layout viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(250, 250), gfx::Vector2dF(0.125f, 0.125f)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(250, 250), gfx::Vector2dF(0.125f, 0.125f)).get()); EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0.125f, 0.125f), outer_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0, 0), inner_scroll_layer->CurrentScrollOffset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); - host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(2, 1, 2); // Now that we zoomed in, the scroll should be applied to the inner viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(250, 250), gfx::Vector2dF(0.5f, 0.5f)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(250, 250), gfx::Vector2dF(0.5f, 0.5f)).get()); EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0.125f, 0.125f), outer_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0.25f, 0.25f), inner_scroll_layer->CurrentScrollOffset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } // Tests that scrolls during a pinch gesture (i.e. "two-finger" scrolls) work @@ -2404,7 +2513,7 @@ TEST_F(LayerTreeHostImplTest, ScrollViewportWithFractionalAmounts) { TEST_F(LayerTreeHostImplTest, ScrollDuringPinchGesture) { LayerTreeSettings settings = DefaultSettings(); CreateHostImpl(settings, CreateLayerTreeFrameSink()); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); const gfx::Size content_size(1000, 1000); const gfx::Size viewport_size(500, 500); @@ -2419,8 +2528,9 @@ TEST_F(LayerTreeHostImplTest, ScrollDuringPinchGesture) { EXPECT_VECTOR_EQ(gfx::Vector2dF(500, 500), outer_scroll_layer->MaxScrollOffset()); - host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(250, 250), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, gfx::Point(250, 250)); @@ -2433,7 +2543,7 @@ TEST_F(LayerTreeHostImplTest, ScrollDuringPinchGesture) { DrawFrame(); host_impl_->ScrollBy( - UpdateState(gfx::Point(250, 250), gfx::Vector2dF(10.f, 10.f)).get()); + UpdateState(gfx::Point(250, 250), gfx::Vector2dF(10, 10)).get()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(130, 130), @@ -2442,14 +2552,14 @@ TEST_F(LayerTreeHostImplTest, ScrollDuringPinchGesture) { DrawFrame(); host_impl_->ScrollBy( - UpdateState(gfx::Point(250, 250), gfx::Vector2dF(400.f, 400.f)).get()); + UpdateState(gfx::Point(250, 250), gfx::Vector2dF(400, 400)).get()); EXPECT_VECTOR_EQ(gfx::Vector2dF(80, 80), outer_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(250, 250), inner_scroll_layer->CurrentScrollOffset()); host_impl_->PinchGestureEnd(gfx::Point(250, 250), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } // Tests the "snapping" of pinch-zoom gestures to the screen edge. That is, when @@ -2458,7 +2568,7 @@ TEST_F(LayerTreeHostImplTest, ScrollDuringPinchGesture) { TEST_F(LayerTreeHostImplTest, PinchZoomSnapsToScreenEdge) { LayerTreeSettings settings = DefaultSettings(); CreateHostImpl(settings, CreateLayerTreeFrameSink()); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); const gfx::Size content_size(1000, 1000); const gfx::Size viewport_size(500, 500); @@ -2470,51 +2580,54 @@ TEST_F(LayerTreeHostImplTest, PinchZoomSnapsToScreenEdge) { // Pinch in within the margins. The scroll should stay exactly locked to the // bottom and right. - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin(BeginState(anchor, gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(anchor, true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(250, 250), InnerViewportScrollLayer()->CurrentScrollOffset()); // Reset. - host_impl_->active_tree()->SetPageScaleOnActiveTree(1.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(1); SetScrollOffsetDelta(InnerViewportScrollLayer(), gfx::Vector2d()); SetScrollOffsetDelta(OuterViewportScrollLayer(), gfx::Vector2d()); // Pinch in within the margins. The scroll should stay exactly locked to the // top and left. anchor = gfx::Point(offsetFromEdge, offsetFromEdge); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin(BeginState(anchor, gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(anchor, true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), InnerViewportScrollLayer()->CurrentScrollOffset()); // Reset. - host_impl_->active_tree()->SetPageScaleOnActiveTree(1.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(1); SetScrollOffsetDelta(InnerViewportScrollLayer(), gfx::Vector2d()); SetScrollOffsetDelta(OuterViewportScrollLayer(), gfx::Vector2d()); // Pinch in just outside the margin. There should be no snapping. offsetFromEdge = Viewport::kPinchZoomSnapMarginDips; anchor = gfx::Point(offsetFromEdge, offsetFromEdge); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin(BeginState(anchor, gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(anchor, true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), InnerViewportScrollLayer()->CurrentScrollOffset()); // Reset. - host_impl_->active_tree()->SetPageScaleOnActiveTree(1.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(1); SetScrollOffsetDelta(InnerViewportScrollLayer(), gfx::Vector2d()); SetScrollOffsetDelta(OuterViewportScrollLayer(), gfx::Vector2d()); @@ -2522,11 +2635,12 @@ TEST_F(LayerTreeHostImplTest, PinchZoomSnapsToScreenEdge) { offsetFromEdge = Viewport::kPinchZoomSnapMarginDips; anchor = gfx::Point(viewport_size.width() - offsetFromEdge, viewport_size.height() - offsetFromEdge); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin(BeginState(anchor, gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(anchor, true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(200, 200), InnerViewportScrollLayer()->CurrentScrollOffset()); @@ -2541,19 +2655,20 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) { LayerImpl* inner_scroll_layer = InnerViewportScrollLayer(); // Zoom into the page by a 2X factor - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 2.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); // Scroll by a small amount, there should be no bubbling to the outer // viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(10, 20)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(10.f, 20.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(10, 20)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 10), inner_scroll_layer->CurrentScrollOffset()); @@ -2561,11 +2676,12 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) { // Scroll by the inner viewport's max scroll extent, the remainder // should bubble up to the outer viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), inner_scroll_layer->CurrentScrollOffset()); @@ -2574,11 +2690,12 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) { // Scroll by the outer viewport's max scroll extent, it should all go to the // outer viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(190, 180)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(190.f, 180.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(190, 180)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(100, 100), outer_scroll_layer->CurrentScrollOffset()); @@ -2594,15 +2711,16 @@ TEST_F(LayerTreeHostImplTest, ScrollWithSwapPromises) { new LatencyInfoSwapPromise(latency_info)); SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 10)).get(), + InputHandler::TOUCHSCREEN) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); host_impl_->QueueSwapPromiseForMainThreadScrollUpdate( std::move(swap_promise)); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2634,13 +2752,14 @@ TEST_F(LayerTreeHostImplTest, ScrollDoesntBubble) { DrawFrame(); { - host_impl_->ScrollBegin(BeginState(gfx::Point(21, 21)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(21, 21), gfx::Vector2d(5, 5)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(21, 21), gfx::Vector2d(5, 5)).get()); host_impl_->ScrollBy( UpdateState(gfx::Point(21, 21), gfx::Vector2d(100, 100)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The child should be fully scrolled by the first ScrollBy. EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 5), scroll_child->CurrentScrollOffset()); @@ -2657,8 +2776,9 @@ TEST_F(LayerTreeHostImplTest, ScrollDoesntBubble) { } { - host_impl_->ScrollBegin(BeginState(gfx::Point(21, 21)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(21, 21), gfx::Vector2d(3, 4)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(21, 21), gfx::Vector2d(3, 4)).get()); host_impl_->ScrollBy( @@ -2667,7 +2787,7 @@ TEST_F(LayerTreeHostImplTest, ScrollDoesntBubble) { UpdateState(gfx::Point(21, 21), gfx::Vector2d(2, 1)).get()); host_impl_->ScrollBy( UpdateState(gfx::Point(21, 21), gfx::Vector2d(2, 1)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The ScrollBy's should scroll the parent to its extent. EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 5), @@ -2688,22 +2808,23 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { LayerImpl* scroll_layer = InnerViewportScrollLayer(); DCHECK(scroll_layer); - float min_page_scale = 1.f; - float max_page_scale = 4.f; + float min_page_scale = 1; + float max_page_scale = 4; // Basic pinch zoom in gesture { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); - float page_scale_delta = 2.f; - host_impl_->ScrollBegin(BeginState(gfx::Point(50, 50)).get(), - InputHandler::TOUCHSCREEN); + float page_scale_delta = 2; + host_impl_->ScrollBegin( + BeginState(gfx::Point(50, 50), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(gfx::Point(50, 50), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); @@ -2715,17 +2836,18 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { // Zoom-in clamping { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); - float page_scale_delta = 10.f; + float page_scale_delta = 10; - host_impl_->ScrollBegin(BeginState(gfx::Point(50, 50)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(50, 50), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(gfx::Point(50, 50), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2734,7 +2856,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { // Zoom-out clamping { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); scroll_layer->layer_tree_impl() @@ -2746,12 +2868,12 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { scroll_layer->element_id(), gfx::ScrollOffset(50, 50)); float page_scale_delta = 0.1f; - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2762,7 +2884,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { // Two-finger panning should not happen based on pinch events only { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); scroll_layer->layer_tree_impl() @@ -2773,14 +2895,15 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { ->scroll_tree.UpdateScrollOffsetBaseForTesting( scroll_layer->element_id(), gfx::ScrollOffset(20, 20)); - float page_scale_delta = 1.f; - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::TOUCHSCREEN); + float page_scale_delta = 1; + host_impl_->ScrollBegin( + BeginState(gfx::Point(10, 10), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20)); host_impl_->PinchGestureEnd(gfx::Point(20, 20), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2790,7 +2913,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { // Two-finger panning should work with interleaved scroll events { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); scroll_layer->layer_tree_impl() @@ -2801,16 +2924,17 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { ->scroll_tree.UpdateScrollOffsetBaseForTesting( scroll_layer->element_id(), gfx::ScrollOffset(20, 20)); - float page_scale_delta = 1.f; - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::TOUCHSCREEN); + float page_scale_delta = 1; + host_impl_->ScrollBegin( + BeginState(gfx::Point(10, 10), gfx::Vector2dF(-10, -10)).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); host_impl_->ScrollBy( UpdateState(gfx::Point(10, 10), gfx::Vector2d(-10, -10)).get()); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20)); host_impl_->PinchGestureEnd(gfx::Point(20, 20), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2821,7 +2945,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { // Two-finger panning should work when starting fully zoomed out. { - host_impl_->active_tree()->PushPageScaleFromMainThread(0.5f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(0.5f, 0.5f, 4); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); scroll_layer->layer_tree_impl() ->property_trees() @@ -2831,24 +2955,25 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { ->scroll_tree.UpdateScrollOffsetBaseForTesting( scroll_layer->element_id(), gfx::ScrollOffset(0, 0)); - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); - host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0)); - host_impl_->PinchGestureUpdate(1.f, gfx::Point(0, 0)); + host_impl_->PinchGestureUpdate(2, gfx::Point(0, 0)); + host_impl_->PinchGestureUpdate(1, gfx::Point(0, 0)); // Needed so layer transform includes page scale. DrawFrame(); host_impl_->ScrollBy( UpdateState(gfx::Point(0, 0), gfx::Vector2d(10, 10)).get()); - host_impl_->PinchGestureUpdate(1.f, gfx::Point(10, 10)); + host_impl_->PinchGestureUpdate(1, gfx::Point(10, 10)); host_impl_->PinchGestureEnd(gfx::Point(10, 10), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_EQ(scroll_info->page_scale_delta, 2.f); + EXPECT_EQ(scroll_info->page_scale_delta, 2); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->element_id(), gfx::ScrollOffset(10, 10))); } @@ -2861,10 +2986,10 @@ TEST_F(LayerTreeHostImplTest, SyncSubpixelScrollDelta) { LayerImpl* scroll_layer = InnerViewportScrollLayer(); DCHECK(scroll_layer); - float min_page_scale = 1.f; - float max_page_scale = 4.f; + float min_page_scale = 1; + float max_page_scale = 4; - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); scroll_layer->layer_tree_impl() @@ -2875,16 +3000,17 @@ TEST_F(LayerTreeHostImplTest, SyncSubpixelScrollDelta) { ->scroll_tree.UpdateScrollOffsetBaseForTesting(scroll_layer->element_id(), gfx::ScrollOffset(0, 20)); - float page_scale_delta = 1.f; - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::TOUCHSCREEN); + float page_scale_delta = 1; + host_impl_->ScrollBegin( + BeginState(gfx::Point(10, 10), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); host_impl_->ScrollBy( UpdateState(gfx::Point(10, 10), gfx::Vector2dF(0, -1.001f)).get()); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 9)); host_impl_->PinchGestureEnd(gfx::Point(10, 9), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -2896,7 +3022,7 @@ TEST_F(LayerTreeHostImplTest, SyncSubpixelScrollDelta) { // scroll layer. draw_property_utils::ComputeTransforms( &scroll_layer->layer_tree_impl()->property_trees()->transform_tree); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, -19.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, -19), scroll_layer->ScreenSpaceTransform().To2dTranslation()); } @@ -2916,11 +3042,12 @@ TEST_F(LayerTreeHostImplTest, SyncSubpixelScrollFromFractionalActiveBase) { ->scroll_tree.UpdateScrollOffsetBaseForTesting( scroll_layer->element_id(), gfx::ScrollOffset(0, 20.5f)); - host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(10, 10), gfx::Vector2dF(0, -1)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy( UpdateState(gfx::Point(10, 10), gfx::Vector2dF(0, -1)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); gfx::ScrollOffset active_base = host_impl_->active_tree() @@ -2939,8 +3066,8 @@ TEST_F(LayerTreeHostImplTest, PinchZoomTriggersPageScaleAnimation) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); DrawFrame(); - float min_page_scale = 1.f; - float max_page_scale = 4.f; + float min_page_scale = 1; + float max_page_scale = 4; float page_scale_delta = 1.04f; base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromSeconds(1); @@ -2953,7 +3080,7 @@ TEST_F(LayerTreeHostImplTest, PinchZoomTriggersPageScaleAnimation) { // Zoom animation if page_scale is < 1.05 * min_page_scale. { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); did_request_redraw_ = false; @@ -2998,7 +3125,7 @@ TEST_F(LayerTreeHostImplTest, PinchZoomTriggersPageScaleAnimation) { std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_EQ(scroll_info->page_scale_delta, 1.f); + EXPECT_EQ(scroll_info->page_scale_delta, 1); } start_time += base::TimeDelta::FromSeconds(10); @@ -3008,7 +3135,7 @@ TEST_F(LayerTreeHostImplTest, PinchZoomTriggersPageScaleAnimation) { // No zoom animation if page_scale is >= 1.05 * min_page_scale. { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); did_request_redraw_ = false; @@ -3065,7 +3192,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { DCHECK(scroll_layer); float min_page_scale = 0.5f; - float max_page_scale = 4.f; + float max_page_scale = 4; base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromSeconds(1); base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100); @@ -3077,7 +3204,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { // Non-anchor zoom-in { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); scroll_layer->layer_tree_impl() ->property_trees() @@ -3088,7 +3215,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { did_request_next_frame_ = false; host_impl_->active_tree()->SetPendingPageScaleAnimation( std::unique_ptr<PendingPageScaleAnimation>( - new PendingPageScaleAnimation(gfx::Vector2d(), false, 2.f, + new PendingPageScaleAnimation(gfx::Vector2d(), false, 2, duration))); host_impl_->ActivateSyncTree(); EXPECT_FALSE(did_request_redraw_); @@ -3138,7 +3265,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { // Anchor zoom-out { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); scroll_layer->layer_tree_impl() ->property_trees() @@ -3194,7 +3321,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { DCHECK(scroll_layer); float min_page_scale = 0.5f; - float max_page_scale = 4.f; + float max_page_scale = 4; base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromSeconds(1); base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100); @@ -3206,7 +3333,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { // Anchor zoom with unchanged page scale should not change scroll or scale. { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + host_impl_->active_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); scroll_layer->layer_tree_impl() ->property_trees() @@ -3215,8 +3342,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { host_impl_->active_tree()->SetPendingPageScaleAnimation( std::unique_ptr<PendingPageScaleAnimation>( - new PendingPageScaleAnimation(gfx::Vector2d(), true, 1.f, - duration))); + new PendingPageScaleAnimation(gfx::Vector2d(), true, 1, duration))); host_impl_->ActivateSyncTree(); begin_frame_args.frame_time = start_time; begin_frame_args.sequence_number++; @@ -3247,7 +3373,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { CreatePendingTree(); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 1); SetupViewportLayers(host_impl_->pending_tree(), gfx::Size(50, 50), gfx::Size(100, 100), gfx::Size(100, 100)); host_impl_->ActivateSyncTree(); @@ -3257,8 +3383,8 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { DCHECK(scroll_layer); float min_page_scale = 0.5f; - float max_page_scale = 4.f; - host_impl_->sync_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, + float max_page_scale = 4; + host_impl_->sync_tree()->PushPageScaleFromMainThread(1, min_page_scale, max_page_scale); host_impl_->ActivateSyncTree(); @@ -3268,7 +3394,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { base::TimeTicks third_through_animation = start_time + duration / 3; base::TimeTicks halfway_through_animation = start_time + duration / 2; base::TimeTicks end_time = start_time + duration; - float target_scale = 2.f; + float target_scale = 2; viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); @@ -3385,7 +3511,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) { viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree.UpdateScrollOffsetBaseForTesting(scroll_layer->element_id(), @@ -3393,8 +3519,8 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) { did_complete_page_scale_animation_ = false; host_impl_->active_tree()->SetPendingPageScaleAnimation( - std::unique_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( - gfx::Vector2d(), false, 2.f, duration))); + std::unique_ptr<PendingPageScaleAnimation>( + new PendingPageScaleAnimation(gfx::Vector2d(), false, 2, duration))); host_impl_->ActivateSyncTree(); begin_frame_args.frame_time = start_time; begin_frame_args.sequence_number++; @@ -3420,7 +3546,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) { TEST_F(LayerTreeHostImplTest, MaxScrollOffsetAffectedByViewportBoundsDelta) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); DrawFrame(); LayerImpl* inner_scroll = InnerViewportScrollLayer(); @@ -3428,10 +3554,8 @@ TEST_F(LayerTreeHostImplTest, MaxScrollOffsetAffectedByViewportBoundsDelta) { EXPECT_EQ(gfx::ScrollOffset(50, 50), inner_scroll->MaxScrollOffset()); PropertyTrees* property_trees = host_impl_->active_tree()->property_trees(); - property_trees->SetInnerViewportContainerBoundsDelta( - gfx::Vector2dF(15.f, 15.f)); - property_trees->SetOuterViewportContainerBoundsDelta( - gfx::Vector2dF(7.f, 7.f)); + property_trees->SetInnerViewportContainerBoundsDelta(gfx::Vector2dF(15, 15)); + property_trees->SetOuterViewportContainerBoundsDelta(gfx::Vector2dF(7, 7)); EXPECT_EQ(gfx::ScrollOffset(42, 42), inner_scroll->MaxScrollOffset()); property_trees->SetInnerViewportContainerBoundsDelta(gfx::Vector2dF()); @@ -3440,8 +3564,7 @@ TEST_F(LayerTreeHostImplTest, MaxScrollOffsetAffectedByViewportBoundsDelta) { GetScrollNode(inner_scroll)->bounds = inner_scroll->bounds(); DrawFrame(); - property_trees->SetOuterViewportContainerBoundsDelta( - gfx::Vector2dF(60.f, 60.f)); + property_trees->SetOuterViewportContainerBoundsDelta(gfx::Vector2dF(60, 60)); EXPECT_EQ(gfx::ScrollOffset(10, 10), inner_scroll->MaxScrollOffset()); } @@ -3495,7 +3618,7 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { host_impl_->InitializeFrameSink(layer_tree_frame_sink_.get()); SetupViewportLayersInnerScrolls(viewport_size, content_size); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 4); auto* scrollbar = AddLayer<SolidColorScrollbarLayerImpl>( host_impl_->active_tree(), VERTICAL, 10, 0, false); @@ -3544,9 +3667,9 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { } // If no scroll happened during a scroll gesture, it should have no effect. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::WHEEL); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); @@ -3554,10 +3677,10 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { // For Aura Overlay Scrollbar, if no scroll happened during a scroll // gesture, shows scrollbars and schedules a delay fade out. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 0)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); if (animator == LayerTreeSettings::AURA_OVERLAY) { @@ -3586,8 +3709,9 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { // After a scroll, a scrollbar animation should be scheduled about 20ms from // now. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 5)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 5)).get()); EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); @@ -3601,7 +3725,7 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { EXPECT_TRUE(animation_task_.is_null()); } - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); if (expecting_animations) { @@ -3662,7 +3786,7 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { EXPECT_TRUE(animation_task_.is_null()); // Changing page scale triggers scrollbar animation. - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 4); host_impl_->active_tree()->SetPageScaleOnActiveTree(1.1f); EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); @@ -3716,7 +3840,7 @@ class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest { SetupScrollbarLayer(scroll, scrollbar); scrollbar->SetOffsetToTransformParent(gfx::Vector2dF(90, 0)); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 1); UpdateDrawProperties(host_impl_->pending_tree()); host_impl_->ActivateSyncTree(); @@ -3734,10 +3858,11 @@ class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest { EXPECT_EQ(nullptr, host_impl_->ScrollbarAnimationControllerForElementId( scroll->element_id())); } - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 5)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 5)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); CreatePendingTree(); // To test the case where the effect tree index of scrollbar layer changes, @@ -3756,22 +3881,22 @@ class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest { EffectNode* pending_tree_node = GetEffectNode(pending_scrollbar_layer); if (expecting_animations) { - EXPECT_FLOAT_EQ(1.f, active_tree_node->opacity); - EXPECT_FLOAT_EQ(1.f, active_scrollbar_layer->Opacity()); + EXPECT_FLOAT_EQ(1, active_tree_node->opacity); + EXPECT_FLOAT_EQ(1, active_scrollbar_layer->Opacity()); } else { - EXPECT_FLOAT_EQ(0.f, active_tree_node->opacity); - EXPECT_FLOAT_EQ(0.f, active_scrollbar_layer->Opacity()); + EXPECT_FLOAT_EQ(0, active_tree_node->opacity); + EXPECT_FLOAT_EQ(0, active_scrollbar_layer->Opacity()); } - EXPECT_FLOAT_EQ(0.f, pending_tree_node->opacity); + EXPECT_FLOAT_EQ(0, pending_tree_node->opacity); host_impl_->ActivateSyncTree(); active_tree_node = GetEffectNode(active_scrollbar_layer); if (expecting_animations) { - EXPECT_FLOAT_EQ(1.f, active_tree_node->opacity); - EXPECT_FLOAT_EQ(1.f, active_scrollbar_layer->Opacity()); + EXPECT_FLOAT_EQ(1, active_tree_node->opacity); + EXPECT_FLOAT_EQ(1, active_scrollbar_layer->Opacity()); } else { - EXPECT_FLOAT_EQ(0.f, active_tree_node->opacity); - EXPECT_FLOAT_EQ(0.f, active_scrollbar_layer->Opacity()); + EXPECT_FLOAT_EQ(0, active_tree_node->opacity); + EXPECT_FLOAT_EQ(0, active_scrollbar_layer->Opacity()); } } }; @@ -3832,8 +3957,8 @@ class LayerTreeHostImplTestMultiScrollable : public LayerTreeHostImplTest { } void ResetScrollbars() { - GetEffectNode(scrollbar_1_)->opacity = 0.f; - GetEffectNode(scrollbar_2_)->opacity = 0.f; + GetEffectNode(scrollbar_1_)->opacity = 0; + GetEffectNode(scrollbar_2_)->opacity = 0; UpdateDrawProperties(host_impl_->active_tree()); if (is_aura_scrollbar_) @@ -3855,15 +3980,16 @@ TEST_F(LayerTreeHostImplTestMultiScrollable, SetUpLayers(settings); - EXPECT_EQ(scrollbar_1_->Opacity(), 0.f); - EXPECT_EQ(scrollbar_2_->Opacity(), 0.f); + EXPECT_EQ(scrollbar_1_->Opacity(), 0); + EXPECT_EQ(scrollbar_2_->Opacity(), 0); // Scroll on root should flash all scrollbars. - host_impl_->RootScrollBegin(BeginState(gfx::Point(20, 20)).get(), - InputHandler::WHEEL); + host_impl_->RootScrollBegin( + BeginState(gfx::Point(20, 20), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy( UpdateState(gfx::Point(20, 20), gfx::Vector2d(0, 10)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_TRUE(scrollbar_1_->Opacity()); EXPECT_TRUE(scrollbar_2_->Opacity()); @@ -3872,9 +3998,10 @@ TEST_F(LayerTreeHostImplTestMultiScrollable, ResetScrollbars(); // Scroll on child should flash all scrollbars. - host_impl_->ScrollAnimatedBegin(BeginState(gfx::Point(70, 70)).get()); + host_impl_->ScrollAnimatedBegin( + BeginState(gfx::Point(70, 70), gfx::Vector2dF(0, 100)).get()); host_impl_->ScrollAnimated(gfx::Point(70, 70), gfx::Vector2d(0, 100)); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_TRUE(scrollbar_1_->Opacity()); EXPECT_TRUE(scrollbar_2_->Opacity()); @@ -3891,8 +4018,8 @@ TEST_F(LayerTreeHostImplTestMultiScrollable, ScrollbarFlashWhenMouseEnter) { SetUpLayers(settings); - EXPECT_EQ(scrollbar_1_->Opacity(), 0.f); - EXPECT_EQ(scrollbar_2_->Opacity(), 0.f); + EXPECT_EQ(scrollbar_1_->Opacity(), 0); + EXPECT_EQ(scrollbar_2_->Opacity(), 0); // Scroll should flash when mouse enter. host_impl_->MouseMoveAt(gfx::Point(1, 1)); @@ -3951,14 +4078,16 @@ TEST_F(LayerTreeHostImplTest, ScrollHitTestOnScrollbar) { // Wheel scroll on root scrollbar should process on impl thread. { InputHandler::ScrollStatus status = host_impl_->RootScrollBegin( - BeginState(gfx::Point(1, 1)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(1, 1), gfx::Vector2dF()).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); } // Touch scroll on root scrollbar should process on main thread. { InputHandler::ScrollStatus status = host_impl_->RootScrollBegin( - BeginState(gfx::Point(1, 1)).get(), InputHandler::TOUCHSCREEN); + BeginState(gfx::Point(1, 1), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling, status.main_thread_scrolling_reasons); @@ -3967,7 +4096,8 @@ TEST_F(LayerTreeHostImplTest, ScrollHitTestOnScrollbar) { // Wheel scroll on scrollbar should process on impl thread. { InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(51, 51)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(51, 51), gfx::Vector2dF()).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -3976,7 +4106,8 @@ TEST_F(LayerTreeHostImplTest, ScrollHitTestOnScrollbar) { // Touch scroll on scrollbar should process on main thread. { InputHandler::ScrollStatus status = host_impl_->RootScrollBegin( - BeginState(gfx::Point(51, 51)).get(), InputHandler::TOUCHSCREEN); + BeginState(gfx::Point(51, 51), gfx::Vector2dF()).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling, status.main_thread_scrolling_reasons); @@ -4002,7 +4133,7 @@ TEST_F(LayerTreeHostImplTest, ScrollbarVisibilityChangeCausesRedrawAndCommit) { SetupScrollbarLayer(scroll, scrollbar); scrollbar->SetOffsetToTransformParent(gfx::Vector2dF(90, 0)); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 1); host_impl_->ActivateSyncTree(); ScrollbarAnimationController* scrollbar_controller = @@ -4121,9 +4252,11 @@ TEST_F(LayerTreeHostImplTest, ScrollbarRegistration) { // Scrolling the viewport should result in a scrollbar animation update. animation_task_.Reset(); - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(10, 10)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(10, 10)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(animation_task_.is_null()); animation_task_.Reset(); @@ -4203,18 +4336,22 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeMouseMove) { EXPECT_FALSE(scrollbar_controller->MouseIsNearScrollbarThumb(VERTICAL)); // Scroll the page down which moves the thumb down. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 100)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 100)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Move the mouse near the thumb in the top position. host_impl_->MouseMoveAt(near_thumb_at_top); EXPECT_FALSE(scrollbar_controller->MouseIsNearScrollbarThumb(VERTICAL)); // Scroll the page up which moves the thumb back up. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL); + host_impl_->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, -100)).get(), + InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, -100)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Move the mouse near the thumb in the top position. host_impl_->MouseMoveAt(near_thumb_at_top); @@ -4292,11 +4429,11 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( } TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf1) { - SetupMouseMoveAtWithDeviceScale(1.f); + SetupMouseMoveAtWithDeviceScale(1); } TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf2) { - SetupMouseMoveAtWithDeviceScale(2.f); + SetupMouseMoveAtWithDeviceScale(2); } // This test verifies that only SurfaceLayers in the viewport and have fallbacks @@ -4323,7 +4460,7 @@ TEST_F(LayerTreeHostImplTest, ActivationDependenciesInMetadata) { child->SetRange( viz::SurfaceRange(fallback_surfaces[i], primary_surfaces[i]), 2u); CopyProperties(root, child); - child->SetOffsetToTransformParent(gfx::Vector2dF(25.f * i, 0.f)); + child->SetOffsetToTransformParent(gfx::Vector2dF(25.0f * i, 0)); } base::flat_set<viz::SurfaceRange> surfaces_set; @@ -4415,14 +4552,14 @@ TEST_F(LayerTreeHostImplTest, SurfaceReferencesChangeCausesDamage) { TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); DrawFrame(); { viz::CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); EXPECT_EQ(gfx::Vector2dF(), metadata.root_scroll_offset); - EXPECT_EQ(1.f, metadata.page_scale_factor); - EXPECT_EQ(gfx::SizeF(50.f, 50.f), metadata.scrollable_viewport_size); + EXPECT_EQ(1, metadata.page_scale_factor); + EXPECT_EQ(gfx::SizeF(50, 50), metadata.scrollable_viewport_size); EXPECT_EQ(0.5f, metadata.min_page_scale_factor); } @@ -4430,46 +4567,47 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); { viz::CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); } - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); { viz::CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); } // Page scale should update metadata correctly (shrinking only the viewport). - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); - host_impl_->PinchGestureUpdate(2.f, gfx::Point()); + host_impl_->PinchGestureUpdate(2, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); { viz::CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); - EXPECT_EQ(2.f, metadata.page_scale_factor); - EXPECT_EQ(gfx::SizeF(25.f, 25.f), metadata.scrollable_viewport_size); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); + EXPECT_EQ(2, metadata.page_scale_factor); + EXPECT_EQ(gfx::SizeF(25, 25), metadata.scrollable_viewport_size); EXPECT_EQ(0.5f, metadata.min_page_scale_factor); } // Likewise if set from the main thread. host_impl_->ProcessScrollDeltas(); - host_impl_->active_tree()->PushPageScaleFromMainThread(4.f, 0.5f, 4.f); - host_impl_->active_tree()->SetPageScaleOnActiveTree(4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(4, 0.5f, 4); + host_impl_->active_tree()->SetPageScaleOnActiveTree(4); { viz::CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); - EXPECT_EQ(4.f, metadata.page_scale_factor); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); + EXPECT_EQ(4, metadata.page_scale_factor); EXPECT_EQ(gfx::SizeF(12.5f, 12.5f), metadata.scrollable_viewport_size); EXPECT_EQ(0.5f, metadata.min_page_scale_factor); } @@ -4549,6 +4687,9 @@ TEST_F(LayerTreeHostImplTest, DamageShouldNotCareAboutContributingLayers) { { TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); EXPECT_FALSE(frame.has_no_damage); @@ -4559,12 +4700,13 @@ TEST_F(LayerTreeHostImplTest, DamageShouldNotCareAboutContributingLayers) { EXPECT_NE(total_quad_count, 0u); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } // Stops the child layer from drawing. We should have damage from this but // should not have any quads. This should clear the damaged area. layer->SetDrawsContent(false); - GetEffectNode(root)->opacity = 0.f; + GetEffectNode(root)->opacity = 0; UpdateDrawProperties(host_impl_->active_tree()); // The background is default to transparent. If the background is opaque, we @@ -4574,6 +4716,9 @@ TEST_F(LayerTreeHostImplTest, DamageShouldNotCareAboutContributingLayers) { { TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); EXPECT_FALSE(frame.has_no_damage); @@ -4584,12 +4729,16 @@ TEST_F(LayerTreeHostImplTest, DamageShouldNotCareAboutContributingLayers) { EXPECT_EQ(total_quad_count, 0u); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } // Now tries to draw again. Nothing changes, so should have no damage, no // render pass, and no quad. { TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); EXPECT_TRUE(frame.has_no_damage); @@ -4600,6 +4749,7 @@ TEST_F(LayerTreeHostImplTest, DamageShouldNotCareAboutContributingLayers) { EXPECT_EQ(total_quad_count, 0u); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } } @@ -4636,7 +4786,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) { layer->SetBounds(gfx::Size(10, 10)); CopyProperties(root, layer); // Ensure visible_layer_rect for layer is not empty - layer->SetOffsetToTransformParent(gfx::Vector2dF(100.f, 100.f)); + layer->SetOffsetToTransformParent(gfx::Vector2dF(100, 100)); UpdateDrawProperties(host_impl_->active_tree()); EXPECT_FALSE(layer->will_draw_returned_true()); @@ -4893,9 +5043,13 @@ TEST_F(LayerTreeHostImplPrepareToDrawTest, PrepareToDrawSucceedsAndFails) { host_impl_->SetRequiresHighResToDraw(); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } } @@ -4959,7 +5113,8 @@ TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) { // Scroll event is ignored because layer is not scrollable. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, status.main_thread_scrolling_reasons); @@ -4969,7 +5124,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) { TEST_F(LayerTreeHostImplTest, ClampingAfterActivation) { CreatePendingTree(); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 1); SetupViewportLayers(host_impl_->pending_tree(), gfx::Size(50, 50), gfx::Size(100, 100), gfx::Size(100, 100)); host_impl_->ActivateSyncTree(); @@ -5005,8 +5160,9 @@ class LayerTreeHostImplBrowserControlsTest : public LayerTreeHostImplTest { bool init = LayerTreeHostImplTest::CreateHostImpl( settings, std::move(layer_tree_frame_sink)); if (init) { - host_impl_->active_tree()->SetTopControlsHeight(top_controls_height_); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f); + host_impl_->active_tree()->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, false}); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f, 1.f); host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); } return init; @@ -5027,9 +5183,9 @@ class LayerTreeHostImplBrowserControlsTest : public LayerTreeHostImplTest { const gfx::Size& inner_viewport_size, const gfx::Size& outer_viewport_size, const gfx::Size& scroll_layer_size) { - tree_impl->set_browser_controls_shrink_blink_size(true); - tree_impl->SetTopControlsHeight(top_controls_height_); - tree_impl->SetCurrentBrowserControlsShownRatio(1.f); + tree_impl->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, true}); + tree_impl->SetCurrentBrowserControlsShownRatio(1.f, 1.f); tree_impl->PushPageScaleFromMainThread(1.f, 1.f, 1.f); host_impl_->DidChangeBrowserControlsPosition(); @@ -5050,7 +5206,7 @@ class LayerTreeHostImplBrowserControlsTest : public LayerTreeHostImplTest { auto* tree = host_impl_->active_tree(); \ auto* property_trees = tree->property_trees(); \ EXPECT_EQ(expected_browser_controls_shown_ratio, \ - tree->CurrentBrowserControlsShownRatio()); \ + tree->CurrentTopControlsShownRatio()); \ EXPECT_EQ( \ tree->top_controls_height() * expected_browser_controls_shown_ratio, \ host_impl_->browser_controls_manager()->ContentTopOffset()); \ @@ -5087,32 +5243,33 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, EXPECT_VIEWPORT_GEOMETRIES(1); EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize()); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25)).get(), + InputHandler::TOUCHSCREEN) + .thread); host_impl_->browser_controls_manager()->ScrollBegin(); // Hide the browser controls by a bit, the scrollable size should increase but // the actual content bounds shouldn't. - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 25)); EXPECT_VIEWPORT_GEOMETRIES(0.5f); EXPECT_EQ(gfx::SizeF(50, 75), active_tree->ScrollableSize()); // Fully hide the browser controls. - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 25)); EXPECT_VIEWPORT_GEOMETRIES(0); EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); // Scrolling additionally shouldn't have any effect. - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 25)); EXPECT_VIEWPORT_GEOMETRIES(0); EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); host_impl_->browser_controls_manager()->ScrollEnd(); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } // Ensure that moving the browser controls (i.e. omnibox/url-bar on mobile) on @@ -5133,7 +5290,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, LayerImpl* content = AddLayer(); content->SetBounds(gfx::Size(100, 100)); CopyProperties(OuterViewportScrollLayer(), content); - active_tree->PushPageScaleFromMainThread(0.5f, 0.5f, 4.f); + active_tree->PushPageScaleFromMainThread(0.5f, 0.5f, 4); DrawFrame(); @@ -5142,21 +5299,22 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, EXPECT_VIEWPORT_GEOMETRIES(1.0f); EXPECT_EQ(gfx::SizeF(200, 1000), active_tree->ScrollableSize()); - ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + ASSERT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25)).get(), + InputHandler::TOUCHSCREEN) + .thread); // Hide the browser controls by 25px. The outer clip should expand by 50px as // because the outer viewport is sized based on the minimum scale, in this // case 0.5. Therefore, changes to the outer viewport need to be divided by // the minimum scale as well. host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(0.f, 25.f)).get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(0, 25)).get()); EXPECT_VIEWPORT_GEOMETRIES(0.5f); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } // Tests that browser controls affect the position of horizontal scrollbars. @@ -5189,18 +5347,19 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds()); EXPECT_EQ(gfx::Rect(20, 0, 10, 3), scrollbar_layer->ComputeThumbQuadRect()); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25)).get(), + InputHandler::TOUCHSCREEN) + .thread); host_impl_->browser_controls_manager()->ScrollBegin(); // Hide the browser controls by a bit, the scrollable size should increase but // the actual content bounds shouldn't. { - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 25)); host_impl_->active_tree()->UpdateScrollbarGeometries(); EXPECT_VIEWPORT_GEOMETRIES(0.5f); EXPECT_EQ(gfx::SizeF(50, 75), active_tree->ScrollableSize()); @@ -5211,7 +5370,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // Fully hide the browser controls. { - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 25)); host_impl_->active_tree()->UpdateScrollbarGeometries(); EXPECT_VIEWPORT_GEOMETRIES(0); EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); @@ -5222,7 +5381,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // Additional scrolling shouldn't have any effect. { - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 25)); EXPECT_VIEWPORT_GEOMETRIES(0); EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds()); @@ -5231,7 +5390,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, } host_impl_->browser_controls_manager()->ScrollEnd(); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplBrowserControlsTest, @@ -5240,21 +5399,22 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10)); DrawFrame(); + gfx::Vector2dF top_controls_scroll_delta(0, 5.25f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(), top_controls_scroll_delta).get(), + InputHandler::TOUCHSCREEN) .thread); // Make the test scroll delta a fractional amount, to verify that the // fixed container size delta is (1) non-zero, and (2) fractional, and // (3) matches the movement of the browser controls. - gfx::Vector2dF top_controls_scroll_delta(0.f, 5.25f); host_impl_->browser_controls_manager()->ScrollBegin(); host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta); host_impl_->browser_controls_manager()->ScrollEnd(); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); auto* property_trees = host_impl_->active_tree()->property_trees(); EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(), property_trees->inner_viewport_container_bounds_delta().y()); @@ -5277,70 +5437,67 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // Need SetDrawsContent so ScrollBegin's hit test finds an actual layer. outer_scroll->SetDrawsContent(true); - host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(2, 1, 2); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); - host_impl_->ScrollBy( - UpdateState(gfx::Point(), gfx::Vector2dF(0.f, 50.f)).get()); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 50)).get(), + InputHandler::TOUCHSCREEN) + .thread); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 50)).get()); // The entire scroll delta should have been used to hide the browser controls. // The viewport layers should be resized back to their full sizes. - EXPECT_EQ(0.f, host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); - EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(0, host_impl_->active_tree()->CurrentTopControlsShownRatio()); + EXPECT_EQ(0, inner_scroll->CurrentScrollOffset().y()); EXPECT_EQ(100, inner_scroll->bounds().height()); EXPECT_EQ(100, outer_scroll->bounds().height()); // The inner viewport should be scrollable by 50px * page_scale. - host_impl_->ScrollBy( - UpdateState(gfx::Point(), gfx::Vector2dF(0.f, 100.f)).get()); - EXPECT_EQ(50.f, inner_scroll->CurrentScrollOffset().y()); - EXPECT_EQ(0.f, outer_scroll->CurrentScrollOffset().y()); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get()); + EXPECT_EQ(50, inner_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(0, outer_scroll->CurrentScrollOffset().y()); EXPECT_EQ(gfx::ScrollOffset(), outer_scroll->MaxScrollOffset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, -50)).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, outer_scroll->scroll_tree_index()); - host_impl_->ScrollBy( - UpdateState(gfx::Point(), gfx::Vector2dF(0.f, -50.f)).get()); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, -50)).get()); // The entire scroll delta should have been used to show the browser controls. // The outer viewport should be resized to accomodate and scrolled to the // bottom of the document to keep the viewport in place. - EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + EXPECT_EQ(1, host_impl_->active_tree()->CurrentTopControlsShownRatio()); EXPECT_EQ(50, inner_scroll->bounds().height()); EXPECT_EQ(100, outer_scroll->bounds().height()); - EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y()); - EXPECT_EQ(25.f, inner_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(25, outer_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(25, inner_scroll->CurrentScrollOffset().y()); // Now when we continue scrolling, make sure the outer viewport gets scrolled // since it wasn't scrollable when the scroll began. - host_impl_->ScrollBy( - UpdateState(gfx::Point(), gfx::Vector2dF(0.f, -20.f)).get()); - EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y()); - EXPECT_EQ(15.f, inner_scroll->CurrentScrollOffset().y()); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, -20)).get()); + EXPECT_EQ(25, outer_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(15, inner_scroll->CurrentScrollOffset().y()); - host_impl_->ScrollBy( - UpdateState(gfx::Point(), gfx::Vector2dF(0.f, -30.f)).get()); - EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y()); - EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y()); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, -30)).get()); + EXPECT_EQ(25, outer_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(0, inner_scroll->CurrentScrollOffset().y()); host_impl_->ScrollBy( - UpdateState(gfx::Point(), gfx::Vector2dF(0.f, -50.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(), gfx::Vector2dF(0.f, -50)).get()); + host_impl_->ScrollEnd(); - EXPECT_EQ(0.f, outer_scroll->CurrentScrollOffset().y()); - EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(0, outer_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(0, inner_scroll->CurrentScrollOffset().y()); } // Test that the fixed position container delta is appropriately adjusted @@ -5349,22 +5506,23 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) { SetupBrowserControlsAndScrollLayerWithVirtualViewport( gfx::Size(100, 100), gfx::Size(100, 100), gfx::Size(100, 100)); DrawFrame(); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); float page_scale = 1.5f; // Zoom in, since the fixed container is the outer viewport, the delta should // not be scaled. - host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1, 2); + gfx::Vector2dF top_controls_scroll_delta(0, 20); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(), top_controls_scroll_delta).get(), + InputHandler::TOUCHSCREEN) .thread); // Scroll down, the browser controls hiding should expand the viewport size so // the delta should be equal to the scroll distance. - gfx::Vector2dF top_controls_scroll_delta(0.f, 20.f); host_impl_->browser_controls_manager()->ScrollBegin(); host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta); EXPECT_FLOAT_EQ(top_controls_height_ - top_controls_scroll_delta.y(), @@ -5373,7 +5531,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) { auto* property_trees = host_impl_->active_tree()->property_trees(); EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(), property_trees->outer_viewport_container_bounds_delta().y()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Scroll past the maximum extent. The delta shouldn't be greater than the // browser controls height. @@ -5381,10 +5539,10 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) { host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta); host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta); host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, top_controls_height_), property_trees->outer_viewport_container_bounds_delta()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Scroll in the direction to make the browser controls show. host_impl_->browser_controls_manager()->ScrollBegin(); @@ -5410,17 +5568,15 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, BrowserControlsPushUnsentRatio) { LayerImpl* outer_scroll = OuterViewportScrollLayer(); outer_scroll->SetDrawsContent(true); - host_impl_->active_tree()->PushBrowserControlsFromMainThread(1); - ASSERT_EQ(1.0f, - host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + host_impl_->active_tree()->PushBrowserControlsFromMainThread(1, 1); + ASSERT_EQ(1.0f, host_impl_->active_tree()->CurrentTopControlsShownRatio()); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0.5f); - ASSERT_EQ(0.5f, - host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0.5f, 0.5f); + ASSERT_EQ(0.5f, host_impl_->active_tree()->CurrentTopControlsShownRatio()); - host_impl_->active_tree()->PushBrowserControlsFromMainThread(0); + host_impl_->active_tree()->PushBrowserControlsFromMainThread(0, 0); - ASSERT_EQ(0, host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + ASSERT_EQ(0, host_impl_->active_tree()->CurrentTopControlsShownRatio()); } // Test that if a scrollable sublayer doesn't consume the scroll, @@ -5434,7 +5590,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, DrawFrame(); // Show browser controls - EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + EXPECT_EQ(1, host_impl_->active_tree()->CurrentTopControlsShownRatio()); LayerImpl* outer_viewport_scroll_layer = OuterViewportScrollLayer(); LayerImpl* child = AddLayer(); @@ -5451,17 +5607,17 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, UpdateDrawProperties(host_impl_->active_tree()); // Scroll child to the limit. - SetScrollOffsetDelta(child, gfx::Vector2dF(0, 100.f)); + SetScrollOffsetDelta(child, gfx::Vector2dF(0, 100)); // Scroll 25px to hide browser controls - gfx::Vector2dF scroll_delta(0.f, 25.f); + gfx::Vector2dF scroll_delta(0, 25); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Browser controls should be hidden EXPECT_EQ(scroll_delta.y(), @@ -5478,19 +5634,19 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, layer_size_, layer_size_, layer_size_); DrawFrame(); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0.f); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0, 0); host_impl_->active_tree()->top_controls_shown_ratio()->PushMainToPending( - 30.f / top_controls_height_); + 30 / top_controls_height_); host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive(); - EXPECT_FLOAT_EQ(30.f, + EXPECT_FLOAT_EQ(30, host_impl_->browser_controls_manager()->ContentTopOffset()); - EXPECT_FLOAT_EQ(-20.f, + EXPECT_FLOAT_EQ(-20, host_impl_->browser_controls_manager()->ControlsTopOffset()); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0.f); - EXPECT_FLOAT_EQ(0.f, + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0, 0); + EXPECT_FLOAT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); - EXPECT_FLOAT_EQ(-50.f, + EXPECT_FLOAT_EQ(-50, host_impl_->browser_controls_manager()->ControlsTopOffset()); host_impl_->DidChangeBrowserControlsPosition(); @@ -5511,33 +5667,33 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // Changing SetCurrentBrowserControlsShownRatio is one way to cause the // pending tree to update it's viewport. - host_impl_->SetCurrentBrowserControlsShownRatio(0.f); + host_impl_->SetCurrentBrowserControlsShownRatio(0, 0); EXPECT_FLOAT_EQ(top_controls_height_, host_impl_->pending_tree() ->property_trees() ->inner_viewport_container_bounds_delta() .y()); - host_impl_->SetCurrentBrowserControlsShownRatio(0.5f); + host_impl_->SetCurrentBrowserControlsShownRatio(0.5f, 0.5f); EXPECT_FLOAT_EQ(0.5f * top_controls_height_, host_impl_->pending_tree() ->property_trees() ->inner_viewport_container_bounds_delta() .y()); - host_impl_->SetCurrentBrowserControlsShownRatio(1.f); - EXPECT_FLOAT_EQ(0.f, host_impl_->pending_tree() - ->property_trees() - ->inner_viewport_container_bounds_delta() - .y()); + host_impl_->SetCurrentBrowserControlsShownRatio(1, 1); + EXPECT_FLOAT_EQ(0, host_impl_->pending_tree() + ->property_trees() + ->inner_viewport_container_bounds_delta() + .y()); // Pushing changes from the main thread is the second way. These values are - // added to the 1.f set above. - host_impl_->pending_tree()->PushBrowserControlsFromMainThread(-0.5f); + // added to the 1 set above. + host_impl_->pending_tree()->PushBrowserControlsFromMainThread(-0.5f, -0.5f); EXPECT_FLOAT_EQ(0.5f * top_controls_height_, host_impl_->pending_tree() ->property_trees() ->inner_viewport_container_bounds_delta() .y()); - host_impl_->pending_tree()->PushBrowserControlsFromMainThread(-1.f); + host_impl_->pending_tree()->PushBrowserControlsFromMainThread(-1, -1); EXPECT_FLOAT_EQ(top_controls_height_, host_impl_->pending_tree() ->property_trees() @@ -5554,35 +5710,34 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, ApplyDeltaOnTreeActivation) { DrawFrame(); host_impl_->active_tree()->top_controls_shown_ratio()->PushMainToPending( - 20.f / top_controls_height_); + 20 / top_controls_height_); host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive(); host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio( - 15.f / top_controls_height_); + 15 / top_controls_height_, 15 / top_controls_height_); host_impl_->active_tree() ->top_controls_shown_ratio() ->PullDeltaForMainThread(); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0.f); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0, 0); host_impl_->sync_tree()->PushBrowserControlsFromMainThread( - 15.f / top_controls_height_); + 15 / top_controls_height_, 15 / top_controls_height_); host_impl_->DidChangeBrowserControlsPosition(); auto* property_trees = host_impl_->active_tree()->property_trees(); - EXPECT_EQ(gfx::Vector2dF(0.f, 50.f), + EXPECT_EQ(gfx::Vector2dF(0, 50), property_trees->inner_viewport_container_bounds_delta()); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); host_impl_->ActivateSyncTree(); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset()); - EXPECT_EQ(gfx::Vector2dF(0.f, 50.f), + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(gfx::Vector2dF(0, 50), property_trees->inner_viewport_container_bounds_delta()); EXPECT_FLOAT_EQ( - -15.f, host_impl_->active_tree()->top_controls_shown_ratio()->Delta() * - top_controls_height_); + -15, host_impl_->active_tree()->top_controls_shown_ratio()->Delta() * + top_controls_height_); EXPECT_FLOAT_EQ( - 15.f, - host_impl_->active_tree()->top_controls_shown_ratio()->ActiveBase() * - top_controls_height_); + 15, host_impl_->active_tree()->top_controls_shown_ratio()->ActiveBase() * + top_controls_height_); } // Test that changing the browser controls layout height is correctly applied to @@ -5595,22 +5750,23 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, layer_size_, layer_size_, layer_size_); DrawFrame(); - host_impl_->sync_tree()->PushBrowserControlsFromMainThread(1.f); - host_impl_->sync_tree()->set_browser_controls_shrink_blink_size(true); + host_impl_->sync_tree()->PushBrowserControlsFromMainThread(1, 1); + host_impl_->sync_tree()->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, true}); - host_impl_->active_tree()->top_controls_shown_ratio()->PushMainToPending(1.f); + host_impl_->active_tree()->top_controls_shown_ratio()->PushMainToPending(1); host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive(); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0.f); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(0, 0); host_impl_->DidChangeBrowserControlsPosition(); auto* property_trees = host_impl_->active_tree()->property_trees(); EXPECT_EQ(gfx::Vector2dF(0, 50), property_trees->inner_viewport_container_bounds_delta()); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); host_impl_->ActivateSyncTree(); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); // The total bounds should remain unchanged since the bounds delta should // account for the difference between the layout height and the current @@ -5618,13 +5774,12 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, EXPECT_EQ(gfx::Vector2dF(0, 50), property_trees->inner_viewport_container_bounds_delta()); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1, 1); host_impl_->DidChangeBrowserControlsPosition(); - EXPECT_EQ(1.f, - host_impl_->browser_controls_manager()->TopControlsShownRatio()); - EXPECT_EQ(50.f, host_impl_->browser_controls_manager()->TopControlsHeight()); - EXPECT_EQ(50.f, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(1, host_impl_->browser_controls_manager()->TopControlsShownRatio()); + EXPECT_EQ(50, host_impl_->browser_controls_manager()->TopControlsHeight()); + EXPECT_EQ(50, host_impl_->browser_controls_manager()->ContentTopOffset()); EXPECT_EQ(gfx::Vector2dF(), property_trees->inner_viewport_container_bounds_delta()); } @@ -5638,34 +5793,34 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400)); DrawFrame(); - EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + EXPECT_EQ(1, host_impl_->active_tree()->CurrentTopControlsShownRatio()); LayerImpl* outer_scroll = OuterViewportScrollLayer(); LayerImpl* inner_scroll = InnerViewportScrollLayer(); // Scroll the viewports to max scroll offset. - SetScrollOffsetDelta(outer_scroll, gfx::Vector2dF(0, 200.f)); - SetScrollOffsetDelta(inner_scroll, gfx::Vector2dF(100, 100.f)); + SetScrollOffsetDelta(outer_scroll, gfx::Vector2dF(0, 200)); + SetScrollOffsetDelta(inner_scroll, gfx::Vector2dF(100, 100)); gfx::ScrollOffset viewport_offset = host_impl_->active_tree()->TotalScrollOffset(); EXPECT_EQ(host_impl_->active_tree()->TotalMaxScrollOffset(), viewport_offset); // Hide the browser controls by 25px. - gfx::Vector2dF scroll_delta(0.f, 25.f); + gfx::Vector2dF scroll_delta(0, 25); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); // scrolling down at the max extents no longer hides the browser controls - EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + EXPECT_EQ(1, host_impl_->active_tree()->CurrentTopControlsShownRatio()); // forcefully hide the browser controls by 25px host_impl_->browser_controls_manager()->ScrollBy(scroll_delta); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FLOAT_EQ( scroll_delta.y(), @@ -5682,21 +5837,21 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, viewport_offset = host_impl_->active_tree()->TotalScrollOffset(); // Bring the browser controls down by 25px. - scroll_delta = gfx::Vector2dF(0.f, -25.f); + scroll_delta = gfx::Vector2dF(0, -25); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The viewport offset shouldn't have changed. EXPECT_EQ(viewport_offset, host_impl_->active_tree()->TotalScrollOffset()); // Scroll the viewports to max scroll offset. - SetScrollOffsetDelta(outer_scroll, gfx::Vector2dF(0, 200.f)); - SetScrollOffsetDelta(inner_scroll, gfx::Vector2dF(100, 100.f)); + SetScrollOffsetDelta(outer_scroll, gfx::Vector2dF(0, 200)); + SetScrollOffsetDelta(inner_scroll, gfx::Vector2dF(100, 100)); EXPECT_EQ(host_impl_->active_tree()->TotalMaxScrollOffset(), host_impl_->active_tree()->TotalScrollOffset()); } @@ -5706,20 +5861,20 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, TEST_F(LayerTreeHostImplBrowserControlsTest, BrowserControlsAspectRatio) { SetupBrowserControlsAndScrollLayerWithVirtualViewport( gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400)); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 2); DrawFrame(); EXPECT_FLOAT_EQ(top_controls_height_, host_impl_->browser_controls_manager()->ContentTopOffset()); - gfx::Vector2dF scroll_delta(0.f, 25.f); + gfx::Vector2dF scroll_delta(0, 25); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FLOAT_EQ( scroll_delta.y(), @@ -5750,27 +5905,27 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // Send a gesture scroll that will scroll the outer viewport, make sure the // browser controls get scrolled. - gfx::Vector2dF scroll_delta(0.f, 15.f); + gfx::Vector2dF scroll_delta(0, 15); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(OuterViewportScrollLayer()->scroll_tree_index(), host_impl_->CurrentlyScrollingNode()->id); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FLOAT_EQ( scroll_delta.y(), top_controls_height_ - host_impl_->browser_controls_manager()->ContentTopOffset()); - scroll_delta = gfx::Vector2dF(0.f, 50.f); + scroll_delta = gfx::Vector2dF(0, 50); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -5779,17 +5934,17 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, EXPECT_EQ(OuterViewportScrollLayer()->scroll_tree_index(), host_impl_->CurrentlyScrollingNode()->id); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Position the viewports such that the inner viewport will be scrolled. - gfx::Vector2dF inner_viewport_offset(0.f, 25.f); + gfx::Vector2dF inner_viewport_offset(0, 25); SetScrollOffsetDelta(OuterViewportScrollLayer(), gfx::Vector2dF()); SetScrollOffsetDelta(InnerViewportScrollLayer(), inner_viewport_offset); - scroll_delta = gfx::Vector2dF(0.f, -65.f); + scroll_delta = gfx::Vector2dF(0, -65); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -5800,7 +5955,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, inner_viewport_offset.y() + (scroll_delta.y() + top_controls_height_), ScrollDelta(InnerViewportScrollLayer()).y()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplBrowserControlsTest, @@ -5809,33 +5964,35 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, layer_size_, layer_size_, layer_size_); DrawFrame(); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 50)).get(), + InputHandler::TOUCHSCREEN) + .thread); host_impl_->browser_controls_manager()->ScrollBegin(); - host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f)); + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0, 50)); host_impl_->browser_controls_manager()->ScrollEnd(); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ContentTopOffset()); // Now that browser controls have moved, expect the clip to resize. auto* property_trees = host_impl_->active_tree()->property_trees(); EXPECT_EQ(gfx::Vector2dF(0, 50), property_trees->inner_viewport_container_bounds_delta()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, -25)).get(), + InputHandler::TOUCHSCREEN) + .thread); - float scroll_increment_y = -25.f; + float scroll_increment_y = -25; host_impl_->browser_controls_manager()->ScrollBegin(); host_impl_->browser_controls_manager()->ScrollBy( - gfx::Vector2dF(0.f, scroll_increment_y)); + gfx::Vector2dF(0, scroll_increment_y)); EXPECT_FLOAT_EQ(-scroll_increment_y, host_impl_->browser_controls_manager()->ContentTopOffset()); // Now that browser controls have moved, expect the clip to resize. @@ -5843,7 +6000,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, property_trees->inner_viewport_container_bounds_delta()); host_impl_->browser_controls_manager()->ScrollBy( - gfx::Vector2dF(0.f, scroll_increment_y)); + gfx::Vector2dF(0, scroll_increment_y)); host_impl_->browser_controls_manager()->ScrollEnd(); EXPECT_FLOAT_EQ(-2 * scroll_increment_y, host_impl_->browser_controls_manager()->ContentTopOffset()); @@ -5851,16 +6008,17 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, EXPECT_EQ(gfx::Vector2dF(), property_trees->inner_viewport_container_bounds_delta()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Verify the layer is once-again non-scrollable. EXPECT_EQ(gfx::ScrollOffset(), InnerViewportScrollLayer()->MaxScrollOffset()); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::TOUCHSCREEN) + .thread); } // Tests that activating a pending tree while there's a bounds_delta on the @@ -5878,25 +6036,28 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, { SetupBrowserControlsAndScrollLayerWithVirtualViewport( inner_viewport_size, outer_viewport_size, content_size); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 1); // Start off with the browser controls hidden on both main and impl. - host_impl_->active_tree()->set_browser_controls_shrink_blink_size(false); - host_impl_->active_tree()->PushBrowserControlsFromMainThread(0); + host_impl_->active_tree()->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, false}); + host_impl_->active_tree()->PushBrowserControlsFromMainThread(0, 0); CreatePendingTree(); SetupBrowserControlsAndScrollLayerWithVirtualViewport( host_impl_->pending_tree(), inner_viewport_size, outer_viewport_size, content_size); - host_impl_->pending_tree()->set_browser_controls_shrink_blink_size(false); + host_impl_->pending_tree()->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, false}); UpdateDrawProperties(host_impl_->pending_tree()); // Fully scroll the viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(75, 75), gfx::Vector2dF(0, 2000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 2000)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } LayerImpl* outer_scroll = OuterViewportScrollLayer(); @@ -5968,7 +6129,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, ASSERT_EQ(1050, outer_scroll->MaxScrollOffset().y()); // NEAR because clip layer bounds are truncated in MaxScrollOffset so we // lose some precision in the intermediate animation steps. - ASSERT_NEAR(1050, outer_scroll->CurrentScrollOffset().y(), 1.f); + ASSERT_NEAR(1050, outer_scroll->CurrentScrollOffset().y(), 1); } // Activate the pending tree which should have the same scroll value as the @@ -5982,7 +6143,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, // Make sure we don't accidentally clamp the outer offset based on a bounds // delta that hasn't yet been updated. - EXPECT_NEAR(1050, outer_scroll->CurrentScrollOffset().y(), 1.f); + EXPECT_NEAR(1050, outer_scroll->CurrentScrollOffset().y(), 1); } } @@ -6008,13 +6169,14 @@ TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) { DrawFrame(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); } @@ -6032,13 +6194,14 @@ TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) { DrawFrame(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); } @@ -6053,7 +6216,8 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesChild) { // Scroll event is ignored because the input coordinate is outside the layer // boundaries. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(15, 5)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(15, 5), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, status.main_thread_scrolling_reasons); @@ -6078,7 +6242,8 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) { // Scroll event is ignored because the scrollable layer is not facing the // viewer and there is nothing scrollable behind it. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer, status.main_thread_scrolling_reasons); @@ -6105,7 +6270,8 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) { // Scrolling fails because the content layer is asking to be scrolled on the // main thread. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL); + BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, status.main_thread_scrolling_reasons); @@ -6117,24 +6283,24 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { gfx::Size content_size(80, 80); SetupViewportLayers(host_impl_->active_tree(), inner_viewport_size, outer_viewport_size, content_size); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); DrawFrame(); gfx::Vector2d scroll_delta(0, 10); gfx::ScrollOffset expected_scroll_delta(scroll_delta); LayerImpl* outer_scroll = OuterViewportScrollLayer(); gfx::ScrollOffset expected_max_scroll = outer_scroll->MaxScrollOffset(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Set new page scale from main thread. - float page_scale = 2.f; - host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f); + float page_scale = 2; + host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1, 2); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6147,7 +6313,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { // The page scale delta remains constant because the impl thread did not // scale. - EXPECT_EQ(1.f, host_impl_->active_tree()->page_scale_delta()); + EXPECT_EQ(1, host_impl_->active_tree()->page_scale_delta()); } TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { @@ -6156,29 +6322,29 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { gfx::Size content_size(80, 80); SetupViewportLayers(host_impl_->active_tree(), inner_viewport_size, outer_viewport_size, content_size); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); DrawFrame(); gfx::Vector2d scroll_delta(0, 10); gfx::ScrollOffset expected_scroll_delta(scroll_delta); LayerImpl* outer_scroll = OuterViewportScrollLayer(); gfx::ScrollOffset expected_max_scroll = outer_scroll->MaxScrollOffset(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Set new page scale on impl thread by pinching. - float page_scale = 2.f; - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + float page_scale = 2; + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); DrawOneFrame(); @@ -6197,14 +6363,14 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { } TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 2); gfx::Size viewport_size(5, 5); gfx::Size surface_size(10, 10); - float default_page_scale = 1.f; + float default_page_scale = 1; gfx::Transform default_page_scale_matrix; default_page_scale_matrix.Scale(default_page_scale, default_page_scale); - float new_page_scale = 2.f; + float new_page_scale = 2; gfx::Transform new_page_scale_matrix; new_page_scale_matrix.Scale(new_page_scale, new_page_scale); @@ -6220,20 +6386,20 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { UpdateDrawProperties(host_impl_->active_tree()); // Set new page scale on impl thread by pinching. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); DrawOneFrame(); // Make sure all the layers are drawn with the page scale delta applied, i.e., // the page scale delta on the root layer is applied hierarchically. DrawFrame(); - EXPECT_EQ(1.f, root->DrawTransform().matrix().getDouble(0, 0)); - EXPECT_EQ(1.f, root->DrawTransform().matrix().getDouble(1, 1)); + EXPECT_EQ(1, root->DrawTransform().matrix().getDouble(0, 0)); + EXPECT_EQ(1, root->DrawTransform().matrix().getDouble(1, 1)); EXPECT_EQ(new_page_scale, inner_scroll->DrawTransform().matrix().getDouble(0, 0)); EXPECT_EQ(new_page_scale, @@ -6254,16 +6420,16 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { gfx::Vector2d scroll_delta(0, 10); gfx::ScrollOffset expected_scroll_delta(scroll_delta); gfx::ScrollOffset expected_max_scroll(outer_scroll->MaxScrollOffset()); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); - float page_scale = 2.f; - host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, + float page_scale = 2; + host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1, page_scale); DrawOneFrame(); @@ -6277,7 +6443,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { // The page scale delta remains constant because the impl thread did not // scale. - EXPECT_EQ(1.f, host_impl_->active_tree()->page_scale_delta()); + EXPECT_EQ(1, host_impl_->active_tree()->page_scale_delta()); } TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { @@ -6308,13 +6474,13 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { DrawFrame(); { gfx::Vector2d scroll_delta(-8, -7); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6445,11 +6611,11 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { gfx::Vector2d scroll_delta(0, -10); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6464,17 +6630,18 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { // The next time we scroll we should only scroll the parent. scroll_delta = gfx::Vector2d(0, -3); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, - grand_child_layer->scroll_tree_index()); + child_layer->scroll_tree_index()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, child_layer->scroll_tree_index()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6491,17 +6658,18 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { // After scrolling the parent, another scroll on the opposite direction // should still scroll the child. scroll_delta = gfx::Vector2d(0, 7); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, grand_child_layer->scroll_tree_index()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, grand_child_layer->scroll_tree_index()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6516,19 +6684,20 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { gfx::ScrollOffset(0, -3))); // Scrolling should be adjusted from viewport space. - host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 2.f, 2.f); - host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(2, 2, 2); + host_impl_->active_tree()->SetPageScaleOnActiveTree(2); scroll_delta = gfx::Vector2d(0, -2); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(1, 1), scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(grand_child_layer->scroll_tree_index(), host_impl_->CurrentlyScrollingNode()->id); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6559,15 +6728,18 @@ TEST_F(LayerTreeHostImplTest, ChildrenOfInnerScrollNodeCanScrollOnThread) { { gfx::ScrollOffset scroll_delta(0, 4); // Scrolling should be able to happen on the compositor thread here. - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), + gfx::ScrollOffsetToVector2dF(scroll_delta)) + .get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF(scroll_delta)) .get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6597,15 +6769,18 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { DrawFrame(); { gfx::ScrollOffset scroll_delta(0, 4); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), + gfx::ScrollOffsetToVector2dF(scroll_delta)) + .get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF(scroll_delta)) .get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); std::unique_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6632,11 +6807,12 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) { SetupViewportLayersNoScrolls(surface_size); // Scrolling should still work even though we did not draw yet. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) + .thread); } TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { @@ -6653,13 +6829,14 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { // Scroll to the right in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(10, 0); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gesture_scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The layer should have scrolled down in its local coordinates. std::unique_ptr<ScrollAndScaleSet> scroll_info = @@ -6671,15 +6848,18 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { // Reset and scroll down with the wheel. SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF()); gfx::ScrollOffset wheel_scroll_delta(0, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(), + gfx::ScrollOffsetToVector2dF(wheel_scroll_delta)) + .get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF( wheel_scroll_delta)) .get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The layer should have scrolled down in its local coordinates. scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6690,7 +6870,7 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); auto* scroll_layer = InnerViewportScrollLayer(); - float child_layer_angle = -20.f; + float child_layer_angle = -20; // Create a child layer that is rotated to a non-axis-aligned angle. // Only allow vertical scrolling. @@ -6709,7 +6889,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { // is a different size than the clip, so make sure the clip layer's origin // lines up over the child. clip_layer_transform_node.origin = gfx::Point3F( - clip_layer->bounds().width() * 0.5f, clip_layer->bounds().height(), 0.f); + clip_layer->bounds().width() * 0.5f, clip_layer->bounds().height(), 0); clip_layer_transform_node.local = rotate_transform; LayerImpl* child = @@ -6723,11 +6903,12 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { gfx::Vector2d gesture_scroll_delta(0, 10); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(1, 1), gesture_scroll_delta).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The child layer should have scrolled down in its local coordinates an // amount proportional to the angle between it and the input scroll delta. @@ -6749,11 +6930,12 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { gfx::Vector2d gesture_scroll_delta(10, 0); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(1, 1), gesture_scroll_delta).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The child layer should have scrolled down in its local coordinates an // amount proportional to the angle between it and the input scroll delta. @@ -6790,7 +6972,7 @@ TEST_F(LayerTreeHostImplTest, ScrollPerspectiveTransformedLayer) { // is a different size than the clip, so make sure the clip layer's origin // lines up over the child. clip_layer_transform_node.origin = gfx::Point3F( - clip_layer->bounds().width(), clip_layer->bounds().height(), 0.f); + clip_layer->bounds().width(), clip_layer->bounds().height(), 0); clip_layer_transform_node.local = perspective_transform; LayerImpl* child = AddScrollableLayer(clip_layer, clip_layer->bounds(), @@ -6826,8 +7008,11 @@ TEST_F(LayerTreeHostImplTest, ScrollPerspectiveTransformedLayer) { DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(viewport_point).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(viewport_point, gfx::ScrollOffsetToVector2dF( + gesture_scroll_deltas[i])) + .get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy( UpdateState(viewport_point, @@ -6835,7 +7020,7 @@ TEST_F(LayerTreeHostImplTest, ScrollPerspectiveTransformedLayer) { .get()); viewport_point += gfx::ScrollOffsetToFlooredVector2d(gesture_scroll_deltas[i]); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); scroll_info = host_impl_->ProcessScrollDeltas(); EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child->element_id(), @@ -6863,11 +7048,11 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { gfx::Vector2d scroll_delta(0, 10); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The layer should have scrolled down in its local coordinates, but half the // amount. @@ -6880,15 +7065,18 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { // Reset and scroll down with the wheel. SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF()); gfx::ScrollOffset wheel_scroll_delta(0, 10); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(), + gfx::ScrollOffsetToVector2dF(wheel_scroll_delta)) + .get(), + InputHandler::WHEEL) + .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::ScrollOffsetToVector2dF( wheel_scroll_delta)) .get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // It should apply the scale factor to the scroll delta for the wheel event. scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6905,7 +7093,7 @@ TEST_F(LayerTreeHostImplTest, ScrollViewportRounding) { UpdateDrawProperties(host_impl_->active_tree()); host_impl_->active_tree()->SetDeviceScaleFactor(scale); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); LayerImpl* inner_viewport_scroll_layer = InnerViewportScrollLayer(); EXPECT_EQ(gfx::ScrollOffset(0, 0), @@ -6920,7 +7108,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { host_impl_->BindToClient(&scroll_watcher); - gfx::Vector2dF initial_scroll_delta(10.f, 10.f); + gfx::Vector2dF initial_scroll_delta(10, 10); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree.UpdateScrollOffsetBaseForTesting(scroll_layer->element_id(), @@ -6938,48 +7126,48 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { // page_scale_factor and {min|max}_page_scale_factor being set. EXPECT_EQ(gfx::SizeF(100, 100), scroll_watcher.scrollable_size()); EXPECT_EQ(gfx::ScrollOffset(90, 80), scroll_watcher.max_scroll_offset()); - EXPECT_EQ(1.f, scroll_watcher.page_scale_factor()); - EXPECT_EQ(1.f, scroll_watcher.min_page_scale_factor()); - EXPECT_EQ(1.f, scroll_watcher.max_page_scale_factor()); + EXPECT_EQ(1, scroll_watcher.page_scale_factor()); + EXPECT_EQ(1, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(1, scroll_watcher.max_page_scale_factor()); // Put a page scale on the tree. - host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 0.5f, 4.f); - EXPECT_EQ(1.f, scroll_watcher.page_scale_factor()); - EXPECT_EQ(1.f, scroll_watcher.min_page_scale_factor()); - EXPECT_EQ(1.f, scroll_watcher.max_page_scale_factor()); + host_impl_->active_tree()->PushPageScaleFromMainThread(2, 0.5f, 4); + EXPECT_EQ(1, scroll_watcher.page_scale_factor()); + EXPECT_EQ(1, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(1, scroll_watcher.max_page_scale_factor()); // Activation will update the delegate. host_impl_->ActivateSyncTree(); - EXPECT_EQ(2.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(2, scroll_watcher.page_scale_factor()); EXPECT_EQ(.5f, scroll_watcher.min_page_scale_factor()); - EXPECT_EQ(4.f, scroll_watcher.max_page_scale_factor()); + EXPECT_EQ(4, scroll_watcher.max_page_scale_factor()); // Animating page scale can change the root offset, so it should update the // delegate. Also resets the page scale to 1 for the rest of the test. host_impl_->LayerTreeHostImpl::StartPageScaleAnimation( - gfx::Vector2d(0, 0), false, 1.f, base::TimeDelta()); + gfx::Vector2d(0, 0), false, 1, base::TimeDelta()); host_impl_->Animate(); - EXPECT_EQ(1.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(1, scroll_watcher.page_scale_factor()); EXPECT_EQ(.5f, scroll_watcher.min_page_scale_factor()); - EXPECT_EQ(4.f, scroll_watcher.max_page_scale_factor()); + EXPECT_EQ(4, scroll_watcher.max_page_scale_factor()); // The pinch gesture doesn't put the delegate into a state where the scroll // offset is outside of the scroll range. (this is verified by DCHECKs in the // delegate). - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); - host_impl_->PinchGestureUpdate(2.f, gfx::Point()); + host_impl_->PinchGestureUpdate(2, gfx::Point()); host_impl_->PinchGestureUpdate(.5f, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // Scrolling should be relative to the offset as given by the delegate. - gfx::Vector2dF scroll_delta(0.f, 10.f); - gfx::ScrollOffset current_offset(7.f, 8.f); + gfx::Vector2dF scroll_delta(0, 10); + gfx::ScrollOffset current_offset(7, 8); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); @@ -6988,12 +7176,12 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { EXPECT_EQ(ScrollOffsetWithDelta(current_offset, scroll_delta), scroll_watcher.last_set_scroll_offset()); - current_offset = gfx::ScrollOffset(42.f, 41.f); + current_offset = gfx::ScrollOffset(42, 41); host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_EQ(current_offset + gfx::ScrollOffset(scroll_delta), scroll_watcher.last_set_scroll_offset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); host_impl_->SetSynchronousInputHandlerRootScrollOffset(gfx::ScrollOffset()); // Forces a full tree synchronization and ensures that the scroll delegate @@ -7001,7 +7189,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { gfx::Size new_viewport_size(21, 12); gfx::Size new_content_size(42, 24); CreatePendingTree(); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 1); SetupViewportLayers(host_impl_->pending_tree(), new_viewport_size, new_content_size, new_content_size); host_impl_->ActivateSyncTree(); @@ -7030,20 +7218,24 @@ TEST_F(LayerTreeHostImplTest, // Draw first frame to clear any pending draws and check scroll. DrawFrame(); - CheckLayerScrollDelta(scroll_layer, gfx::Vector2dF(0.f, 0.f)); + CheckLayerScrollDelta(scroll_layer, gfx::Vector2dF(0, 0)); EXPECT_FALSE(host_impl_->active_tree()->needs_update_draw_properties()); // Set external scroll delta on delegate and notify LayerTreeHost. - gfx::ScrollOffset scroll_offset(10.f, 10.f); + gfx::ScrollOffset scroll_offset(10, 10); host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); - CheckLayerScrollDelta(scroll_layer, gfx::Vector2dF(0.f, 0.f)); + CheckLayerScrollDelta(scroll_layer, gfx::Vector2dF(0, 0)); EXPECT_TRUE(host_impl_->active_tree()->needs_update_draw_properties()); // Check scroll delta reflected in layer. TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); EXPECT_FALSE(frame.has_no_damage); CheckLayerScrollDelta(scroll_layer, gfx::ScrollOffsetToVector2dF(scroll_offset)); @@ -7070,7 +7262,7 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { // Ensure that the scroll offset is interpreted as a content offset so it // should be unaffected by the page scale factor. See // https://crbug.com/973771. - float page_scale_factor = 2.f; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, page_scale_factor, page_scale_factor); @@ -7080,7 +7272,7 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { GetScrollNode(inner_scroll)->user_scrollable_vertical = false; GetScrollNode(inner_scroll)->user_scrollable_horizontal = false; - gfx::ScrollOffset scroll_offset(25.f, 30.f); + gfx::ScrollOffset scroll_offset(25, 30); host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); EXPECT_VECTOR_EQ(gfx::ScrollOffset(), scroll_tree.current_scroll_offset(inner_element_id)); @@ -7102,9 +7294,9 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { GetScrollNode(outer_scroll)->user_scrollable_vertical = false; GetScrollNode(outer_scroll)->user_scrollable_horizontal = false; - gfx::ScrollOffset scroll_offset(120.f, 140.f); + gfx::ScrollOffset scroll_offset(120, 140); host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); - EXPECT_VECTOR_EQ(gfx::ScrollOffset(50.f, 50.f), + EXPECT_VECTOR_EQ(gfx::ScrollOffset(50, 50), scroll_tree.current_scroll_offset(inner_element_id)); EXPECT_VECTOR_EQ(gfx::ScrollOffset(), scroll_tree.current_scroll_offset(outer_element_id)); @@ -7126,7 +7318,7 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { GetScrollNode(outer_scroll)->user_scrollable_vertical = false; GetScrollNode(outer_scroll)->user_scrollable_horizontal = false; - gfx::ScrollOffset scroll_offset(60.f, 70.f); + gfx::ScrollOffset scroll_offset(60, 70); host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); EXPECT_VECTOR_EQ(gfx::ScrollOffset(), scroll_tree.current_scroll_offset(inner_element_id)); @@ -7147,11 +7339,11 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { ASSERT_FALSE(did_request_redraw_); GetScrollNode(outer_scroll)->user_scrollable_vertical = false; GetScrollNode(outer_scroll)->user_scrollable_horizontal = false; - SetScrollOffset(inner_scroll, gfx::ScrollOffset(50.f, 50.f)); + SetScrollOffset(inner_scroll, gfx::ScrollOffset(50, 50)); - gfx::ScrollOffset scroll_offset(60.f, 70.f); + gfx::ScrollOffset scroll_offset(60, 70); host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); - EXPECT_VECTOR_EQ(gfx::ScrollOffset(50.f, 50.f), + EXPECT_VECTOR_EQ(gfx::ScrollOffset(50, 50), scroll_tree.current_scroll_offset(inner_element_id)); EXPECT_VECTOR_EQ(gfx::ScrollOffset(), scroll_tree.current_scroll_offset(outer_element_id)); @@ -7168,7 +7360,7 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetNoViewportCrash) { auto* inner_scroll = InnerViewportScrollLayer(); ASSERT_FALSE(inner_scroll); - gfx::ScrollOffset scroll_offset(25.f, 30.f); + gfx::ScrollOffset scroll_offset(25, 30); host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); } @@ -7176,7 +7368,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) { InputHandlerScrollResult scroll_result; SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); DrawFrame(); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); @@ -7184,7 +7376,8 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); @@ -7297,7 +7490,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) { EXPECT_EQ(scroll_result.accumulated_root_overscroll, host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { @@ -7306,18 +7499,14 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { InputHandlerScrollResult scroll_result; gfx::Size scroll_container_size(5, 5); gfx::Size surface_size(10, 10); - LayerImpl* root_clip = SetupDefaultRootLayer(surface_size); - LayerImpl* root = - AddScrollableLayer(root_clip, scroll_container_size, surface_size); + SetupViewportLayersNoScrolls(surface_size); + LayerImpl* root = AddScrollableLayer(OuterViewportScrollLayer(), + scroll_container_size, surface_size); LayerImpl* child_layer = AddScrollableLayer(root, scroll_container_size, surface_size); LayerImpl* grand_child_layer = AddScrollableLayer(child_layer, scroll_container_size, surface_size); - LayerTreeImpl::ViewportPropertyIds viewport_property_ids; - viewport_property_ids.inner_scroll = root->scroll_tree_index(); - host_impl_->active_tree()->SetViewportPropertyIds(viewport_property_ids); - UpdateDrawProperties(host_impl_->active_tree()); host_impl_->active_tree()->DidBecomeActive(); @@ -7335,33 +7524,38 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { gfx::Vector2d scroll_delta(0, -10); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); scroll_result = host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); + EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, + grand_child_layer->scroll_tree_index()); EXPECT_TRUE(scroll_result.did_scroll); EXPECT_FALSE(scroll_result.did_overscroll_root); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // The next time we scroll we should only scroll the parent, but overscroll // should still not reach the root layer. scroll_delta = gfx::Vector2d(0, -30); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, - grand_child_layer->scroll_tree_index()); + child_layer->scroll_tree_index()); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::TOUCHSCREEN) - .thread); + host_impl_->ScrollEnd(); + + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); scroll_result = host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -7369,16 +7563,17 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, child_layer->scroll_tree_index()); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // After scrolling the parent, another scroll on the opposite direction // should scroll the child. scroll_delta = gfx::Vector2d(0, 70); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, grand_child_layer->scroll_tree_index()); scroll_result = @@ -7388,7 +7583,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, grand_child_layer->scroll_tree_index()); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } } @@ -7401,11 +7596,12 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) { DrawFrame(); { gfx::Vector2d scroll_delta(0, 8); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::WHEEL) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta).get(), + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -7421,7 +7617,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) { EXPECT_FALSE(scroll_result.did_scroll); EXPECT_TRUE(scroll_result.did_overscroll_root); EXPECT_EQ(gfx::Vector2dF(0, 14), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } } @@ -7433,7 +7629,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollAlways) { SetupViewportLayersNoScrolls(gfx::Size(50, 50)); UpdateDrawProperties(host_impl_->active_tree()); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); DrawFrame(); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); @@ -7441,7 +7637,8 @@ TEST_F(LayerTreeHostImplTest, OverscrollAlways) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); @@ -7460,11 +7657,13 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) { // Edge glow effect should be applicable only upon reaching Edges // of the content. unnecessary glow effect calls shouldn't be // called while scrolling up without reaching the edge of the content. - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 100)).get(), + InputHandler::WHEEL) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get()); EXPECT_TRUE(scroll_result.did_scroll); @@ -7477,13 +7676,14 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) { EXPECT_FALSE(scroll_result.did_overscroll_root); EXPECT_EQ(gfx::Vector2dF().ToString(), host_impl_->accumulated_root_overscroll().ToString()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // unusedrootDelta should be subtracted from applied delta so that // unwanted glow effect calls are not called. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 20)).get(), + InputHandler::TOUCHSCREEN) .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 20)).get()); @@ -7498,13 +7698,15 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) { EXPECT_FALSE(scroll_result.did_overscroll_root); EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0.000000f, 17.699997f), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); // TestCase to check kEpsilon, which prevents minute values to trigger // gloweffect without reaching edge. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::WHEEL) + ->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(-0.12f, 0.1f)) + .get(), + InputHandler::WHEEL) .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(-0.12f, 0.1f)).get()); @@ -7512,7 +7714,7 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) { EXPECT_FALSE(scroll_result.did_overscroll_root); EXPECT_EQ(gfx::Vector2dF().ToString(), host_impl_->accumulated_root_overscroll().ToString()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } } @@ -7532,14 +7734,15 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollOnNonViewportLayers) { // Start a scroll gesture, ensure it's scrolling the subscroller. { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(100.f, 100.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(100, 100), scroll_layer->CurrentScrollOffset()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); } @@ -7547,11 +7750,11 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollOnNonViewportLayers) { // doesn't consume the delta but it isn't counted as overscroll. { InputHandlerScrollResult result = host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(120.f, 140.f)).get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(120, 140)).get()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(200.f, 200.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(200, 200), scroll_layer->CurrentScrollOffset()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); EXPECT_FALSE(result.did_overscroll_root); } @@ -7560,16 +7763,16 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollOnNonViewportLayers) { // doesn't consume the delta but it isn't counted as overscroll. { InputHandlerScrollResult result = host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(20.f, 40.f)).get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(20, 40)).get()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(200.f, 200.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(200, 200), scroll_layer->CurrentScrollOffset()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); EXPECT_FALSE(result.did_overscroll_root); } - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplTest, OverscrollOnMainThread) { @@ -7592,18 +7795,20 @@ TEST_F(LayerTreeHostImplTest, OverscrollOnMainThread) { gfx::PointF(0, 60))); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 60)).get(), - InputHandler::WHEEL) + ->ScrollBegin( + BeginState(gfx::Point(0, 60), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); // Overscroll initiated inside layers will be handled by the main thread. EXPECT_NE(nullptr, host_impl_->active_tree()->FindLayerThatIsHitByPoint( gfx::PointF(0, 0))); - EXPECT_EQ( - InputHandler::SCROLL_ON_MAIN_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) + .thread); } // Test that scrolling the inner viewport directly works, as can happen when the @@ -7612,8 +7817,9 @@ TEST_F(LayerTreeHostImplTest, ScrollFromOuterViewportSibling) { const gfx::Size viewport_size(100, 100); SetupViewportLayersNoScrolls(viewport_size); - host_impl_->active_tree()->SetTopControlsHeight(10); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f); + host_impl_->active_tree()->SetBrowserControlsParams( + {10, 0, 0, 0, false, false}); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f, 1.f); LayerImpl* outer_scroll_layer = OuterViewportScrollLayer(); LayerImpl* inner_scroll_layer = InnerViewportScrollLayer(); @@ -7625,23 +7831,23 @@ TEST_F(LayerTreeHostImplTest, ScrollFromOuterViewportSibling) { LayerImpl* scroll_layer = AddScrollableLayer( inner_scroll_layer, viewport_size, gfx::Size(400, 400)); - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 2.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); // Fully scroll the child. { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000.f, 1000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get()); + host_impl_->ScrollEnd(); - EXPECT_EQ(1.f, - host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(300.f, 300.f), + EXPECT_EQ(1, host_impl_->active_tree()->CurrentTopControlsShownRatio()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(300, 300), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll_layer->CurrentScrollOffset()); @@ -7653,23 +7859,22 @@ TEST_F(LayerTreeHostImplTest, ScrollFromOuterViewportSibling) { // Scrolling it should cause browser controls to hide. The outer viewport // should not be affected. { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); gfx::Vector2d scroll_delta(0, 10); + host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0), scroll_delta).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - EXPECT_EQ(0.f, - host_impl_->active_tree()->CurrentBrowserControlsShownRatio()); + EXPECT_EQ(0, host_impl_->active_tree()->CurrentTopControlsShownRatio()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll_layer->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 10.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 10), inner_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), outer_scroll_layer->CurrentScrollOffset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } } @@ -7705,25 +7910,27 @@ TEST_F(LayerTreeHostImplTest, ScrollChainingWithReplacedOuterViewport) { // chain to the parent scrolling layer which is now set as the outer // viewport. The original outer viewport layer shouldn't get any scroll here. { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(200, 200)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(200.f, 200.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(200, 200)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(200.f, 200.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(200, 200), child_scroll_layer->CurrentScrollOffset()); - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(200, 200)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(200.f, 200.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(200, 200)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(200.f, 200.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(200, 200), scroll_layer->CurrentScrollOffset()); } @@ -7731,11 +7938,12 @@ TEST_F(LayerTreeHostImplTest, ScrollChainingWithReplacedOuterViewport) { // would normally chain up to the "outer viewport" but since we've set the // scrolling content as the outer viewport, it should stop chaining there. { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(), outer_scroll_layer->CurrentScrollOffset()); @@ -7743,8 +7951,8 @@ TEST_F(LayerTreeHostImplTest, ScrollChainingWithReplacedOuterViewport) { // Zoom into the page by a 2X factor so that the inner viewport becomes // scrollable. - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 2.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); @@ -7757,24 +7965,26 @@ TEST_F(LayerTreeHostImplTest, ScrollChainingWithReplacedOuterViewport) { // and then chain up to the current outer viewport (i.e. the parent scroll // layer). { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(50.f, 50.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), inner_scroll_layer->CurrentScrollOffset()); - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(50.f, 50.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 50), scroll_layer->CurrentScrollOffset()); } } @@ -7798,10 +8008,13 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { // of the outer viewport scroll layer. LayerImpl* outer_scroll_layer = AddScrollableLayer(content_layer, content_size, gfx::Size(1200, 1200)); - GetScrollNode(outer_scroll_layer)->scrolls_outer_viewport = true; LayerImpl* sibling_scroll_layer = AddScrollableLayer( content_layer, gfx::Size(600, 600), gfx::Size(1200, 1200)); + GetScrollNode(InnerViewportScrollLayer()) + ->prevent_viewport_scrolling_from_inner = true; + GetScrollNode(OuterViewportScrollLayer())->scrolls_outer_viewport = false; + GetScrollNode(outer_scroll_layer)->scrolls_outer_viewport = true; auto viewport_property_ids = layer_tree_impl->ViewportPropertyIdsForTesting(); viewport_property_ids.outer_scroll = outer_scroll_layer->scroll_tree_index(); layer_tree_impl->SetViewportPropertyIds(viewport_property_ids); @@ -7813,33 +8026,35 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { // propagate to the outer viewport scroll layer. { // This should fully scroll the layer. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000.f, 1000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(600.f, 600.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(600, 600), sibling_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), outer_scroll_layer->CurrentScrollOffset()); // Scrolling now should chain up but, since the outer viewport is a sibling // rather than an ancestor, we shouldn't chain to it. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000.f, 1000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000, 1000)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(600.f, 600.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(600, 600), sibling_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), outer_scroll_layer->CurrentScrollOffset()); } - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 1.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 1; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); @@ -7854,9 +8069,9 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { { // Pinch in to the middle of the screen. The inner viewport should scroll // to keep the gesture anchored but not the outer or the sibling scroller. - page_scale_factor = 2.f; + page_scale_factor = 2; gfx::Point anchor(viewport_size.width() / 2, viewport_size.height() / 2); - host_impl_->ScrollBegin(BeginState(anchor).get(), + host_impl_->ScrollBegin(BeginState(anchor, gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_factor, anchor); @@ -7867,7 +8082,7 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { host_impl_->ScrollBy(UpdateState(anchor, viewport_size_vec).get()); - EXPECT_VECTOR_EQ(ScaleVector2d(viewport_size_vec, 1.f / page_scale_factor), + EXPECT_VECTOR_EQ(ScaleVector2d(viewport_size_vec, 1 / page_scale_factor), inner_scroll_layer->CurrentScrollOffset()); // TODO(bokan): This doesn't yet work but we'll probably want to fix this // at some point. @@ -7877,7 +8092,7 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { EXPECT_VECTOR_EQ(gfx::Vector2dF(), sibling_scroll_layer->CurrentScrollOffset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } // Reset the scroll offsets @@ -7891,23 +8106,25 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { { // This should fully scroll the sibling but, because we latch to the // scroller, it shouldn't chain up to the inner viewport yet. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(2000, 2000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(2000.f, 2000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(2000, 2000)).get()); + host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(600.f, 600.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(600, 600), sibling_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll_layer->CurrentScrollOffset()); // Scrolling now should chain up to the inner viewport. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(2000, 2000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(2000.f, 2000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(2000, 2000)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(ScaleVector2d(viewport_size_vec, 1 / page_scale_factor), inner_scroll_layer->CurrentScrollOffset()); @@ -7915,11 +8132,12 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) { outer_scroll_layer->CurrentScrollOffset()); // No more scrolling should be possible. - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(2000, 2000)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(2000.f, 2000.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(2000, 2000)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(), outer_scroll_layer->CurrentScrollOffset()); @@ -7949,18 +8167,20 @@ TEST_F(LayerTreeHostImplTest, OverscrollOnImplThread) { gfx::PointF(0, 60))); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 60)).get(), - InputHandler::WHEEL) + ->ScrollBegin( + BeginState(gfx::Point(0, 60), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); // Overscroll initiated inside layers will be handled by the impl thread. EXPECT_NE(nullptr, host_impl_->active_tree()->FindLayerThatIsHitByPoint( gfx::PointF(0, 0))); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) + .thread); } class BlendStateCheckLayer : public LayerImpl { @@ -8014,10 +8234,10 @@ class BlendStateCheckLayer : public LayerImpl { auto* test_blending_draw_quad = render_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>(); - test_blending_draw_quad->SetNew( - shared_quad_state, quad_rect_, visible_quad_rect, needs_blending, - resource_id_, gfx::RectF(0.f, 0.f, 1.f, 1.f), gfx::Size(1, 1), false, - false, false); + test_blending_draw_quad->SetNew(shared_quad_state, quad_rect_, + visible_quad_rect, needs_blending, + resource_id_, gfx::RectF(0, 0, 1, 1), + gfx::Size(1, 1), false, false, false); EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending()); EXPECT_EQ(has_render_surface_, @@ -8060,20 +8280,20 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { auto* layer1 = AddLayer<BlendStateCheckLayer>( host_impl_->active_tree(), host_impl_->resource_provider()); CopyProperties(root, layer1); - CreateTransformNode(layer1).post_translation = gfx::Vector2dF(2.f, 2.f); + CreateTransformNode(layer1).post_translation = gfx::Vector2dF(2, 2); CreateEffectNode(layer1); // Opaque layer, drawn without blending. layer1->SetContentsOpaque(true); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); // Layer with translucent content and painting, so drawn with blending. layer1->SetContentsOpaque(false); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); @@ -8081,7 +8301,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetContentsOpaque(true); SetOpacity(layer1, 0.5f); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); @@ -8089,25 +8309,25 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetContentsOpaque(true); SetOpacity(layer1, 0.5f); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); auto* layer2 = AddLayer<BlendStateCheckLayer>( host_impl_->active_tree(), host_impl_->resource_provider()); CopyProperties(layer1, layer2); - CreateTransformNode(layer2).post_translation = gfx::Vector2dF(4.f, 4.f); + CreateTransformNode(layer2).post_translation = gfx::Vector2dF(4, 4); CreateEffectNode(layer2); // 2 opaque layers, drawn without blending. layer1->SetContentsOpaque(true); - SetOpacity(layer1, 1.f); + SetOpacity(layer1, 1); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetContentsOpaque(true); - SetOpacity(layer2, 1.f); + SetOpacity(layer2, 1); layer2->SetExpectation(false, false, root); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -8116,9 +8336,9 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { // Child layer with opaque content, drawn without blending. layer1->SetContentsOpaque(false); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetExpectation(false, false, root); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -8128,9 +8348,9 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { // Child layer with opaque content, drawn without blending. layer1->SetContentsOpaque(true); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetExpectation(false, false, root); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -8144,9 +8364,9 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { SetOpacity(layer1, 0.5f); GetEffectNode(layer1)->render_surface_reason = RenderSurfaceReason::kTest; layer1->SetExpectation(false, true, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetExpectation(false, false, layer1); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -8155,26 +8375,26 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { // Draw again, but with child non-opaque, to make sure // layer1 not culled. layer1->SetContentsOpaque(true); - SetOpacity(layer1, 1.f); + SetOpacity(layer1, 1); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetContentsOpaque(true); SetOpacity(layer2, 0.5f); layer2->SetExpectation(true, false, layer1); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); // A second way of making the child non-opaque. layer1->SetContentsOpaque(true); - SetOpacity(layer1, 1.f); + SetOpacity(layer1, 1); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetContentsOpaque(false); - SetOpacity(layer2, 1.f); + SetOpacity(layer2, 1); layer2->SetExpectation(true, false, root); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -8182,13 +8402,13 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { // And when the layer says its not opaque but is painted opaque, it is not // blended. layer1->SetContentsOpaque(true); - SetOpacity(layer1, 1.f); + SetOpacity(layer1, 1); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetContentsOpaque(true); - SetOpacity(layer2, 1.f); + SetOpacity(layer2, 1); layer2->SetExpectation(false, false, root); - layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer2->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -8199,7 +8419,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 5)); layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); @@ -8209,7 +8429,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 2)); layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); @@ -8219,7 +8439,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetQuadVisibleRect(gfx::Rect(7, 5, 3, 5)); layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(true, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); @@ -8230,7 +8450,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 2, 5)); layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(false, false, root); - layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); + layer1->UnionUpdateRect(gfx::Rect(layer1->bounds())); DrawFrame(); EXPECT_TRUE(layer1->quads_appended()); } @@ -8238,9 +8458,13 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { static bool MayContainVideoBitSetOnFrameData(LayerTreeHostImpl* host_impl) { host_impl->active_tree()->set_needs_update_draw_properties(); TestFrameData frame; + host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl->PrepareToDraw(&frame)); host_impl->DrawLayers(&frame); host_impl->DidDrawAllLayers(frame); + host_impl->DidFinishImplFrame(); return frame.may_contain_video; } @@ -8273,11 +8497,11 @@ TEST_F(LayerTreeHostImplTest, MayContainVideo) { EXPECT_TRUE(MayContainVideoBitSetOnFrameData(host_impl_.get())); // Move the video layer so it goes beyond the root. - video_layer->SetOffsetToTransformParent(gfx::Vector2dF(100.f, 100.f)); + video_layer->SetOffsetToTransformParent(gfx::Vector2dF(100, 100)); UpdateDrawProperties(host_impl_->active_tree()); EXPECT_FALSE(MayContainVideoBitSetOnFrameData(host_impl_.get())); - video_layer->SetOffsetToTransformParent(gfx::Vector2dF(0.f, 0.f)); + video_layer->SetOffsetToTransformParent(gfx::Vector2dF(0, 0)); video_layer->NoteLayerPropertyChanged(); UpdateDrawProperties(host_impl_->active_tree()); EXPECT_TRUE(MayContainVideoBitSetOnFrameData(host_impl_.get())); @@ -8491,7 +8715,7 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredScaled) { bool software = false; CreateHostImpl(DefaultSettings(), CreateFakeLayerTreeFrameSink(software)); - host_impl_->active_tree()->SetDeviceScaleFactor(2.f); + host_impl_->active_tree()->SetDeviceScaleFactor(2); SetupActiveTreeLayers(); EXPECT_SCOPED(TestLayerCoversFullViewport()); EXPECT_SCOPED(TestEmptyLayer()); @@ -8577,8 +8801,6 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { nullptr); layer_tree_host_impl->SetVisible(true); layer_tree_host_impl->InitializeFrameSink(layer_tree_frame_sink.get()); - layer_tree_host_impl->WillBeginImplFrame( - viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2)); LayerImpl* root = SetupRootLayer<LayerImpl>( layer_tree_host_impl->active_tree(), gfx::Size(500, 500)); @@ -8586,7 +8808,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { child->SetBounds(gfx::Size(14, 15)); child->SetDrawsContent(true); CopyProperties(root, child); - child->SetOffsetToTransformParent(gfx::Vector2dF(12.f, 13.f)); + child->SetOffsetToTransformParent(gfx::Vector2dF(12, 13)); layer_tree_host_impl->active_tree()->SetLocalSurfaceIdAllocationFromParent( viz::LocalSurfaceIdAllocation( viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), @@ -8596,9 +8818,13 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { TestFrameData frame; // First frame, the entire screen should get swapped. + layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame)); layer_tree_host_impl->DrawLayers(&frame); layer_tree_host_impl->DidDrawAllLayers(frame); + layer_tree_host_impl->DidFinishImplFrame(); gfx::Rect expected_swap_rect(500, 500); EXPECT_EQ(expected_swap_rect.ToString(), fake_layer_tree_frame_sink->last_swap_rect().ToString()); @@ -8607,9 +8833,13 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { // the union of old and new child rects: gfx::Rect(26, 28). child->SetOffsetToTransformParent(gfx::Vector2dF()); child->NoteLayerPropertyChanged(); + layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame)); layer_tree_host_impl->DrawLayers(&frame); - host_impl_->DidDrawAllLayers(frame); + layer_tree_host_impl->DidDrawAllLayers(frame); + layer_tree_host_impl->DidFinishImplFrame(); expected_swap_rect = gfx::Rect(26, 28); EXPECT_EQ(expected_swap_rect.ToString(), @@ -8618,9 +8848,13 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { layer_tree_host_impl->active_tree()->SetDeviceViewportRect(gfx::Rect(10, 10)); // This will damage everything. root->SetBackgroundColor(SK_ColorBLACK); + layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame)); layer_tree_host_impl->DrawLayers(&frame); - host_impl_->DidDrawAllLayers(frame); + layer_tree_host_impl->DidDrawAllLayers(frame); + layer_tree_host_impl->DidFinishImplFrame(); expected_swap_rect = gfx::Rect(10, 10); EXPECT_EQ(expected_swap_rect.ToString(), @@ -8715,6 +8949,9 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { // Verify one quad is drawn when transparent background set is not set. TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); { const auto& root_pass = frame.render_passes.back(); @@ -8724,6 +8961,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { } host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); // Cause damage so we would draw something if possible. host_impl_->SetFullViewportDamage(); @@ -8731,6 +8969,9 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { // Verify no quads are drawn when transparent background is set. host_impl_->active_tree()->set_background_color(SK_ColorTRANSPARENT); host_impl_->SetFullViewportDamage(); + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); { const auto& root_pass = frame.render_passes.back(); @@ -8738,6 +8979,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { } host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); // Cause damage so we would draw something if possible. host_impl_->SetFullViewportDamage(); @@ -8745,6 +8987,9 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { // Verify no quads are drawn when semi-transparent background is set. host_impl_->active_tree()->set_background_color(SkColorSetARGB(5, 255, 0, 0)); host_impl_->SetFullViewportDamage(); + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); { const auto& root_pass = frame.render_passes.back(); @@ -8752,6 +8997,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { } host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } class LayerTreeHostImplTestDrawAndTestDamage : public LayerTreeHostImplTest { @@ -8765,6 +9011,9 @@ class LayerTreeHostImplTestDrawAndTestDamage : public LayerTreeHostImplTest { bool expect_to_draw = !expected_damage.IsEmpty(); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); if (!expect_to_draw) { @@ -8794,6 +9043,7 @@ class LayerTreeHostImplTestDrawAndTestDamage : public LayerTreeHostImplTest { EXPECT_EQ(expect_to_draw, host_impl_->DrawLayers(&frame)); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } }; @@ -8809,7 +9059,7 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, FrameIncludesDamageRect) { child->SetDrawsContent(true); child->SetBackgroundColor(SK_ColorRED); CopyProperties(root, child); - child->SetOffsetToTransformParent(gfx::Vector2dF(9.f, 9.f)); + child->SetOffsetToTransformParent(gfx::Vector2dF(9, 9)); UpdateDrawProperties(host_impl_->active_tree()); @@ -8821,7 +9071,7 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, FrameIncludesDamageRect) { // The second frame has damage that doesn't touch the child layer. Its quads // should still be generated. gfx::Rect small_damage = gfx::Rect(0, 0, 1, 1); - root->SetUpdateRect(small_damage); + root->UnionUpdateRect(small_damage); DrawFrameAndTestDamage(small_damage, child); // The third frame should have no damage, so no quads should be generated. @@ -8837,12 +9087,11 @@ class GLRendererWithSetupQuadForAntialiasing : public viz::GLRenderer { TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { // Due to precision issues (especially on Android), sometimes far // away quads can end up thinking they need AA. - float device_scale_factor = 4.f / 3.f; + float device_scale_factor = 4 / 3; gfx::Size root_size(2000, 1000); CreatePendingTree(); host_impl_->pending_tree()->SetDeviceScaleFactor(device_scale_factor); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f / 16.f, - 16.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1 / 16, 16); auto* root = SetupRootLayer<LayerImpl>(host_impl_->pending_tree(), root_size); root->SetNeedsPushProperties(); @@ -8875,6 +9124,9 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { ASSERT_EQ(1u, host_impl_->active_tree()->GetRenderSurfaceList().size()); TestFrameData frame; + host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); @@ -8894,6 +9146,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); + host_impl_->DidFinishImplFrame(); } class CompositorFrameMetadataTest : public LayerTreeHostImplTest { @@ -9054,12 +9307,16 @@ void ExpectFullDamageAndDraw(LayerTreeHostImpl* host_impl) { gfx::Rect full_frame_damage( host_impl->active_tree()->GetDeviceViewport().size()); TestFrameData frame; + host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); EXPECT_EQ(DRAW_SUCCESS, host_impl->PrepareToDraw(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); const viz::RenderPass* root_render_pass = frame.render_passes.back().get(); EXPECT_EQ(full_frame_damage, root_render_pass->damage_rect); EXPECT_TRUE(host_impl->DrawLayers(&frame)); host_impl->DidDrawAllLayers(frame); + host_impl->DidFinishImplFrame(); } } // namespace @@ -9098,44 +9355,6 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, EXPECT_SCOPED(ExpectFullDamageAndDraw(host_impl_.get())); } -TEST_F(LayerTreeHostImplTest, RequireHighResAfterMSAAToggles) { - // Create a host impl with MSAA support and a forced sample count of 4. - LayerTreeSettings msaaSettings = DefaultSettings(); - msaaSettings.gpu_rasterization_msaa_sample_count = 4; - EXPECT_TRUE(CreateHostImpl( - msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization( - msaaSettings.gpu_rasterization_msaa_sample_count))); - - ASSERT_TRUE(host_impl_->active_tree()); - EXPECT_FALSE(host_impl_->use_msaa()); - - // RequiresHighResToDraw is set when new output surface is used. - EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); - - host_impl_->ResetRequiresHighResToDraw(); - - host_impl_->SetContentHasSlowPaths(false); - host_impl_->CommitComplete(); - EXPECT_FALSE(host_impl_->RequiresHighResToDraw()); - host_impl_->NotifyReadyToActivate(); - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); - host_impl_->NotifyReadyToActivate(); - host_impl_->SetContentHasSlowPaths(false); - host_impl_->CommitComplete(); - EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); - host_impl_->NotifyReadyToActivate(); - - host_impl_->ResetRequiresHighResToDraw(); - - EXPECT_FALSE(host_impl_->RequiresHighResToDraw()); - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); - host_impl_->NotifyReadyToActivate(); -} - class LayerTreeHostImplTestPrepareTiles : public LayerTreeHostImplTest { public: void SetUp() override { @@ -9227,41 +9446,6 @@ TEST_F(LayerTreeHostImplTest, CreateETC1UIResource) { EXPECT_NE(0u, id1); } -TEST_F(LayerTreeHostImplTest, - GpuRasterizationStatusChangeDoesNotEvictUIResources) { - // Create a host impl with MSAA support and a forced sample count of 4. - LayerTreeSettings msaaSettings = DefaultSettings(); - msaaSettings.gpu_rasterization_msaa_sample_count = 4; - EXPECT_TRUE(CreateHostImpl( - msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization( - msaaSettings.gpu_rasterization_msaa_sample_count))); - - host_impl_->SetContentHasSlowPaths(false); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); - - UIResourceId ui_resource_id = 1; - UIResourceBitmap bitmap(gfx::Size(1, 1), false /* is_opaque */); - host_impl_->CreateUIResource(ui_resource_id, bitmap); - viz::ResourceId resource_id = - host_impl_->ResourceIdForUIResource(ui_resource_id); - EXPECT_NE(viz::kInvalidResourceId, resource_id); - EXPECT_FALSE(host_impl_->EvictedUIResourcesExist()); - - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_TRUE(host_impl_->use_msaa()); - - resource_id = host_impl_->ResourceIdForUIResource(ui_resource_id); - EXPECT_NE(viz::kInvalidResourceId, resource_id); - EXPECT_FALSE(host_impl_->EvictedUIResourcesExist()); -} - TEST_F(LayerTreeHostImplTest, ObeyMSAACaps) { LayerTreeSettings msaaSettings = DefaultSettings(); msaaSettings.gpu_rasterization_msaa_sample_count = 4; @@ -9273,15 +9457,7 @@ TEST_F(LayerTreeHostImplTest, ObeyMSAACaps) { msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization( msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow))); - - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_oop_rasterization()); - EXPECT_TRUE(host_impl_->use_msaa()); + EXPECT_TRUE(host_impl_->can_use_msaa()); } // gpu raster, msaa off @@ -9291,15 +9467,7 @@ TEST_F(LayerTreeHostImplTest, ObeyMSAACaps) { msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization( msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow))); - - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - - EXPECT_EQ(GpuRasterizationStatus::ON, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_oop_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); + EXPECT_FALSE(host_impl_->can_use_msaa()); } // oop raster, msaa on @@ -9309,15 +9477,7 @@ TEST_F(LayerTreeHostImplTest, ObeyMSAACaps) { msaaSettings, FakeLayerTreeFrameSink::Create3dForOopRasterization( msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow))); - - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_TRUE(host_impl_->use_oop_rasterization()); - EXPECT_TRUE(host_impl_->use_msaa()); + EXPECT_TRUE(host_impl_->can_use_msaa()); } // oop raster, msaa off @@ -9327,15 +9487,7 @@ TEST_F(LayerTreeHostImplTest, ObeyMSAACaps) { msaaSettings, FakeLayerTreeFrameSink::Create3dForOopRasterization( msaaSettings.gpu_rasterization_msaa_sample_count, msaa_is_slow))); - - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - - EXPECT_EQ(GpuRasterizationStatus::ON, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_TRUE(host_impl_->use_oop_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); + EXPECT_FALSE(host_impl_->can_use_msaa()); } } @@ -9379,7 +9531,7 @@ class LayerTreeHostImplTestWithRenderer RendererType renderer_type() const { return GetParam(); } }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostImplTestWithRenderer, ::testing::Values(RENDERER_GL, RENDERER_SKIA)); @@ -9457,7 +9609,8 @@ TEST_F(LayerTreeHostImplTest, ScrollUnknownNotOnAncestorChain) { DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, status.main_thread_scrolling_reasons); @@ -9478,19 +9631,20 @@ TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) { LayerImpl* child_scroll = AddScrollableLayer(child_scroll_clip, viewport_size, content_size); - child_scroll->SetOffsetToTransformParent(gfx::Vector2dF(10.f, 10.f)); + child_scroll->SetOffsetToTransformParent(gfx::Vector2dF(10, 10)); LayerImpl* occluder_layer = AddLayer(); occluder_layer->SetDrawsContent(true); occluder_layer->SetHitTestable(true); occluder_layer->SetBounds(content_size); CopyProperties(child_scroll, occluder_layer); - occluder_layer->SetOffsetToTransformParent(gfx::Vector2dF(-10.f, -10.f)); + occluder_layer->SetOffsetToTransformParent(gfx::Vector2dF(-10, -10)); DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::WHEEL); + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread); EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest, status.main_thread_scrolling_reasons); @@ -9513,7 +9667,8 @@ TEST_F(LayerTreeHostImplTest, ScrollInvisibleScroller) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); EXPECT_EQ(child_scroll->scroll_tree_index(), @@ -9558,13 +9713,13 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) { UpdateDrawProperties(host_impl_->active_tree()); // Plumb the layer-local selection bounds. - gfx::Point selection_top(5, 0); - gfx::Point selection_bottom(5, 5); + gfx::Point selection_start(5, 0); + gfx::Point selection_end(5, 5); LayerSelection selection; selection.start.type = gfx::SelectionBound::CENTER; selection.start.layer_id = root->id(); - selection.start.edge_bottom = selection_bottom; - selection.start.edge_top = selection_top; + selection.start.edge_end = selection_end; + selection.start.edge_start = selection_start; selection.end = selection.start; host_impl_->active_tree()->RegisterSelection(selection); @@ -9576,8 +9731,8 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) { metadata.selection; EXPECT_EQ(selection.start.type, selection_after.start.type()); EXPECT_EQ(selection.end.type, selection_after.end.type()); - EXPECT_EQ(gfx::PointF(selection_bottom), selection_after.start.edge_bottom()); - EXPECT_EQ(gfx::PointF(selection_top), selection_after.start.edge_top()); + EXPECT_EQ(gfx::PointF(selection_end), selection_after.start.edge_end()); + EXPECT_EQ(gfx::PointF(selection_start), selection_after.start.edge_start()); EXPECT_TRUE(selection_after.start.visible()); EXPECT_TRUE(selection_after.end.visible()); } @@ -9588,8 +9743,8 @@ TEST_F(LayerTreeHostImplTest, HiddenSelectionBoundsStayHidden) { UpdateDrawProperties(host_impl_->active_tree()); // Plumb the layer-local selection bounds. - gfx::Point selection_top(5, 0); - gfx::Point selection_bottom(5, 5); + gfx::Point selection_start(5, 0); + gfx::Point selection_end(5, 5); LayerSelection selection; // Mark the start as hidden. @@ -9597,8 +9752,8 @@ TEST_F(LayerTreeHostImplTest, HiddenSelectionBoundsStayHidden) { selection.start.type = gfx::SelectionBound::CENTER; selection.start.layer_id = root->id(); - selection.start.edge_bottom = selection_bottom; - selection.start.edge_top = selection_top; + selection.start.edge_end = selection_end; + selection.start.edge_start = selection_start; selection.end = selection.start; host_impl_->active_tree()->RegisterSelection(selection); @@ -9610,8 +9765,8 @@ TEST_F(LayerTreeHostImplTest, HiddenSelectionBoundsStayHidden) { metadata.selection; EXPECT_EQ(selection.start.type, selection_after.start.type()); EXPECT_EQ(selection.end.type, selection_after.end.type()); - EXPECT_EQ(gfx::PointF(selection_bottom), selection_after.start.edge_bottom()); - EXPECT_EQ(gfx::PointF(selection_top), selection_after.start.edge_top()); + EXPECT_EQ(gfx::PointF(selection_end), selection_after.start.edge_end()); + EXPECT_EQ(gfx::PointF(selection_start), selection_after.start.edge_start()); EXPECT_FALSE(selection_after.start.visible()); EXPECT_FALSE(selection_after.end.visible()); } @@ -9695,16 +9850,17 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); // Scrolling normally should not trigger any forwarding. - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_TRUE( host_impl_ ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()) .did_scroll); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_EQ(0, set_needs_commit_count); EXPECT_EQ(1, set_needs_redraw_count); @@ -9712,16 +9868,17 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) { // Scrolling with a scroll handler should defer the swap to the main // thread. host_impl_->active_tree()->set_have_scroll_event_handlers(true); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_TRUE( host_impl_ ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()) .did_scroll); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_EQ(0, set_needs_commit_count); EXPECT_EQ(2, set_needs_redraw_count); @@ -9734,8 +9891,9 @@ class LayerTreeHostImplWithBrowserControlsTest : public LayerTreeHostImplTest { LayerTreeSettings settings = DefaultSettings(); settings.commit_to_active_tree = false; CreateHostImpl(settings, CreateLayerTreeFrameSink()); - host_impl_->active_tree()->SetTopControlsHeight(top_controls_height_); - host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f); + host_impl_->active_tree()->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, false}); + host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f, 1.f); } protected: @@ -9764,7 +9922,8 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); EXPECT_FALSE(did_request_redraw_); CreatePendingTree(); - host_impl_->sync_tree()->SetTopControlsHeight(100); + host_impl_->sync_tree()->SetBrowserControlsParams( + {100, 0, 0, 0, false, false}); host_impl_->ActivateSyncTree(); EXPECT_EQ(100, host_impl_->browser_controls_manager()->TopControlsHeight()); } @@ -9772,17 +9931,18 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, TEST_F(LayerTreeHostImplWithBrowserControlsTest, BrowserControlsStayFullyVisibleOnHeightChange) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ControlsTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); CreatePendingTree(); - host_impl_->sync_tree()->SetTopControlsHeight(0); + host_impl_->sync_tree()->SetBrowserControlsParams({0, 0, 0, 0, false, false}); host_impl_->ActivateSyncTree(); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ControlsTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); CreatePendingTree(); - host_impl_->sync_tree()->SetTopControlsHeight(50); + host_impl_->sync_tree()->SetBrowserControlsParams( + {50, 0, 0, 0, false, false}); host_impl_->ActivateSyncTree(); - EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ControlsTopOffset()); + EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); } TEST_F(LayerTreeHostImplWithBrowserControlsTest, @@ -9809,18 +9969,20 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, BrowserControlsState::kBoth, BrowserControlsState::kShown, false); DrawFrame(); + // First, scroll just the browser controls and verify that the scroll + // succeeds. + const float residue = 10; + float offset = top_controls_height_ - residue; EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, offset)).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); - // Scroll just the browser controls and verify that the scroll succeeds. - const float residue = 10; - float offset = top_controls_height_ - residue; result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2d(0, offset)).get()); EXPECT_EQ(result.unused_scroll_delta, gfx::Vector2d(0, 0)); @@ -9872,30 +10034,32 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplWithBrowserControlsTest, WheelUnhandledByBrowserControls) { SetupViewportLayersInnerScrolls(gfx::Size(50, 100), gfx::Size(100, 200)); - host_impl_->active_tree()->set_browser_controls_shrink_blink_size(true); + host_impl_->active_tree()->SetBrowserControlsParams( + {top_controls_height_, 0, 0, 0, false, true}); host_impl_->browser_controls_manager()->UpdateBrowserControlsState( BrowserControlsState::kBoth, BrowserControlsState::kShown, false); DrawFrame(); LayerImpl* viewport_layer = InnerViewportScrollLayer(); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) - .thread); + const float delta = top_controls_height_; + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, delta)).get(), + InputHandler::WHEEL) + .thread); EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), viewport_layer->CurrentScrollOffset()); // Wheel scrolls should not affect the browser controls, and should pass // directly through to the viewport. - const float delta = top_controls_height_; EXPECT_TRUE( host_impl_ ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, delta)).get()) @@ -9925,18 +10089,19 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, BrowserControlsState::kBoth, BrowserControlsState::kShown, false); DrawFrame(); + const float residue = 35; + float offset = top_controls_height_ - residue; EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, offset)).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); // Scroll the browser controls partially. - const float residue = 35; - float offset = top_controls_height_ - residue; EXPECT_TRUE( host_impl_ ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, offset)).get()) @@ -9951,8 +10116,8 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, did_request_commit_ = false; // End the scroll while the controls are still offset from their limit. - host_impl_->ScrollEnd(EndState().get()); - ASSERT_TRUE(host_impl_->browser_controls_manager()->has_animation()); + host_impl_->ScrollEnd(); + ASSERT_TRUE(host_impl_->browser_controls_manager()->HasAnimation()); EXPECT_TRUE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); @@ -9987,12 +10152,12 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, EXPECT_TRUE(did_request_redraw_); if (new_offset != 0) { - EXPECT_TRUE(host_impl_->browser_controls_manager()->has_animation()); + EXPECT_TRUE(host_impl_->browser_controls_manager()->HasAnimation()); EXPECT_TRUE(did_request_next_frame_); } host_impl_->DidFinishImplFrame(); } - EXPECT_FALSE(host_impl_->browser_controls_manager()->has_animation()); + EXPECT_FALSE(host_impl_->browser_controls_manager()->HasAnimation()); } TEST_F(LayerTreeHostImplWithBrowserControlsTest, @@ -10011,18 +10176,19 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, gfx::ScrollOffset(0, initial_scroll_offset)); DrawFrame(); + const float residue = 15; + float offset = top_controls_height_ - residue; EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, offset)).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(), scroll_layer->CurrentScrollOffset().ToString()); // Scroll the browser controls partially. - const float residue = 15; - float offset = top_controls_height_ - residue; EXPECT_TRUE( host_impl_ ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, offset)).get()) @@ -10037,8 +10203,8 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, did_request_commit_ = false; // End the scroll while the controls are still offset from the limit. - host_impl_->ScrollEnd(EndState().get()); - ASSERT_TRUE(host_impl_->browser_controls_manager()->has_animation()); + host_impl_->ScrollEnd(); + ASSERT_TRUE(host_impl_->browser_controls_manager()->HasAnimation()); EXPECT_TRUE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); @@ -10068,7 +10234,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, } host_impl_->DidFinishImplFrame(); } - EXPECT_FALSE(host_impl_->browser_controls_manager()->has_animation()); + EXPECT_FALSE(host_impl_->browser_controls_manager()->HasAnimation()); EXPECT_EQ(-top_controls_height_, host_impl_->browser_controls_manager()->ControlsTopOffset()); } @@ -10085,14 +10251,15 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, BrowserControlsState::kBoth, BrowserControlsState::kShown, false); DrawFrame(); + float offset = 50; EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->ScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, offset)).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); - float offset = 50; EXPECT_TRUE( host_impl_ ->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, offset)).get()) @@ -10151,7 +10318,7 @@ TEST_F(LayerTreeHostImplWithBrowserControlsTest, // Browser controls should be fully visible EXPECT_EQ(0, host_impl_->browser_controls_manager()->ControlsTopOffset()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } // Tests that when we set a child scroller (e.g. a scrolling div) as the outer @@ -10185,21 +10352,22 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, layer_tree_impl->SetViewportPropertyIds(viewport_property_ids); DrawFrame(); - ASSERT_EQ(1.f, layer_tree_impl->CurrentBrowserControlsShownRatio()); + ASSERT_EQ(1, layer_tree_impl->CurrentTopControlsShownRatio()); // Scrolling should scroll the child content and the browser controls. The // original outer viewport should get no scroll. { - host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::TOUCHSCREEN); + host_impl_->ScrollBegin( + BeginState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get(), + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( - UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); - host_impl_->ScrollEnd(EndState().get()); + UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100, 100)).get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(), outer_scroll->CurrentScrollOffset()); - EXPECT_VECTOR_EQ(gfx::Vector2dF(100.f, 50.f), + EXPECT_VECTOR_EQ(gfx::Vector2dF(100, 50), scroll_layer->CurrentScrollOffset()); - EXPECT_EQ(0.f, layer_tree_impl->CurrentBrowserControlsShownRatio()); + EXPECT_EQ(0, layer_tree_impl->CurrentTopControlsShownRatio()); } } @@ -10223,18 +10391,16 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, RootScrollBothInnerAndOuterLayer) { EXPECT_EQ(inner_expected, inner_scroll->CurrentScrollOffset()); EXPECT_EQ(outer_expected, outer_scroll->CurrentScrollOffset()); - gfx::ScrollOffset current_offset(70.f, 100.f); + gfx::ScrollOffset current_offset(70, 100); host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); - EXPECT_EQ(gfx::ScrollOffset(25.f, 40.f), inner_scroll->MaxScrollOffset()); - EXPECT_EQ(gfx::ScrollOffset(50.f, 80.f), outer_scroll->MaxScrollOffset()); + EXPECT_EQ(gfx::ScrollOffset(25, 40), inner_scroll->MaxScrollOffset()); + EXPECT_EQ(gfx::ScrollOffset(50, 80), outer_scroll->MaxScrollOffset()); // Inner viewport scrolls first. Then the rest is applied to the outer // viewport. - EXPECT_EQ(gfx::ScrollOffset(25.f, 40.f), - inner_scroll->CurrentScrollOffset()); - EXPECT_EQ(gfx::ScrollOffset(45.f, 60.f), - outer_scroll->CurrentScrollOffset()); + EXPECT_EQ(gfx::ScrollOffset(25, 40), inner_scroll->CurrentScrollOffset()); + EXPECT_EQ(gfx::ScrollOffset(45, 60), outer_scroll->CurrentScrollOffset()); } } @@ -10257,17 +10423,18 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset()); EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset()); + gfx::Vector2d scroll_delta(inner_viewport.width() / 2, + inner_viewport.height() / 2); + // Make sure the scroll goes to the inner viewport first. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), InputHandler::TOUCHSCREEN) .thread); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); // Scroll near the edge of the outer viewport. - gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f, - inner_viewport.height() / 2.f); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); inner_expected += scroll_delta; EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); @@ -10283,7 +10450,7 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); outer_expected += scroll_delta; inner_expected += scroll_delta; - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset()); @@ -10309,20 +10476,22 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->RootScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) + ->RootScrollBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode(), - host_impl_->ViewportMainScrollNode()); - host_impl_->ScrollEnd(EndState().get()); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + host_impl_->OuterViewportScrollNode()); + host_impl_->ScrollEnd(); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::TOUCHSCREEN) + .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingNode()->id, child_scroll->scroll_tree_index()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); } TEST_F(LayerTreeHostImplVirtualViewportTest, @@ -10342,11 +10511,12 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, // Ensure inner viewport doesn't react to scrolls (test it's unscrollable). EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::TOUCHSCREEN) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 100)).get(), + InputHandler::TOUCHSCREEN) + .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); @@ -10687,7 +10857,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsSublayerScaleFactor) { EffectNode* node = host_impl_->active_tree()->property_trees()->effect_tree.Node( test_layer->effect_tree_index()); - EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1.f, 1.f)); + EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1, 1)); gfx::Transform external_transform; external_transform.Translate(10, 10); @@ -10702,7 +10872,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsSublayerScaleFactor) { resourceless_software_draw, false); node = host_impl_->active_tree()->property_trees()->effect_tree.Node( test_layer->effect_tree_index()); - EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(2.f, 2.f)); + EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(2, 2)); // Clear the external transform. external_transform = gfx::Transform(); @@ -10713,7 +10883,7 @@ TEST_F(LayerTreeHostImplTest, ExternalTransformAffectsSublayerScaleFactor) { resourceless_software_draw, false); node = host_impl_->active_tree()->property_trees()->effect_tree.Node( test_layer->effect_tree_index()); - EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1.f, 1.f)); + EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1, 1)); } TEST_F(LayerTreeHostImplTest, ScrollAnimated) { @@ -10829,8 +10999,8 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimatedWhileZoomed) { // Zoom in to 2X { - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 2.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); @@ -10908,8 +11078,7 @@ TEST_F(LayerTreeHostImplTest, SingleGSUForScrollbarThumbDragPerFrame) { // Set up the thumb dimensions. scrollbar->SetThumbThickness(15); scrollbar->SetThumbLength(50); - scrollbar->SetTrackStart(15); - scrollbar->SetTrackLength(575); + scrollbar->SetTrackRect(gfx::Rect(0, 15, 15, 575)); // Set up scrollbar arrows. scrollbar->SetBackButtonRect( @@ -10919,8 +11088,9 @@ TEST_F(LayerTreeHostImplTest, SingleGSUForScrollbarThumbDragPerFrame) { scrollbar->SetOffsetToTransformParent(gfx::Vector2dF(345, 0)); - host_impl_->ScrollBegin(BeginState(gfx::Point(350, 18)).get(), - InputHandler::SCROLLBAR); + host_impl_->ScrollBegin( + BeginState(gfx::Point(350, 18), gfx::Vector2dF()).get(), + InputHandler::SCROLLBAR); TestInputHandlerClient input_handler_client; host_impl_->BindToClient(&input_handler_client); @@ -10976,14 +11146,18 @@ TEST_F(LayerTreeHostImplTest, SecondScrollAnimatedBeginNotIgnored) { const gfx::Size viewport_size(50, 100); SetupViewportLayersOuterScrolls(viewport_size, content_size); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollAnimatedBegin(BeginState(gfx::Point()).get()).thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollAnimatedBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get()) + .thread); // The second ScrollAnimatedBegin should not get ignored. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollAnimatedBegin(BeginState(gfx::Point()).get()).thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollAnimatedBegin( + BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get()) + .thread); } // Verfify that a smooth scroll animation doesn't jump when UpdateTarget gets @@ -11148,17 +11322,17 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedAborted) { EXPECT_TRUE(y > 1 && y < 49); // Perform instant scroll. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point(0, y)).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin( + BeginState(gfx::Point(0, y), gfx::Vector2dF(0, 50)).get(), + InputHandler::WHEEL) + .thread); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y))); host_impl_->ScrollBy( UpdateState(gfx::Point(0, y), gfx::Vector2d(0, 50)).get()); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, y + 50))); - std::unique_ptr<ScrollState> scroll_state_end = EndState(); - host_impl_->ScrollEnd(scroll_state_end.get()); + host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point())); // The instant scroll should have marked the smooth scroll animation as @@ -11257,8 +11431,8 @@ TEST_F(LayerTreeHostImplTimelinesTest, ImplPinchZoomScrollAnimated) { LayerImpl* inner_scroll_layer = InnerViewportScrollLayer(); // Zoom into the page by a 2X factor - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 2.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); @@ -11269,9 +11443,9 @@ TEST_F(LayerTreeHostImplTimelinesTest, ImplPinchZoomScrollAnimated) { base::TimeTicks() + base::TimeDelta::FromMilliseconds(250); viz::BeginFrameArgs begin_frame_args = viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); - EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(10.f, 20.f)) - .thread); + EXPECT_EQ( + InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(10, 20)).thread); host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_EQ(inner_scroll_layer->scroll_tree_index(), @@ -11289,8 +11463,7 @@ TEST_F(LayerTreeHostImplTimelinesTest, ImplPinchZoomScrollAnimated) { // should bubble up to the outer viewport. EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(100.f, 100.f)) - .thread); + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(100, 100)).thread); host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_EQ(inner_scroll_layer->scroll_tree_index(), @@ -11308,8 +11481,7 @@ TEST_F(LayerTreeHostImplTimelinesTest, ImplPinchZoomScrollAnimated) { // outer viewport. EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(190.f, 180.f)) - .thread); + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(190, 180)).thread); host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_EQ(outer_scroll_layer->scroll_tree_index(), @@ -11325,10 +11497,9 @@ TEST_F(LayerTreeHostImplTimelinesTest, ImplPinchZoomScrollAnimated) { // Scroll upwards by the max scroll extent. The inner viewport should animate // and the remainder should bubble to the outer viewport. - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(-110.f, -120.f)) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(-110, -120)) + .thread); host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_EQ(inner_scroll_layer->scroll_tree_index(), @@ -11354,8 +11525,8 @@ TEST_F(LayerTreeHostImplTimelinesTest, ImplPinchZoomScrollAnimatedUpdate) { LayerImpl* inner_scroll_layer = InnerViewportScrollLayer(); // Zoom into the page by a 2X factor - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 2.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 2; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); @@ -11515,8 +11686,6 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedChangingBounds) { scrolling_layer->SetBounds(new_content_size); GetScrollNode(scrolling_layer)->bounds = new_content_size; - DrawFrame(); - begin_frame_args.frame_time = start_time + base::TimeDelta::FromMilliseconds(200); begin_frame_args.sequence_number++; @@ -11547,7 +11716,7 @@ TEST_F(LayerTreeHostImplTest, InvalidLayerNotAddedToRasterQueue) { layer->tilings()->tiling_at(0)->set_resolution( TileResolution::HIGH_RESOLUTION); layer->tilings()->tiling_at(0)->CreateAllTilesForTesting(); - layer->tilings()->UpdateTilePriorities(gfx::Rect(gfx::Size(10, 10)), 1.f, 1.0, + layer->tilings()->UpdateTilePriorities(gfx::Rect(gfx::Size(10, 10)), 1, 1.0, Occlusion(), true); layer->set_has_valid_tile_priorities(true); @@ -11604,8 +11773,8 @@ TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) { EXPECT_EQ(scroll_layer, InnerViewportScrollLayer()); - float min_page_scale = 1.f, max_page_scale = 4.f; - float page_scale_factor = 1.f; + float min_page_scale = 1, max_page_scale = 4; + float page_scale_factor = 1; // The scroll deltas should have the page scale factor applied. { @@ -11614,24 +11783,24 @@ TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) { host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); SetScrollOffsetDelta(scroll_layer, gfx::Vector2d()); - float page_scale_delta = 2.f; - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + float page_scale_delta = 2; + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); gfx::Vector2dF scroll_delta(0, 5); - EXPECT_EQ( - InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) - .thread); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(), scroll_delta).get(), + InputHandler::WHEEL) + .thread); EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset()); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 2.5), scroll_layer->CurrentScrollOffset()); } @@ -11849,40 +12018,6 @@ TEST_F(LayerTreeHostImplTest, AddVideoFrameControllerOutsideFrame) { EXPECT_FALSE(controller.did_draw_frame()); } -// Tests that SetContentHasSlowPaths behaves as expected. -TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusSlowPaths) { - LayerTreeSettings msaaSettings = DefaultSettings(); - msaaSettings.gpu_rasterization_msaa_sample_count = 4; - EXPECT_TRUE(CreateHostImpl( - msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization( - msaaSettings.gpu_rasterization_msaa_sample_count))); - - // Set initial state, with slow paths on. - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_msaa()); - host_impl_->NotifyReadyToActivate(); - - // Toggle slow paths off. - host_impl_->SetContentHasSlowPaths(false); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); - host_impl_->NotifyReadyToActivate(); - - // And on. - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_TRUE(host_impl_->use_msaa()); - host_impl_->NotifyReadyToActivate(); -} - // Tests that SetDeviceScaleFactor correctly impacts GPU rasterization. TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusDeviceScaleFactor) { // Create a host impl with MSAA support (4 samples). @@ -11892,7 +12027,6 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusDeviceScaleFactor) { msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization(4))); // Set initial state, before varying scale factor. - host_impl_->SetContentHasSlowPaths(true); host_impl_->CommitComplete(); EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); @@ -11902,18 +12036,15 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusDeviceScaleFactor) { // 8 to 4. host_impl_->active_tree()->SetDeviceScaleFactor(2.0f); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); + EXPECT_TRUE(host_impl_->can_use_msaa()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_TRUE(host_impl_->use_msaa()); host_impl_->NotifyReadyToActivate(); // Set device scale factor back to 1. host_impl_->active_tree()->SetDeviceScaleFactor(1.0f); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); + EXPECT_FALSE(host_impl_->can_use_msaa()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); host_impl_->NotifyReadyToActivate(); } @@ -11926,12 +12057,9 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusExplicitMSAACount) { msaaSettings, FakeLayerTreeFrameSink::Create3dForGpuRasterization( msaaSettings.gpu_rasterization_msaa_sample_count))); - host_impl_->SetContentHasSlowPaths(true); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); + EXPECT_TRUE(host_impl_->can_use_msaa()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_TRUE(host_impl_->use_msaa()); } class GpuRasterizationDisabledLayerTreeHostImplTest @@ -11942,28 +12070,6 @@ class GpuRasterizationDisabledLayerTreeHostImplTest } }; -// Tests that GPU rasterization overrides work as expected. -TEST_F(GpuRasterizationDisabledLayerTreeHostImplTest, - GpuRasterizationStatusOverrides) { - LayerTreeSettings settings = DefaultSettings(); - EXPECT_TRUE(CreateHostImpl(settings, FakeLayerTreeFrameSink::Create3d())); - host_impl_->SetContentHasSlowPaths(false); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::OFF_DEVICE, - host_impl_->gpu_rasterization_status()); - EXPECT_FALSE(host_impl_->use_gpu_rasterization()); - - // GPU rasterization explicitly forced. - settings.gpu_rasterization_forced = true; - EXPECT_TRUE(CreateHostImpl(settings, FakeLayerTreeFrameSink::Create3d())); - - host_impl_->SetContentHasSlowPaths(true); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON_FORCED, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); -} - class MsaaIsSlowLayerTreeHostImplTest : public LayerTreeHostImplTest { public: void CreateHostImplWithCaps(bool msaa_is_slow, bool avoid_stencil_buffers) { @@ -11987,37 +12093,29 @@ TEST_F(MsaaIsSlowLayerTreeHostImplTest, GpuRasterizationStatusMsaaIsSlow) { // Ensure that without the msaa_is_slow or avoid_stencil_buffers caps // we raster slow paths with msaa. CreateHostImplWithCaps(false, false); - host_impl_->SetContentHasSlowPaths(true); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); + EXPECT_TRUE(host_impl_->can_use_msaa()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); // Ensure that with either msaa_is_slow or avoid_stencil_buffers caps // we don't raster slow paths with msaa (we'll still use GPU raster, though). // msaa_is_slow = true, avoid_stencil_buffers = false CreateHostImplWithCaps(true, false); - host_impl_->SetContentHasSlowPaths(true); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); + EXPECT_FALSE(host_impl_->can_use_msaa()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); // msaa_is_slow = false, avoid_stencil_buffers = true CreateHostImplWithCaps(false, true); - host_impl_->SetContentHasSlowPaths(true); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); + EXPECT_FALSE(host_impl_->can_use_msaa()); // msaa_is_slow = true, avoid_stencil_buffers = true CreateHostImplWithCaps(true, true); - host_impl_->SetContentHasSlowPaths(true); host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); EXPECT_TRUE(host_impl_->use_gpu_rasterization()); - EXPECT_FALSE(host_impl_->use_msaa()); + EXPECT_FALSE(host_impl_->can_use_msaa()); } class MsaaCompatibilityLayerTreeHostImplTest : public LayerTreeHostImplTest { @@ -12041,66 +12139,73 @@ class MsaaCompatibilityLayerTreeHostImplTest : public LayerTreeHostImplTest { TEST_F(MsaaCompatibilityLayerTreeHostImplTest, GpuRasterizationStatusNonAAPaint) { + // Always use a recording with slow paths so the toggle is dependent on non aa + // paint. + auto recording_source = FakeRecordingSource::CreateRecordingSource( + gfx::Rect(100, 100), gfx::Size(100, 100)); + recording_source->set_has_slow_paths(true); + // Ensure that without non-aa paint and without multisample compatibility, we // raster slow paths with msaa. CreateHostImplWithMultisampleCompatibility(false); - host_impl_->SetContentHasSlowPaths(true); - host_impl_->SetContentHasNonAAPaint(false); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); + recording_source->set_has_non_aa_paint(false); + recording_source->Rerecord(); + EXPECT_TRUE(host_impl_->can_use_msaa()); + EXPECT_GT(host_impl_->GetMSAASampleCountForRaster( + recording_source->GetDisplayItemList()), + 0); // Ensure that without non-aa paint and with multisample compatibility, we // raster slow paths with msaa. CreateHostImplWithMultisampleCompatibility(true); - host_impl_->SetContentHasSlowPaths(true); - host_impl_->SetContentHasNonAAPaint(false); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); + recording_source->set_has_non_aa_paint(false); + recording_source->Rerecord(); + EXPECT_TRUE(host_impl_->can_use_msaa()); + EXPECT_GT(host_impl_->GetMSAASampleCountForRaster( + recording_source->GetDisplayItemList()), + 0); // Ensure that with non-aa paint and without multisample compatibility, we do // not raster slow paths with msaa. CreateHostImplWithMultisampleCompatibility(false); - host_impl_->SetContentHasSlowPaths(true); - host_impl_->SetContentHasNonAAPaint(true); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); + recording_source->set_has_non_aa_paint(true); + recording_source->Rerecord(); + EXPECT_TRUE(host_impl_->can_use_msaa()); + EXPECT_EQ(host_impl_->GetMSAASampleCountForRaster( + recording_source->GetDisplayItemList()), + 0); // Ensure that with non-aa paint and with multisample compatibility, we raster // slow paths with msaa. CreateHostImplWithMultisampleCompatibility(true); - host_impl_->SetContentHasSlowPaths(true); - host_impl_->SetContentHasNonAAPaint(true); - host_impl_->CommitComplete(); - EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT, - host_impl_->gpu_rasterization_status()); - EXPECT_TRUE(host_impl_->use_gpu_rasterization()); + recording_source->set_has_non_aa_paint(true); + recording_source->Rerecord(); + EXPECT_TRUE(host_impl_->can_use_msaa()); + EXPECT_GT(host_impl_->GetMSAASampleCountForRaster( + recording_source->GetDisplayItemList()), + 0); } TEST_F(LayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) { // Check page scale factor update in property trees when an update is made // on the active tree. CreatePendingTree(); - host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 3.f); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1, 1, 3); SetupViewportLayers(host_impl_->pending_tree(), gfx::Size(50, 50), gfx::Size(100, 100), gfx::Size(100, 100)); host_impl_->ActivateSyncTree(); DrawFrame(); CreatePendingTree(); - host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(2); TransformNode* active_tree_node = host_impl_->active_tree()->PageScaleTransformNode(); // SetPageScaleOnActiveTree also updates the factors in property trees. EXPECT_TRUE(active_tree_node->local.IsScale2d()); - EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), active_tree_node->local.Scale2d()); + EXPECT_EQ(gfx::Vector2dF(2, 2), active_tree_node->local.Scale2d()); EXPECT_EQ(gfx::Point3F(), active_tree_node->origin); - EXPECT_EQ(2.f, host_impl_->active_tree()->current_page_scale_factor()); + EXPECT_EQ(2, host_impl_->active_tree()->current_page_scale_factor()); TransformNode* pending_tree_node = host_impl_->pending_tree()->PageScaleTransformNode(); @@ -12109,30 +12214,30 @@ TEST_F(LayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) { // shared data between the active and pending trees. EXPECT_TRUE(pending_tree_node->local.IsIdentity()); EXPECT_EQ(gfx::Point3F(), pending_tree_node->origin); - EXPECT_EQ(2.f, host_impl_->pending_tree()->current_page_scale_factor()); - EXPECT_EQ(1.f, host_impl_->pending_tree() - ->property_trees() - ->transform_tree.page_scale_factor()); + EXPECT_EQ(2, host_impl_->pending_tree()->current_page_scale_factor()); + EXPECT_EQ(1, host_impl_->pending_tree() + ->property_trees() + ->transform_tree.page_scale_factor()); host_impl_->pending_tree()->set_needs_update_draw_properties(); UpdateDrawProperties(host_impl_->pending_tree()); pending_tree_node = host_impl_->pending_tree()->PageScaleTransformNode(); EXPECT_TRUE(pending_tree_node->local.IsScale2d()); - EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), pending_tree_node->local.Scale2d()); + EXPECT_EQ(gfx::Vector2dF(2, 2), pending_tree_node->local.Scale2d()); EXPECT_EQ(gfx::Point3F(), pending_tree_node->origin); host_impl_->ActivateSyncTree(); UpdateDrawProperties(host_impl_->active_tree()); active_tree_node = host_impl_->active_tree()->PageScaleTransformNode(); EXPECT_TRUE(active_tree_node->local.IsScale2d()); - EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), active_tree_node->local.Scale2d()); + EXPECT_EQ(gfx::Vector2dF(2, 2), active_tree_node->local.Scale2d()); EXPECT_EQ(gfx::Point3F(), active_tree_node->origin); } TEST_F(LayerTreeHostImplTest, SubLayerScaleForNodeInSubtreeOfPageScaleLayer) { // Checks that the sublayer scale of a transform node in the subtree of the // page scale layer is updated without a property tree rebuild. - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 3.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 1, 3); SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); LayerImpl* in_subtree_of_page_scale_layer = AddLayer(); CopyProperties(root_layer(), in_subtree_of_page_scale_layer); @@ -12144,14 +12249,14 @@ TEST_F(LayerTreeHostImplTest, SubLayerScaleForNodeInSubtreeOfPageScaleLayer) { DrawFrame(); EffectNode* node = GetEffectNode(in_subtree_of_page_scale_layer); - EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1.f, 1.f)); + EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(1, 1)); - host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(2); DrawFrame(); node = GetEffectNode(in_subtree_of_page_scale_layer); - EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(2.f, 2.f)); + EXPECT_EQ(node->surface_contents_scale, gfx::Vector2dF(2, 2)); } // Checks that if we lose a GPU raster enabled LayerTreeFrameSink and replace @@ -12392,7 +12497,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates( // scrollbar_2_animation_controller, then mouse up should not cause crash. host_impl_->MouseMoveAt(gfx::Point(40, 150)); host_impl_->MouseDown(gfx::PointF(40, 150), /*shift_modifier*/ false); - host_impl_->UnregisterScrollbarAnimationController(root_scroll->element_id()); + host_impl_->DidUnregisterScrollbarLayer(root_scroll->element_id()); host_impl_->MouseUp(gfx::PointF(40, 150)); } @@ -12529,7 +12634,7 @@ TEST_F(LayerTreeHostImplTest, UpdatedTilingsForNonDrawingLayers) { host_impl_->pending_tree()->SetElementIdsForTesting(); gfx::Transform singular; - singular.Scale3d(6.f, 6.f, 0.f); + singular.Scale3d(6, 6, 0); CopyProperties(root, animated_transform_layer); CreateTransformNode(animated_transform_layer).local = singular; @@ -12646,35 +12751,21 @@ TEST_F(LayerTreeHostImplTest, DrawAfterDroppingTileResources) { DrawFrame(); EXPECT_FALSE(host_impl_->active_tree()->needs_update_draw_properties()); - EXPECT_LT(0.f, layer->raster_page_scale()); + EXPECT_LT(0, layer->raster_page_scale()); EXPECT_GT(layer->tilings()->num_tilings(), 0u); const ManagedMemoryPolicy policy = host_impl_->ActualManagedMemoryPolicy(); const ManagedMemoryPolicy zero_policy(0u); host_impl_->SetMemoryPolicy(zero_policy); - EXPECT_EQ(0.f, layer->raster_page_scale()); + EXPECT_EQ(0, layer->raster_page_scale()); EXPECT_EQ(layer->tilings()->num_tilings(), 0u); host_impl_->SetMemoryPolicy(policy); DrawFrame(); - EXPECT_LT(0.f, layer->raster_page_scale()); + EXPECT_LT(0, layer->raster_page_scale()); EXPECT_GT(layer->tilings()->num_tilings(), 0u); } -TEST_F(LayerTreeHostImplTest, NeedUpdateGpuRasterization) { - EXPECT_FALSE(host_impl_->NeedUpdateGpuRasterizationStatusForTesting()); - - host_impl_->SetContentHasSlowPaths(true); - EXPECT_TRUE(host_impl_->NeedUpdateGpuRasterizationStatusForTesting()); - host_impl_->CommitComplete(); - EXPECT_FALSE(host_impl_->NeedUpdateGpuRasterizationStatusForTesting()); - - host_impl_->SetContentHasNonAAPaint(true); - EXPECT_TRUE(host_impl_->NeedUpdateGpuRasterizationStatusForTesting()); - host_impl_->CommitComplete(); - EXPECT_FALSE(host_impl_->NeedUpdateGpuRasterizationStatusForTesting()); -} - TEST_F(LayerTreeHostImplTest, WhiteListedTouchActionTest1) { WhiteListedTouchActionTestHelper(1.0f, 1.0f); } @@ -12726,20 +12817,20 @@ class TestRenderFrameMetadataObserver : public RenderFrameMetadataObserver { TEST_F(LayerTreeHostImplTest, RenderFrameMetadata) { SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); host_impl_->active_tree()->SetDeviceViewportRect(gfx::Rect(50, 50)); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1, 0.5f, 4); { // Check initial metadata is correct. RenderFrameMetadata metadata = StartDrawAndProduceRenderFrameMetadata(); EXPECT_EQ(gfx::Vector2dF(), metadata.root_scroll_offset); - EXPECT_EQ(1.f, metadata.page_scale_factor); + EXPECT_EQ(1, metadata.page_scale_factor); #if defined(OS_ANDROID) - EXPECT_EQ(gfx::SizeF(50.f, 50.f), metadata.scrollable_viewport_size); + EXPECT_EQ(gfx::SizeF(50, 50), metadata.scrollable_viewport_size); EXPECT_EQ(0.5f, metadata.min_page_scale_factor); - EXPECT_EQ(4.f, metadata.max_page_scale_factor); - EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size); + EXPECT_EQ(4, metadata.max_page_scale_factor); + EXPECT_EQ(gfx::SizeF(100, 100), metadata.root_layer_size); EXPECT_FALSE(metadata.root_overflow_y_hidden); #endif } @@ -12748,17 +12839,18 @@ TEST_F(LayerTreeHostImplTest, RenderFrameMetadata) { EXPECT_EQ( InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL) + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10)).get(), + InputHandler::WHEEL) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); { RenderFrameMetadata metadata = StartDrawAndProduceRenderFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); } - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); { RenderFrameMetadata metadata = StartDrawAndProduceRenderFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); } #if defined(OS_ANDROID) @@ -12811,41 +12903,41 @@ TEST_F(LayerTreeHostImplTest, RenderFrameMetadata) { #endif // Page scale should update metadata correctly (shrinking only the viewport). - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), + host_impl_->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); - host_impl_->PinchGestureUpdate(2.f, gfx::Point()); + host_impl_->PinchGestureUpdate(2, gfx::Point()); host_impl_->PinchGestureEnd(gfx::Point(), true); - host_impl_->ScrollEnd(EndState().get()); + host_impl_->ScrollEnd(); { RenderFrameMetadata metadata = StartDrawAndProduceRenderFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); - EXPECT_EQ(2.f, metadata.page_scale_factor); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); + EXPECT_EQ(2, metadata.page_scale_factor); #if defined(OS_ANDROID) - EXPECT_EQ(gfx::SizeF(25.f, 25.f), metadata.scrollable_viewport_size); + EXPECT_EQ(gfx::SizeF(25, 25), metadata.scrollable_viewport_size); EXPECT_EQ(0.5f, metadata.min_page_scale_factor); - EXPECT_EQ(4.f, metadata.max_page_scale_factor); - EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size); + EXPECT_EQ(4, metadata.max_page_scale_factor); + EXPECT_EQ(gfx::SizeF(100, 100), metadata.root_layer_size); #endif } // Likewise if set from the main thread. host_impl_->ProcessScrollDeltas(); - host_impl_->active_tree()->PushPageScaleFromMainThread(4.f, 0.5f, 4.f); - host_impl_->active_tree()->SetPageScaleOnActiveTree(4.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(4, 0.5f, 4); + host_impl_->active_tree()->SetPageScaleOnActiveTree(4); { RenderFrameMetadata metadata = StartDrawAndProduceRenderFrameMetadata(); - EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); - EXPECT_EQ(4.f, metadata.page_scale_factor); + EXPECT_EQ(gfx::Vector2dF(0, 10), metadata.root_scroll_offset); + EXPECT_EQ(4, metadata.page_scale_factor); #if defined(OS_ANDROID) EXPECT_EQ(gfx::SizeF(12.5f, 12.5f), metadata.scrollable_viewport_size); EXPECT_EQ(0.5f, metadata.min_page_scale_factor); - EXPECT_EQ(4.f, metadata.max_page_scale_factor); - EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size); + EXPECT_EQ(4, metadata.max_page_scale_factor); + EXPECT_EQ(gfx::SizeF(100, 100), metadata.root_layer_size); #endif } } @@ -12870,19 +12962,19 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToRenderFrameMetadata) { observer_ptr->last_metadata()->selection; EXPECT_EQ(gfx::SelectionBound::EMPTY, selection_1.start.type()); EXPECT_EQ(gfx::SelectionBound::EMPTY, selection_1.end.type()); - EXPECT_EQ(gfx::PointF(), selection_1.start.edge_bottom()); - EXPECT_EQ(gfx::PointF(), selection_1.start.edge_top()); + EXPECT_EQ(gfx::PointF(), selection_1.start.edge_end()); + EXPECT_EQ(gfx::PointF(), selection_1.start.edge_start()); EXPECT_FALSE(selection_1.start.visible()); EXPECT_FALSE(selection_1.end.visible()); // Plumb the layer-local selection bounds. - gfx::Point selection_top(5, 0); - gfx::Point selection_bottom(5, 5); + gfx::Point selection_start(5, 0); + gfx::Point selection_end(5, 5); LayerSelection selection; selection.start.type = gfx::SelectionBound::CENTER; selection.start.layer_id = root->id(); - selection.start.edge_bottom = selection_bottom; - selection.start.edge_top = selection_top; + selection.start.edge_end = selection_end; + selection.start.edge_start = selection_start; selection.end = selection.start; host_impl_->active_tree()->RegisterSelection(selection); @@ -12896,12 +12988,96 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToRenderFrameMetadata) { observer_ptr->last_metadata()->selection; EXPECT_EQ(selection.start.type, selection_2.start.type()); EXPECT_EQ(selection.end.type, selection_2.end.type()); - EXPECT_EQ(gfx::PointF(selection_bottom), selection_2.start.edge_bottom()); - EXPECT_EQ(gfx::PointF(selection_top), selection_2.start.edge_top()); + EXPECT_EQ(gfx::PointF(selection_end), selection_2.start.edge_end()); + EXPECT_EQ(gfx::PointF(selection_start), selection_2.start.edge_start()); EXPECT_TRUE(selection_2.start.visible()); EXPECT_TRUE(selection_2.end.visible()); } +TEST_F(LayerTreeHostImplTest, + VerticalScrollDirectionChangesPassedToRenderFrameMetadata) { + // Set up the viewport. + SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100)); + host_impl_->active_tree()->SetDeviceViewportRect(gfx::Rect(50, 50)); + + // Set up the render frame metadata observer. + auto observer = std::make_unique<TestRenderFrameMetadataObserver>(false); + auto* observer_ptr = observer.get(); + host_impl_->SetRenderFrameObserver(std::move(observer)); + EXPECT_FALSE(observer_ptr->last_metadata()); + + // Our test will be comprised of multiple legs, each leg consisting of a + // distinct scroll event and an expectation regarding the vertical scroll + // direction passed to the render frame metadata. + typedef struct { + gfx::Vector2d scroll_delta; + viz::VerticalScrollDirection expected_vertical_scroll_direction; + } TestLeg; + + std::vector<TestLeg> test_legs; + + // Initially, vertical scroll direction should be |kNull| indicating absence. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kNull}); + + // Scrolling to the right should not affect vertical scroll direction. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(10, 0), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kNull}); + + // After scrolling down, the vertical scroll direction should be |kDown|. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(0, 10), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kDown}); + + // If we scroll down again, the vertical scroll direction should be |kNull| as + // there was no change in vertical scroll direction. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(0, 10), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kNull}); + + // Scrolling to the left should not affect last vertical scroll direction. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(-10, 0), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kNull}); + + // After scrolling up, the vertical scroll direction should be |kUp|. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(0, -10), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kUp}); + + // If we scroll up again, the vertical scroll direction should be |kNull| as + // there was no change in vertical scroll direction. + test_legs.push_back({/*scroll_delta=*/gfx::Vector2d(0, -10), + /*expected_vertical_scroll_direction=*/viz:: + VerticalScrollDirection::kNull}); + + // Iterate over all legs of our test. + for (auto& test_leg : test_legs) { + // If the test leg contains a scroll, perform it. + if (!test_leg.scroll_delta.IsZero()) { + host_impl_->ScrollBegin( + BeginState(gfx::Point(), test_leg.scroll_delta).get(), + InputHandler::WHEEL); + host_impl_->ScrollBy( + UpdateState(gfx::Point(), test_leg.scroll_delta).get()); + } + + // Trigger draw. + host_impl_->SetNeedsRedraw(); + DrawFrame(); + + // Assert our expectation regarding the vertical scroll direction. + EXPECT_EQ(test_leg.expected_vertical_scroll_direction, + observer_ptr->last_metadata()->new_vertical_scroll_direction); + + // If the test leg contains a scroll, end it. + if (!test_leg.scroll_delta.IsZero()) + host_impl_->ScrollEnd(); + } +} + // Tests ScrollBy() to see if the method sets the scroll tree's currently // scrolling node and the ScrollState properly. TEST_F(LayerTreeHostImplTest, ScrollByScrollingNode) { @@ -12918,7 +13094,7 @@ TEST_F(LayerTreeHostImplTest, ScrollByScrollingNode) { EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_ - ->ScrollBegin(BeginState(gfx::Point()).get(), + ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF()).get(), InputHandler::TOUCHSCREEN) .thread); @@ -12958,37 +13134,11 @@ class HitTestRegionListGeneratingLayerTreeHostImplTest std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink) override { // Enable hit test data generation with the CompositorFrame. LayerTreeSettings new_settings = settings; - new_settings.build_hit_test_data = true; return LayerTreeHostImplTest::CreateHostImpl( new_settings, std::move(layer_tree_frame_sink)); } }; -// When disabled, no HitTestRegionList should be generated. -// Test to ensure that hit test data is created correctly from the active layer -// tree. -TEST_F(LayerTreeHostImplTest, DisabledBuildHitTestData) { - // Setup surface layers in LayerTreeHostImpl. - host_impl_->CreatePendingTree(); - host_impl_->ActivateSyncTree(); - - auto* root = SetupDefaultRootLayer(gfx::Size(1024, 768)); - auto* surface_child = AddLayer<SurfaceLayerImpl>(host_impl_->active_tree()); - - surface_child->SetBounds(gfx::Size(100, 100)); - surface_child->SetDrawsContent(true); - surface_child->SetSurfaceHitTestable(true); - - CopyProperties(root, surface_child); - surface_child->SetOffsetToTransformParent(gfx::Vector2dF(50, 50)); - - UpdateDrawProperties(host_impl_->active_tree()); - - base::Optional<viz::HitTestRegionList> hit_test_region_list = - host_impl_->BuildHitTestData(); - EXPECT_FALSE(hit_test_region_list); -} - // Test to ensure that hit test data is created correctly from the active layer // tree. TEST_F(HitTestRegionListGeneratingLayerTreeHostImplTest, BuildHitTestData) { @@ -13361,9 +13511,9 @@ TEST_F(LayerTreeHostImplTest, TouchScrollOnAndroidScrollbar) { gfx::Size scroll_content_size = gfx::Size(360, 3800); gfx::Size scrollbar_size = gfx::Size(15, 600); - LayerImpl* root = SetupDefaultRootLayer(viewport_size); - LayerImpl* content = - AddScrollableLayer(root, viewport_size, scroll_content_size); + SetupViewportLayersNoScrolls(viewport_size); + LayerImpl* content = AddScrollableLayer(OuterViewportScrollLayer(), + viewport_size, scroll_content_size); auto* scrollbar = AddLayer<SolidColorScrollbarLayerImpl>( layer_tree_impl, VERTICAL, 10, 0, false); @@ -13378,7 +13528,8 @@ TEST_F(LayerTreeHostImplTest, TouchScrollOnAndroidScrollbar) { // should result in scrolling the scroll layer on the impl thread as the // scrollbar should not be hit. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point(350, 50)).get(), InputHandler::TOUCHSCREEN); + BeginState(gfx::Point(350, 50), gfx::Vector2dF(0, 10)).get(), + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); } diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc index 4af1f35d30f..aab9ee9f75f 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -77,7 +77,7 @@ LayerTreeTest::RendererType const kRendererTypes[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostFiltersPixelTest, ::testing::ValuesIn(kRendererTypes)); @@ -91,7 +91,7 @@ LayerTreeTest::RendererType const kRendererTypesGpu[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostFiltersPixelTestGPU, ::testing::ValuesIn(kRendererTypesGpu)); @@ -221,21 +221,24 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) { 16, 18, 20, 22, 30, 40, 50); blur->SetBackdropFilterBounds(backdrop_filter_bounds); -#if defined(OS_WIN) || defined(ARCH_CPU_ARM64) - // Windows and ARM64 have 436 pixels off by 1: crbug.com/259915 - float percentage_pixels_large_error = 1.09f; // 436px / (200*200) - float percentage_pixels_small_error = 0.0f; - float average_error_allowed_in_bad_pixels = 1.f; - int large_error_allowed = 1; - int small_error_allowed = 0; + // Skia has various algorithms for clipping by a path, depending on the + // available hardware, including MSAA techniques. MSAA results vary + // substantially by platform; with 4x MSAA, a difference of 1 sample can + // cause up to a 25% color difference! + // See http://crbug.com/259915 + int small_error_threshold = 64; // 25% of 255. + // Allow for ~1 perimeter of the clip path to have a small error. + float percentage_pixels_small_error = 100.f * (100*4) / (200*200); + int large_error_limit = 128; // Off by two samples in 4 MSAA. + float percentage_pixels_large_or_small_error = + 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( true, // discard_alpha - percentage_pixels_large_error, percentage_pixels_small_error, - average_error_allowed_in_bad_pixels, large_error_allowed, - small_error_allowed)); -#else - pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false); -#endif + percentage_pixels_large_or_small_error, percentage_pixels_small_error, + average_error_allowed_in_bad_pixels, large_error_limit, + small_error_threshold)); RunPixelTest(renderer_type(), background, (renderer_type() == RENDERER_SOFTWARE) @@ -246,11 +249,6 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) { } TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOutsets) { - if (renderer_type() == RENDERER_SKIA_GL || - renderer_type() == RENDERER_SKIA_VK) { - // TODO(973696): Implement bounds clipping in skia_renderer. - return; - } scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); @@ -469,7 +467,7 @@ class LayerTreeHostFiltersScaledPixelTest float device_scale_factor_; }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostFiltersScaledPixelTest, ::testing::ValuesIn(kRendererTypes)); @@ -1150,7 +1148,7 @@ class BackdropFilterOffsetTest : public LayerTreeHostFiltersPixelTest { float device_scale_factor_ = 1; }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, BackdropFilterOffsetTest, ::testing::ValuesIn(kRendererTypes)); @@ -1197,7 +1195,7 @@ class BackdropFilterInvertTest : public LayerTreeHostFiltersPixelTest { float device_scale_factor_ = 1; }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, BackdropFilterInvertTest, ::testing::ValuesIn(kRendererTypes)); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc b/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc index ed011f43887..86b14635524 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_mirror.cc @@ -31,7 +31,7 @@ const LayerTreeTest::RendererType kRendererTypes[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostMirrorPixelTest, ::testing::ValuesIn(kRendererTypes)); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc index 345dc9cab6b..416d19d0351 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc @@ -429,7 +429,7 @@ ReadbackTestConfig const kTestConfigs[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostReadbackPixelTest, ::testing::ValuesIn(kTestConfigs)); @@ -447,7 +447,7 @@ ReadbackTestConfig const kMaybeVulkanTestConfigs[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostReadbackPixelTestMaybeVulkan, ::testing::ValuesIn(kMaybeVulkanTestConfigs)); @@ -531,7 +531,7 @@ TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackNonRootLayerSubrect) { base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostReadbackDeviceScalePixelTest, ::testing::ValuesIn(kTestConfigs)); @@ -571,7 +571,7 @@ TEST_P(LayerTreeHostReadbackColorSpacePixelTest, Readback) { base::FilePath(FILE_PATH_LITERAL("srgb_green_in_p3.png"))); } -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostReadbackColorSpacePixelTest, ::testing::ValuesIn(kTestConfigs)); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc index 4be54575240..d9e1ec67ee4 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc @@ -50,12 +50,14 @@ class PaintedScrollbar : public FakeScrollbar { set_track_rect(gfx::Rect(size)); } - void PaintPart(PaintCanvas* canvas, ScrollbarPart part) override { + void PaintPart(PaintCanvas* canvas, + ScrollbarPart part, + const gfx::Rect& rect) override { PaintFlags flags; flags.setStyle(PaintFlags::kStroke_Style); flags.setStrokeWidth(SkIntToScalar(paint_scale_)); flags.setColor(color_); - gfx::Rect inset_rect = GetPartRect(part); + gfx::Rect inset_rect = rect; while (!inset_rect.IsEmpty()) { int big = paint_scale_ + 2; int small = paint_scale_; @@ -68,6 +70,8 @@ class PaintedScrollbar : public FakeScrollbar { void set_paint_scale(int scale) { paint_scale_ = scale; } private: + ~PaintedScrollbar() override = default; + int paint_scale_ = 4; SkColor color_ = SK_ColorGREEN; }; @@ -80,7 +84,7 @@ LayerTreeTest::RendererType const kRendererTypes[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostScrollbarsPixelTest, ::testing::ValuesIn(kRendererTypes)); @@ -88,7 +92,7 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, NoScale) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); - auto scrollbar = std::make_unique<PaintedScrollbar>(gfx::Size(200, 200)); + auto scrollbar = base::MakeRefCounted<PaintedScrollbar>(gfx::Size(200, 200)); scoped_refptr<PaintedScrollbarLayer> layer = PaintedScrollbarLayer::Create(std::move(scrollbar)); layer->SetIsDrawable(true); @@ -107,7 +111,7 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, DeviceScaleFactor) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE); - auto scrollbar = std::make_unique<PaintedScrollbar>(gfx::Size(100, 100)); + auto scrollbar = base::MakeRefCounted<PaintedScrollbar>(gfx::Size(100, 100)); scoped_refptr<PaintedScrollbarLayer> layer = PaintedScrollbarLayer::Create(std::move(scrollbar)); layer->SetIsDrawable(true); @@ -122,7 +126,7 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, TransformScale) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); - auto scrollbar = std::make_unique<PaintedScrollbar>(gfx::Size(100, 100)); + auto scrollbar = base::MakeRefCounted<PaintedScrollbar>(gfx::Size(100, 100)); scoped_refptr<PaintedScrollbarLayer> layer = PaintedScrollbarLayer::Create(std::move(scrollbar)); layer->SetIsDrawable(true); @@ -149,7 +153,7 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE); - auto scrollbar = std::make_unique<PaintedScrollbar>(gfx::Size(10, 400)); + auto scrollbar = base::MakeRefCounted<PaintedScrollbar>(gfx::Size(10, 400)); scrollbar->set_paint_scale(1); scoped_refptr<PaintedScrollbarLayer> layer = PaintedScrollbarLayer::Create(std::move(scrollbar)); @@ -210,12 +214,13 @@ class PaintedOverlayScrollbar : public FakeScrollbar { VERTICAL, /*is_left_side_vertical_scrollbar*/ false, /*is_overlay*/ true) { - set_thumb_thickness(15); - set_thumb_length(50); + set_thumb_size(gfx::Size(15, 50)); set_track_rect(gfx::Rect(0, 0, 15, 400)); } - void PaintPart(PaintCanvas* canvas, ScrollbarPart part) override { + void PaintPart(PaintCanvas* canvas, + ScrollbarPart part, + const gfx::Rect& rect) override { // The outside of the rect will be painted with a 1 pixel black, red, then // blue border. The inside will be solid blue. This will allow the test to // ensure that scaling the thumb doesn't scale the border at all. Note @@ -226,7 +231,7 @@ class PaintedOverlayScrollbar : public FakeScrollbar { flags.setStrokeWidth(SkIntToScalar(1)); flags.setColor(SK_ColorBLACK); - gfx::Rect inset_rect = GetPartRect(part); + gfx::Rect inset_rect = rect; canvas->drawRect(RectToSkRect(inset_rect), flags); flags.setColor(SK_ColorRED); @@ -245,9 +250,12 @@ class PaintedOverlayScrollbar : public FakeScrollbar { gfx::Rect NinePatchThumbAperture() const override { return gfx::Rect(3, 3, 1, 1); } + + private: + ~PaintedOverlayScrollbar() override = default; }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostOverlayScrollbarsPixelTest, ::testing::ValuesIn(kRendererTypes)); @@ -257,7 +265,7 @@ TEST_P(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE); - auto scrollbar = std::make_unique<PaintedOverlayScrollbar>(); + auto scrollbar = base::MakeRefCounted<PaintedOverlayScrollbar>(); scoped_refptr<PaintedOverlayScrollbarLayer> layer = PaintedOverlayScrollbarLayer::Create(std::move(scrollbar)); @@ -281,7 +289,7 @@ TEST_P(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledDown) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE); - auto scrollbar = std::make_unique<PaintedOverlayScrollbar>(); + auto scrollbar = base::MakeRefCounted<PaintedOverlayScrollbar>(); scoped_refptr<PaintedOverlayScrollbarLayer> layer = PaintedOverlayScrollbarLayer::Create(std::move(scrollbar)); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc index 7b3f854f7f9..713d41e50d4 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc @@ -63,7 +63,7 @@ LayerTreeTest::RendererType const kRendererTypesGpu[] = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostSynchronousPixelTest, ::testing::ValuesIn(kRendererTypesGpu)); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc index 8e27a3ef68b..7ddfc099cc5 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc @@ -186,7 +186,7 @@ std::vector<TilesTestConfig> const kTestCases = { #endif }; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostTilesTestPartialInvalidation, ::testing::ValuesIn(kTestCases)); @@ -214,7 +214,7 @@ std::vector<TilesTestConfig> const kTestCasesMultiThread = { using LayerTreeHostTilesTestPartialInvalidationMultiThread = LayerTreeHostTilesTestPartialInvalidation; -INSTANTIATE_TEST_SUITE_P(, +INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostTilesTestPartialInvalidationMultiThread, ::testing::ValuesIn(kTestCasesMultiThread)); @@ -244,7 +244,7 @@ using LayerTreeHostTilesTestPartialInvalidationLowBitDepth = // RGBA4444 format using either SwiftShader or native Vulkan. See // crbug.com/987278 for details INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostTilesTestPartialInvalidationLowBitDepth, ::testing::Values( TilesTestConfig{LayerTreeTest::RENDERER_GL, GPU_LOW_BIT_DEPTH}, diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc index 03d02988fce..0c93511d76c 100644 --- a/chromium/cc/trees/layer_tree_host_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest.cc @@ -1139,7 +1139,6 @@ class LayerTreeHostTestSurfaceDamage : public LayerTreeHostTest { case 3: EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged()); EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged()); - EndTest(); PostSetNeedsCommitToMainThread(); break; case 4: @@ -1158,8 +1157,7 @@ class LayerTreeHostTestSurfaceDamage : public LayerTreeHostTest { scoped_refptr<Layer> grand_child_; }; -// TODO(crbug.com/1014263): Disable because this test is flaky. -// SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSurfaceDamage); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSurfaceDamage); class LayerTreeHostTestLayerListSurfaceDamage : public LayerTreeHostTest { protected: @@ -6161,19 +6159,13 @@ class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest { } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - EXPECT_FALSE(layer_->HasSlowPaths()); - EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization()); EXPECT_FALSE(host_impl->use_gpu_rasterization()); - EXPECT_FALSE(host_impl->use_msaa()); } void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { - EXPECT_FALSE(layer_->HasSlowPaths()); - EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization()); EXPECT_FALSE(host_impl->use_gpu_rasterization()); - EXPECT_FALSE(host_impl->use_msaa()); EndTest(); } @@ -6239,17 +6231,19 @@ class LayerTreeHostTestGpuRasterizationEnabled void BeginTest() override { PostSetNeedsCommitToMainThread(); } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - EXPECT_FALSE(layer_->HasSlowPaths()); + auto* raster_source = static_cast<PictureLayerImpl*>( + host_impl->sync_tree()->LayerById(layer_->id())) + ->GetRasterSource(); + EXPECT_EQ(host_impl->GetMSAASampleCountForRaster( + raster_source->GetDisplayItemList()), + 0); EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); - EXPECT_FALSE(host_impl->use_msaa()); } void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { - EXPECT_FALSE(layer_->HasSlowPaths()); EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); - EXPECT_FALSE(host_impl->use_msaa()); EndTest(); } }; @@ -6261,7 +6255,7 @@ class LayerTreeHostTestGpuRasterizationEnabledWithMSAA protected: void BeginTest() override { // Content-based MSAA trigger. - layer_->set_force_content_has_slow_paths(true); + layer_client_.set_contains_slow_paths(true); // MSAA trigger will take effect when layers are updated. // The results will be verified after commit is completed below. @@ -6272,125 +6266,20 @@ class LayerTreeHostTestGpuRasterizationEnabledWithMSAA } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - // Ensure the slow path bit sticks. - EXPECT_TRUE(layer_->HasSlowPaths()); - + auto* raster_source = static_cast<PictureLayerImpl*>( + host_impl->sync_tree()->LayerById(layer_->id())) + ->GetRasterSource(); + EXPECT_GT(host_impl->GetMSAASampleCountForRaster( + raster_source->GetDisplayItemList()), + 0); EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); - EXPECT_TRUE(host_impl->use_msaa()); - } - - void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { - EXPECT_TRUE(layer_->HasSlowPaths()); - - EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization()); - EXPECT_TRUE(host_impl->use_gpu_rasterization()); - EXPECT_TRUE(host_impl->use_msaa()); EndTest(); } }; MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabledWithMSAA); -class LayerTreeHostTestGpuRasterizationMSAAReenabled - : public LayerTreeHostWithGpuRasterizationSupportedTest { - protected: - void InitializeSettings(LayerTreeSettings* settings) override { - settings->gpu_rasterization_msaa_sample_count = 4; - } - - void BeginTest() override { - // Content-based MSAA trigger is relevant. - layer_->set_force_content_has_slow_paths(true); - - // MSAA trigger will take effect when layers are updated. - // The results will be verified after commit is completed below. - // Since we are manually marking the source as containing slow paths, - // make sure that the layer gets a chance to update. - layer_->SetNeedsDisplay(); - PostSetNeedsCommitToMainThread(); - } - - void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - SCOPED_TRACE(base::StringPrintf("commit %d", num_commits_)); - if (expected_use_msaa_) { - EXPECT_TRUE(host_impl->use_msaa()); - } else { - EXPECT_FALSE(host_impl->use_msaa()); - } - - ++num_commits_; - switch (num_commits_) { - case 1: - layer_->set_force_content_has_slow_paths(false); - break; - case 30: - layer_->set_force_content_has_slow_paths(true); - break; - case 31: - layer_->set_force_content_has_slow_paths(false); - break; - case 90: - expected_use_msaa_ = false; - break; - } - PostSetNeedsCommitToMainThread(); - if (num_commits_ > 100) - EndTest(); - } - - int num_commits_ = 0; - bool expected_use_msaa_ = true; -}; - -MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationMSAAReenabled); - -class LayerTreeHostTestGpuRasterizationNonAASticky - : public LayerTreeHostWithGpuRasterizationSupportedTest { - protected: - void InitializeSettings(LayerTreeSettings* settings) override { - settings->gpu_rasterization_msaa_sample_count = 4; - } - - void BeginTest() override { - // Start without slow paths, but no non-aa paint. - layer_->set_force_content_has_slow_paths(true); - layer_->set_force_content_has_non_aa_paint(false); - - // The results will be verified after commit is completed below. - layer_->SetNeedsDisplay(); - PostSetNeedsCommitToMainThread(); - } - - void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - SCOPED_TRACE(base::StringPrintf("commit %d", num_commits_)); - if (expected_use_msaa_) { - EXPECT_TRUE(host_impl->use_msaa()); - } else { - EXPECT_FALSE(host_impl->use_msaa()); - } - - ++num_commits_; - switch (num_commits_) { - case 30: - layer_->set_force_content_has_non_aa_paint(true); - expected_use_msaa_ = false; - break; - case 31: - layer_->set_force_content_has_non_aa_paint(false); - break; - } - PostSetNeedsCommitToMainThread(); - if (num_commits_ > 100) - EndTest(); - } - - int num_commits_ = 0; - bool expected_use_msaa_ = true; -}; - -MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationNonAASticky); - class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest { protected: void InitializeSettings(LayerTreeSettings* settings) override { @@ -6417,9 +6306,6 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest { } void BeginTest() override { - // Content-based MSAA trigger is irrelevant as well. - layer_->set_force_content_has_slow_paths(true); - // Veto will take effect when layers are updated. // The results will be verified after commit is completed below. // Since we are manually marking the source as containing slow paths, @@ -6429,16 +6315,11 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest { } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - // Ensure the slow-paths bit sticks. - EXPECT_TRUE(layer_->HasSlowPaths()); - EXPECT_TRUE(host_impl->sync_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); } void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { - EXPECT_TRUE(layer_->HasSlowPaths()); - EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); EndTest(); @@ -6844,7 +6725,7 @@ class LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { EXPECT_EQ(info_.page_scale_delta, args.page_scale_delta); - EXPECT_EQ(info_.top_controls_delta, args.browser_controls_delta); + EXPECT_EQ(info_.top_controls_delta, args.top_controls_delta); EXPECT_EQ(info_.browser_controls_constraint, args.browser_controls_constraint); deltas_sent_to_client_ = true; @@ -8771,9 +8652,11 @@ class LayerTreeHostTopControlsDeltaTriggersViewportUpdate SetupViewport(root_layer, gfx::Size(50, 50), root_layer->bounds()); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 1.f); // Set browser controls to be partially shown. - layer_tree_host()->SetBrowserControlsHeight(kTopControlsHeight, 0.0f, - true /* shrink */); - layer_tree_host()->SetBrowserControlsShownRatio(kTopControlsShownRatio); + layer_tree_host()->SetBrowserControlsParams( + {kTopControlsHeight, 0, kBottomControlsHeight, 0, false /* animate */, + true /* shrink */}); + layer_tree_host()->SetBrowserControlsShownRatio(kTopControlsShownRatio, + kBottomControlsShownRatio); } void BeginCommitOnThread(LayerTreeHostImpl* impl) override { @@ -8800,6 +8683,8 @@ class LayerTreeHostTopControlsDeltaTriggersViewportUpdate static constexpr float kTopControlsHeight = 10.0f; static constexpr float kTopControlsShownRatio = 0.3f; + static constexpr float kBottomControlsHeight = 10.0f; + static constexpr float kBottomControlsShownRatio = 1.f; }; MULTI_THREAD_TEST_F(LayerTreeHostTopControlsDeltaTriggersViewportUpdate); diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc index a21e88e65bb..8d49e947ff9 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc @@ -15,6 +15,7 @@ #include "cc/animation/element_animations.h" #include "cc/animation/keyframe_effect.h" #include "cc/animation/scroll_offset_animation_curve.h" +#include "cc/animation/scroll_offset_animation_curve_factory.h" #include "cc/animation/scroll_offset_animations.h" #include "cc/animation/single_keyframe_effect_animation.h" #include "cc/animation/timing_function.h" @@ -793,10 +794,9 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated switch (layer_tree_host()->SourceFrameNumber()) { case 1: { std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(500.f, 550.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory:: + CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(500.f, 550.f))); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); keyframe_model->set_needs_synchronized_start_time(true); @@ -880,7 +880,9 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationTakeover scoped_refptr<FakePictureLayer> scroll_layer_; }; -MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationTakeover); +// TODO(crbug.com/1018213): [BlinkGenPropertyTrees] Scroll Animation should be +// taken over from cc when scroll is unpromoted. +// MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationTakeover); // Verifies that an impl-only scroll offset animation gets updated when the // scroll offset is adjusted on the main thread. @@ -1005,10 +1007,8 @@ class LayerTreeHostPresentationDuringAnimation layer_tree_host()->root_layer()->AddChild(scroll_layer_); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(6500.f, 7500.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(6500.f, 7500.f))); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); keyframe_model->set_needs_synchronized_start_time(true); @@ -1083,10 +1083,8 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval layer_tree_host()->root_layer()->AddChild(scroll_layer_); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(6500.f, 7500.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(6500.f, 7500.f))); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); keyframe_model->set_needs_synchronized_start_time(true); @@ -1211,10 +1209,8 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationCompletion layer_tree_host()->root_layer()->AddChild(scroll_layer_); std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - final_position_, - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + final_position_)); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); keyframe_model->set_needs_synchronized_start_time(true); @@ -2163,10 +2159,8 @@ class ImplSideInvalidationWithoutCommitTestScroll void BeginTest() override { std::unique_ptr<ScrollOffsetAnimationCurve> curve( - ScrollOffsetAnimationCurve::Create( - gfx::ScrollOffset(500.f, 550.f), - CubicBezierTimingFunction::CreatePreset( - CubicBezierTimingFunction::EaseType::EASE_IN_OUT))); + ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting( + gfx::ScrollOffset(500.f, 550.f))); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET)); keyframe_model->set_needs_synchronized_start_time(true); diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc index f2b8bba821c..118fbff0189 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_context.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc @@ -983,8 +983,7 @@ class LayerTreeHostContextTestDontUseLostResources layer_tree_host()->SetDebugState(debug_state); scoped_refptr<PaintedScrollbarLayer> scrollbar = - PaintedScrollbarLayer::Create( - std::unique_ptr<Scrollbar>(new FakeScrollbar)); + PaintedScrollbarLayer::Create(base::MakeRefCounted<FakeScrollbar>()); scrollbar->SetScrollElementId(layer->element_id()); scrollbar->SetBounds(gfx::Size(10, 10)); scrollbar->SetIsDrawable(true); diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc index 2d3bc04e847..50e7dbe7489 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc @@ -160,7 +160,7 @@ class LayerTreeHostCopyRequestTestMultipleRequests }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestMultipleRequests, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL, @@ -197,7 +197,7 @@ class LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -259,7 +259,7 @@ class LayerTreeHostCopyRequestCompletionCausesCommit }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestCompletionCausesCommit, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -364,7 +364,7 @@ class LayerTreeHostCopyRequestTestLayerDestroyed }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestLayerDestroyed, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -471,7 +471,7 @@ class LayerTreeHostCopyRequestTestInHiddenSubtree }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestInHiddenSubtree, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -593,7 +593,7 @@ class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -650,7 +650,7 @@ class LayerTreeHostCopyRequestTestClippedOut }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestClippedOut, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -711,7 +711,7 @@ class LayerTreeHostCopyRequestTestScaledLayer }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestScaledLayer, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -807,7 +807,7 @@ class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostTestAsyncTwoReadbacksWithoutDraw, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -951,7 +951,7 @@ class LayerTreeHostCopyRequestTestDeleteSharedImage }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestDeleteSharedImage, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -1097,7 +1097,7 @@ class LayerTreeHostCopyRequestTestCreatesSharedImage }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestCreatesSharedImage, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -1186,7 +1186,7 @@ class LayerTreeHostCopyRequestTestDestroyBeforeCopy }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestDestroyBeforeCopy, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -1270,7 +1270,7 @@ class LayerTreeHostCopyRequestTestShutdownBeforeCopy }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestShutdownBeforeCopy, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); @@ -1403,7 +1403,7 @@ class LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest }; INSTANTIATE_TEST_SUITE_P( - , + All, LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest, CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, LayerTreeTest::RENDERER_SKIA_GL})); diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc index 6f6915ee368..700c29d9af2 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc @@ -61,18 +61,11 @@ std::unique_ptr<ScrollState> UpdateState(const gfx::Point& point, return scroll_state; } -std::unique_ptr<ScrollState> EndState() { - ScrollStateData scroll_state_data; - scroll_state_data.is_ending = true; - std::unique_ptr<ScrollState> scroll_state(new ScrollState(scroll_state_data)); - return scroll_state; -} - static ScrollTree* ScrollTreeForLayer(LayerImpl* layer_impl) { return &layer_impl->layer_tree_impl()->property_trees()->scroll_tree; } -class LayerTreeHostScrollTest : public LayerTreeTest { +class LayerTreeHostScrollTest : public LayerTreeTest, public ScrollCallbacks { protected: LayerTreeHostScrollTest() { SetUseLayerLists(); } @@ -85,29 +78,48 @@ class LayerTreeHostScrollTest : public LayerTreeTest { root_layer->bounds().height() + 100); SetupViewport(root_layer, root_layer->bounds(), scroll_layer_bounds); - layer_tree_host() - ->OuterViewportScrollLayerForTesting() - ->set_did_scroll_callback(base::BindRepeating( - &LayerTreeHostScrollTest::DidScrollOuterViewport, - base::Unretained(this))); + layer_tree_host()->property_trees()->scroll_tree.SetScrollCallbacks( + weak_ptr_factory_.GetWeakPtr()); } - // This is set as did_scroll_callback of scroll layers to automatically - // synchronize scroll delta from impl-side, which simulates cc client (e.g. - // Blink) behavior when handling impl-side scrolls. - void SyncScrollFromImpl(const gfx::ScrollOffset& scroll_offset, - const ElementId& element_id) { + // This is called from DidScroll() to synchronize scroll delta from impl-side, + // which simulates cc client (e.g Blink) behavior when handling impl-side + // scrolls. + void SyncScrollFromImpl(ElementId element_id, + const gfx::ScrollOffset& scroll_offset) { SetScrollOffset(layer_tree_host()->LayerByElementId(element_id), scroll_offset); } - virtual void DidScrollOuterViewport(const gfx::ScrollOffset& scroll_offset, - const ElementId& element_id) { - SyncScrollFromImpl(scroll_offset, element_id); + // ScrollCallbacks + void DidScroll(ElementId element_id, + const gfx::ScrollOffset& scroll_offset, + const base::Optional<TargetSnapAreaElementIds>& + snap_target_ids) override { + SyncScrollFromImpl(element_id, scroll_offset); + if (element_id == + layer_tree_host()->OuterViewportScrollLayerForTesting()->element_id()) { + DidScrollOuterViewport(scroll_offset); + } + if (snap_target_ids.has_value()) { + ScrollNode* scroller_node = + layer_tree_host() + ->property_trees() + ->scroll_tree.FindNodeFromElementId(element_id); + scroller_node->snap_container_data.value().SetTargetSnapAreaElementIds( + snap_target_ids.value()); + } + } + void DidChangeScrollbarsHidden(ElementId, bool) override {} + + virtual void DidScrollOuterViewport(const gfx::ScrollOffset& scroll_offset) { num_outer_viewport_scrolls_++; } int num_outer_viewport_scrolls_ = 0; + + private: + base::WeakPtrFactory<LayerTreeHostScrollTest> weak_ptr_factory_{this}; }; class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest { @@ -523,10 +535,6 @@ class LayerTreeHostScrollTestScrollSnapping : public LayerTreeHostScrollTest { CreateScrollNode(scroll_layer_.get()); layer_tree_host()->root_layer()->AddChild(scroll_layer_); - scroll_layer_->set_did_scroll_callback(base::BindRepeating( - &LayerTreeHostScrollTestScrollSnapping::SyncScrollFromImpl, - base::Unretained(this))); - layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.1f, 100.f); } @@ -585,9 +593,6 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { layer_tree_host()->OuterViewportScrollLayerForTesting(); child_layer_ = Layer::Create(); - child_layer_->set_did_scroll_callback( - base::BindRepeating(&LayerTreeHostScrollTestCaseWithChild::DidScroll, - base::Unretained(this))); child_layer_->SetElementId( LayerIdToElementIdForTesting(child_layer_->id())); child_layer_->SetBounds(gfx::Size(110, 110)); @@ -637,11 +642,18 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { } } - void DidScroll(const gfx::ScrollOffset& offset, const ElementId& element_id) { - SyncScrollFromImpl(offset, element_id); - final_scroll_offset_ = expected_scroll_layer_->CurrentScrollOffset(); - EXPECT_VECTOR_EQ(offset, final_scroll_offset_); - EXPECT_EQ(element_id, expected_scroll_layer_->element_id()); + void DidScroll(ElementId element_id, + const gfx::ScrollOffset& offset, + const base::Optional<TargetSnapAreaElementIds>& + snap_target_ids) override { + LayerTreeHostScrollTest::DidScroll(element_id, offset, snap_target_ids); + if (element_id == expected_scroll_layer_->element_id()) { + final_scroll_offset_ = expected_scroll_layer_->CurrentScrollOffset(); + EXPECT_EQ(offset, final_scroll_offset_); + EXPECT_EQ(element_id, expected_scroll_layer_->element_id()); + } else { + EXPECT_TRUE(offset.IsZero()); + } } void UpdateLayerTreeHost() override { @@ -707,7 +719,7 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get()); auto* scrolling_node = impl->CurrentlyScrollingNode(); CHECK(scrolling_node); - impl->ScrollEnd(EndState().get()); + impl->ScrollEnd(); CHECK(!impl->CurrentlyScrollingNode()); EXPECT_EQ(scrolling_node->id, impl->active_tree()->LastScrolledScrollNodeIndex()); @@ -730,7 +742,7 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { BeginState(scroll_point).get(), InputHandler::WHEEL); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get()); - impl->ScrollEnd(EndState().get()); + impl->ScrollEnd(); // Check the scroll is applied as a delta. EXPECT_VECTOR_EQ(javascript_scroll_, @@ -757,15 +769,10 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { } void AfterTest() override { - if (scroll_child_layer_) { - EXPECT_EQ(0, num_outer_viewport_scrolls_); - EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(javascript_scroll_, - scroll_amount_), - final_scroll_offset_); - } else { - EXPECT_EQ(2, num_outer_viewport_scrolls_); - EXPECT_VECTOR_EQ(gfx::ScrollOffset(), final_scroll_offset_); - } + EXPECT_EQ(scroll_child_layer_ ? 0 : 2, num_outer_viewport_scrolls_); + EXPECT_VECTOR_EQ( + gfx::ScrollOffsetWithDelta(javascript_scroll_, scroll_amount_), + final_scroll_offset_); } protected: @@ -1106,6 +1113,296 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest { // This tests scrolling on the impl side which is only possible with a thread. MULTI_THREAD_TEST_F(LayerTreeHostScrollTestImplOnlyScroll); +void DoGestureScroll(LayerTreeHostImpl* host_impl, + const scoped_refptr<Layer>& scroller, + gfx::Vector2dF offset) { + ScrollStateData begin_scroll_state_data; + begin_scroll_state_data.set_current_native_scrolling_element( + scroller->element_id()); + std::unique_ptr<ScrollState> begin_scroll_state( + new ScrollState(begin_scroll_state_data)); + auto scroll_status = host_impl->ScrollBegin(begin_scroll_state.get(), + InputHandler::TOUCHSCREEN); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, scroll_status.thread); + auto* scrolling_node = host_impl->CurrentlyScrollingNode(); + EXPECT_TRUE(scrolling_node); + EXPECT_EQ(scrolling_node->element_id, scroller->element_id()); + + ScrollStateData update_scroll_state_data; + update_scroll_state_data.set_current_native_scrolling_element( + scroller->element_id()); + update_scroll_state_data.delta_x = offset.x(); + update_scroll_state_data.delta_y = offset.y(); + std::unique_ptr<ScrollState> update_scroll_state( + new ScrollState(update_scroll_state_data)); + host_impl->ScrollBy(update_scroll_state.get()); + + ScrollStateData end_scroll_state_data; + end_scroll_state_data.set_current_native_scrolling_element( + scroller->element_id()); + std::unique_ptr<ScrollState> end_scroll_state( + new ScrollState(end_scroll_state_data)); + host_impl->ScrollEnd(true /* should_snap */); +} + +// This test simulates scrolling on the impl thread such that snapping occurs +// and ensures that the target snap area element ids are sent back to the main +// thread. +class LayerTreeHostScrollTestImplOnlyScrollSnap + : public LayerTreeHostScrollTest { + public: + LayerTreeHostScrollTestImplOnlyScrollSnap() + : initial_scroll_(100, 100), + impl_thread_scroll_(350, 350), + snap_area_id_(ElementId(10)) {} + + void SetupTree() override { + LayerTreeHostScrollTest::SetupTree(); + + Layer* root = layer_tree_host()->root_layer(); + container_ = Layer::Create(); + scroller_ = Layer::Create(); + scroller_->SetElementId(LayerIdToElementIdForTesting(scroller_->id())); + + container_->SetBounds(gfx::Size(100, 100)); + CopyProperties(root, container_.get()); + root->AddChild(container_); + + scroller_->SetBounds(gfx::Size(1000, 1000)); + scroller_->SetScrollable(container_->bounds()); + CopyProperties(container_.get(), scroller_.get()); + CreateTransformNode(scroller_.get()); + + // Set up a snap area. + snap_area_ = Layer::Create(); + snap_area_->SetBounds(gfx::Size(50, 50)); + snap_area_->SetPosition(gfx::PointF(500, 500)); + CopyProperties(scroller_.get(), snap_area_.get()); + scroller_->AddChild(snap_area_); + SnapAreaData snap_area_data(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(500, 500, 100, 100), false, + snap_area_id_); + + // Set up snap container data. + SnapContainerData snap_container_data( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 100, 100), gfx::ScrollOffset(900, 900)); + snap_container_data.AddSnapAreaData(snap_area_data); + CreateScrollNode(scroller_.get()).snap_container_data = snap_container_data; + + root->AddChild(scroller_); + } + + void BeginTest() override { + SetScrollOffset(scroller_.get(), initial_scroll_); + PostSetNeedsCommitToMainThread(); + } + + void UpdateLayerTreeHost() override { + ScrollNode* scroller_node = + layer_tree_host()->property_trees()->scroll_tree.Node( + scroller_->scroll_tree_index()); + auto snap_target_ids = scroller_node->snap_container_data.value() + .GetTargetSnapAreaElementIds(); + if (layer_tree_host()->SourceFrameNumber() == 0) { + // On the first BeginMainFrame scrolling has not happened yet. + // Check that the scroll offset and scroll snap targets are at the initial + // values on the main thread. + EXPECT_EQ(snap_target_ids, TargetSnapAreaElementIds()); + EXPECT_VECTOR_EQ(initial_scroll_, scroller_->CurrentScrollOffset()); + } else { + // After a snap target is set on the impl thread, the snap targets should + // be pushed to the main thread. + EXPECT_EQ(snap_target_ids, + TargetSnapAreaElementIds(snap_area_id_, snap_area_id_)); + EndTest(); + } + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + // Perform a scroll such that a snap target is found. This will get pushed + // to the main thread on the next BeginMainFrame. + if (host_impl->active_tree()->source_frame_number() == 0) { + LayerImpl* scroller_impl = + host_impl->active_tree()->LayerById(scroller_->id()); + + DoGestureScroll(host_impl, scroller_, impl_thread_scroll_); + + EXPECT_TRUE(host_impl->is_animating_for_snap_for_testing()); + EXPECT_VECTOR_EQ(impl_thread_scroll_, ScrollDelta(scroller_impl)); + + ScrollNode* scroller_node = + host_impl->active_tree()->property_trees()->scroll_tree.Node( + scroller_->scroll_tree_index()); + auto snap_target_ids = scroller_node->snap_container_data.value() + .GetTargetSnapAreaElementIds(); + EXPECT_EQ(snap_target_ids, + TargetSnapAreaElementIds(snap_area_id_, snap_area_id_)); + } + PostSetNeedsCommitToMainThread(); + } + + private: + scoped_refptr<Layer> container_; + scoped_refptr<Layer> scroller_; + scoped_refptr<Layer> snap_area_; + + gfx::ScrollOffset initial_scroll_; + gfx::Vector2dF impl_thread_scroll_; + + ElementId snap_area_id_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostScrollTestImplOnlyScrollSnap); + +// This test simulates scrolling on the impl thread such that 2 impl-only +// scrolls occur between main frames. It ensures that the snap target ids will +// be synced from impl to main for both snapped scrolling nodes. +class LayerTreeHostScrollTestImplOnlyMultipleScrollSnap + : public LayerTreeHostScrollTest { + public: + LayerTreeHostScrollTestImplOnlyMultipleScrollSnap() + : initial_scroll_(100, 100), + // Scroll to the boundary so that an animation is not created when + // snapping to allow 2 scrolls between main frames. + impl_thread_scroll_a_(400, 400), + impl_thread_scroll_b_(400, 400), + snap_area_a_id_(ElementId(10)), + snap_area_b_id_(ElementId(20)) {} + + void SetupTree() override { + LayerTreeHostScrollTest::SetupTree(); + + Layer* root = layer_tree_host()->root_layer(); + container_ = Layer::Create(); + scroller_a_ = Layer::Create(); + scroller_b_ = Layer::Create(); + scroller_a_->SetElementId(LayerIdToElementIdForTesting(scroller_a_->id())); + scroller_b_->SetElementId(LayerIdToElementIdForTesting(scroller_b_->id())); + + container_->SetBounds(gfx::Size(100, 100)); + CopyProperties(root, container_.get()); + root->AddChild(container_); + + scroller_a_->SetBounds(gfx::Size(1000, 1000)); + scroller_a_->SetScrollable(container_->bounds()); + CopyProperties(container_.get(), scroller_a_.get()); + CreateTransformNode(scroller_a_.get()); + scroller_b_->SetBounds(gfx::Size(1000, 1000)); + scroller_b_->SetScrollable(container_->bounds()); + CopyProperties(container_.get(), scroller_b_.get()); + CreateTransformNode(scroller_b_.get()); + + // Set up snap areas. + snap_area_a_ = Layer::Create(); + snap_area_a_->SetBounds(gfx::Size(50, 50)); + snap_area_a_->SetPosition(gfx::PointF(500, 500)); + CopyProperties(scroller_a_.get(), snap_area_a_.get()); + scroller_a_->AddChild(snap_area_a_); + SnapAreaData snap_area_data_a(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(500, 500, 100, 100), false, + snap_area_a_id_); + + snap_area_b_ = Layer::Create(); + snap_area_b_->SetBounds(gfx::Size(50, 50)); + snap_area_b_->SetPosition(gfx::PointF(500, 500)); + CopyProperties(scroller_b_.get(), snap_area_b_.get()); + scroller_b_->AddChild(snap_area_b_); + SnapAreaData snap_area_data_b(ScrollSnapAlign(SnapAlignment::kStart), + gfx::RectF(500, 500, 100, 100), false, + snap_area_b_id_); + + // Set up snap container data. + SnapContainerData snap_container_data_a( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 100, 100), gfx::ScrollOffset(900, 900)); + snap_container_data_a.AddSnapAreaData(snap_area_data_a); + CreateScrollNode(scroller_a_.get()).snap_container_data = + snap_container_data_a; + + // Set up snap container data. + SnapContainerData snap_container_data_b( + ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), + gfx::RectF(0, 0, 100, 100), gfx::ScrollOffset(900, 900)); + snap_container_data_b.AddSnapAreaData(snap_area_data_b); + CreateScrollNode(scroller_b_.get()).snap_container_data = + snap_container_data_b; + + root->AddChild(scroller_a_); + root->AddChild(scroller_b_); + } + + void BeginTest() override { + SetScrollOffset(scroller_a_.get(), initial_scroll_); + SetScrollOffset(scroller_b_.get(), initial_scroll_); + PostSetNeedsCommitToMainThread(); + } + + void UpdateLayerTreeHost() override { + ScrollNode* scroller_node_a = + layer_tree_host()->property_trees()->scroll_tree.Node( + scroller_a_->scroll_tree_index()); + ScrollNode* scroller_node_b = + layer_tree_host()->property_trees()->scroll_tree.Node( + scroller_b_->scroll_tree_index()); + auto snap_target_ids_a = scroller_node_a->snap_container_data.value() + .GetTargetSnapAreaElementIds(); + auto snap_target_ids_b = scroller_node_b->snap_container_data.value() + .GetTargetSnapAreaElementIds(); + if (layer_tree_host()->SourceFrameNumber() == 0) { + // On the first BeginMainFrame scrolling has not happened yet. + // Check that the scroll offset and scroll snap targets are at the initial + // values on the main thread. + EXPECT_EQ(snap_target_ids_a, TargetSnapAreaElementIds()); + EXPECT_EQ(snap_target_ids_b, TargetSnapAreaElementIds()); + EXPECT_VECTOR_EQ(initial_scroll_, scroller_a_->CurrentScrollOffset()); + EXPECT_VECTOR_EQ(initial_scroll_, scroller_b_->CurrentScrollOffset()); + } else { + // When scrolling happens on the impl thread, the snap targets of the + // scrolled layers should be pushed to the main thread. + EXPECT_EQ(snap_target_ids_a, + TargetSnapAreaElementIds(snap_area_a_id_, snap_area_a_id_)); + EXPECT_EQ(snap_target_ids_b, + TargetSnapAreaElementIds(snap_area_b_id_, snap_area_b_id_)); + EndTest(); + } + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + // Perform scrolls such that a snap target is found. These will get pushed + // to the main thread on the next BeginMainFrame. + if (host_impl->active_tree()->source_frame_number() == 0) { + LayerImpl* scroller_impl_a = + host_impl->active_tree()->LayerById(scroller_a_->id()); + LayerImpl* scroller_impl_b = + host_impl->active_tree()->LayerById(scroller_b_->id()); + + DoGestureScroll(host_impl, scroller_a_, impl_thread_scroll_a_); + DoGestureScroll(host_impl, scroller_b_, impl_thread_scroll_b_); + + EXPECT_VECTOR_EQ(impl_thread_scroll_a_, ScrollDelta(scroller_impl_a)); + EXPECT_VECTOR_EQ(impl_thread_scroll_b_, ScrollDelta(scroller_impl_b)); + } + PostSetNeedsCommitToMainThread(); + } + + private: + scoped_refptr<Layer> container_; + scoped_refptr<Layer> scroller_a_; + scoped_refptr<Layer> scroller_b_; + scoped_refptr<Layer> snap_area_a_; + scoped_refptr<Layer> snap_area_b_; + + gfx::ScrollOffset initial_scroll_; + gfx::Vector2dF impl_thread_scroll_a_; + gfx::Vector2dF impl_thread_scroll_b_; + + ElementId snap_area_a_id_; + ElementId snap_area_b_id_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostScrollTestImplOnlyMultipleScrollSnap); + class LayerTreeHostScrollTestScrollZeroMaxScrollOffset : public LayerTreeHostScrollTest { public: @@ -1129,9 +1426,7 @@ class LayerTreeHostScrollTestScrollZeroMaxScrollOffset layer_tree_host()->root_layer()->AddChild(scroller_.get()); } - void BeginTest() override { - PostSetNeedsCommitToMainThread(); - } + void BeginTest() override { PostSetNeedsCommitToMainThread(); } void UpdateLayerTreeHost() override { ScrollTree& scroll_tree = layer_tree_host()->property_trees()->scroll_tree; @@ -1344,12 +1639,9 @@ class LayerTreeHostScrollTestLayerStructureChange Layer* outer_scroll_layer = layer_tree_host()->OuterViewportScrollLayerForTesting(); - Layer* root_scroll_layer = - CreateScrollLayer(outer_scroll_layer, &root_scroll_layer_client_); - Layer* sibling_scroll_layer = - CreateScrollLayer(outer_scroll_layer, &sibling_scroll_layer_client_); - Layer* child_scroll_layer = - CreateScrollLayer(root_scroll_layer, &child_scroll_layer_client_); + Layer* root_scroll_layer = CreateScrollLayer(outer_scroll_layer); + Layer* sibling_scroll_layer = CreateScrollLayer(outer_scroll_layer); + Layer* child_scroll_layer = CreateScrollLayer(root_scroll_layer); root_scroll_layer_id_ = root_scroll_layer->id(); sibling_scroll_layer_id_ = sibling_scroll_layer->id(); child_scroll_layer_id_ = child_scroll_layer->id(); @@ -1378,7 +1670,9 @@ class LayerTreeHostScrollTestLayerStructureChange } } - virtual void DidScroll(Layer* layer) { + void DidScroll(ElementId element_id, + const gfx::ScrollOffset&, + const base::Optional<TargetSnapAreaElementIds>&) override { if (scroll_destroy_whole_tree_) { layer_tree_host()->SetRootLayer(nullptr); layer_tree_host()->property_trees()->clear(); @@ -1387,20 +1681,11 @@ class LayerTreeHostScrollTestLayerStructureChange EndTest(); return; } - layer->RemoveFromParent(); + layer_tree_host()->LayerByElementId(element_id)->RemoveFromParent(); } protected: - class FakeLayerScrollClient { - public: - void DidScroll(const gfx::ScrollOffset&, const ElementId&) { - owner_->DidScroll(layer_); - } - LayerTreeHostScrollTestLayerStructureChange* owner_; - Layer* layer_; - }; - - Layer* CreateScrollLayer(Layer* parent, FakeLayerScrollClient* client) { + Layer* CreateScrollLayer(Layer* parent) { scoped_refptr<PictureLayer> scroll_layer = PictureLayer::Create(&fake_content_layer_client_); scroll_layer->SetIsDrawable(true); @@ -1410,10 +1695,6 @@ class LayerTreeHostScrollTestLayerStructureChange LayerIdToElementIdForTesting(scroll_layer->id())); scroll_layer->SetBounds(gfx::Size(parent->bounds().width() + 100, parent->bounds().height() + 100)); - scroll_layer->set_did_scroll_callback(base::BindRepeating( - &FakeLayerScrollClient::DidScroll, base::Unretained(client))); - client->owner_ = this; - client->layer_ = scroll_layer.get(); CopyProperties(parent, scroll_layer.get()); CreateTransformNode(scroll_layer.get()); @@ -1433,9 +1714,6 @@ class LayerTreeHostScrollTestLayerStructureChange layer_impl->element_id()); } - FakeLayerScrollClient root_scroll_layer_client_; - FakeLayerScrollClient sibling_scroll_layer_client_; - FakeLayerScrollClient child_scroll_layer_client_; int root_scroll_layer_id_; int sibling_scroll_layer_id_; int child_scroll_layer_id_; @@ -2030,13 +2308,10 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostScrollTestPropertyTreeUpdate); class LayerTreeHostScrollTestImplSideInvalidation : public LayerTreeHostScrollTest { - void BeginTest() override { - PostSetNeedsCommitToMainThread(); - } + void BeginTest() override { PostSetNeedsCommitToMainThread(); } - void DidScrollOuterViewport(const gfx::ScrollOffset& offset, - const ElementId& element_id) override { - LayerTreeHostScrollTest::DidScrollOuterViewport(offset, element_id); + void DidScrollOuterViewport(const gfx::ScrollOffset& offset) override { + LayerTreeHostScrollTest::DidScrollOuterViewport(offset); // Defer responding to the main frame until an impl-side pending tree is // created for the invalidation request. diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index 27812c1d31e..aff9ec178c4 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -17,6 +17,7 @@ #include "base/debug/dump_without_crashing.h" #include "base/json/json_writer.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/ranges.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/timer/elapsed_timer.h" @@ -97,6 +98,18 @@ class ViewportAnchor { LayerTreeImpl* tree_impl_; gfx::ScrollOffset viewport_in_content_coordinates_; }; + +std::pair<gfx::PointF, gfx::PointF> GetVisibleSelectionEndPoints( + const gfx::RectF& rect, + const gfx::PointF& top, + const gfx::PointF& bottom) { + gfx::PointF start(base::ClampToRange(top.x(), rect.x(), rect.right()), + base::ClampToRange(top.y(), rect.y(), rect.bottom())); + gfx::PointF end = + start + gfx::Vector2dF(bottom.x() - top.x(), bottom.y() - top.y()); + return {start, end}; +} + } // namespace void LayerTreeLifecycle::AdvanceTo(LifecycleState next_state) { @@ -118,6 +131,7 @@ LayerTreeImpl::LayerTreeImpl( LayerTreeHostImpl* host_impl, scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, scoped_refptr<SyncedBrowserControls> top_controls_shown_ratio, + scoped_refptr<SyncedBrowserControls> bottom_controls_shown_ratio, scoped_refptr<SyncedElasticOverscroll> elastic_overscroll) : host_impl_(host_impl), source_frame_number_(-1), @@ -141,10 +155,8 @@ LayerTreeImpl::LayerTreeImpl( handle_visibility_changed_(false), have_scroll_event_handlers_(false), event_listener_properties_(), - browser_controls_shrink_blink_size_(false), - top_controls_height_(0), - bottom_controls_height_(0), - top_controls_shown_ratio_(top_controls_shown_ratio) { + top_controls_shown_ratio_(std::move(top_controls_shown_ratio)), + bottom_controls_shown_ratio_(std::move(bottom_controls_shown_ratio)) { property_trees()->is_main_thread = false; } @@ -242,22 +254,23 @@ void LayerTreeImpl::UpdateScrollbarGeometries() { gfx::SizeF scrolling_size(scroll_node->bounds); gfx::Size bounds_size(scroll_tree.container_bounds(scroll_node->id)); - bool is_viewport_scrollbar = scroll_node->scrolls_inner_viewport || - scroll_node->scrolls_outer_viewport; + bool is_viewport_scrollbar = scroll_node == InnerViewportScrollNode() || + scroll_node == OuterViewportScrollNode(); if (is_viewport_scrollbar) { gfx::SizeF viewport_bounds(bounds_size); - if (scroll_node->scrolls_inner_viewport) { + if (scroll_node == InnerViewportScrollNode()) { DCHECK_EQ(scroll_node, InnerViewportScrollNode()); - if (auto* outer_scroll_node = OuterViewportScrollNode()) { - // Add offset and bounds contribution of outer viewport. - current_offset += - scroll_tree.current_scroll_offset(outer_scroll_node->element_id); - gfx::SizeF outer_viewport_bounds( - scroll_tree.container_bounds(outer_scroll_node->id)); - viewport_bounds.SetToMin(outer_viewport_bounds); - // The scrolling size is only determined by the outer viewport. - scrolling_size = gfx::SizeF(outer_scroll_node->bounds); - } + auto* outer_scroll_node = OuterViewportScrollNode(); + DCHECK(outer_scroll_node); + + // Add offset and bounds contribution of outer viewport. + current_offset += + scroll_tree.current_scroll_offset(outer_scroll_node->element_id); + gfx::SizeF outer_viewport_bounds( + scroll_tree.container_bounds(outer_scroll_node->id)); + viewport_bounds.SetToMin(outer_viewport_bounds); + // The scrolling size is only determined by the outer viewport. + scrolling_size = gfx::SizeF(outer_scroll_node->bounds); } else { DCHECK_EQ(scroll_node, OuterViewportScrollNode()); auto* inner_scroll_node = InnerViewportScrollNode(); @@ -352,25 +365,29 @@ void LayerTreeImpl::UpdateViewportContainerSizes() { if (!InnerViewportScrollNode()) return; + DCHECK(OuterViewportScrollNode()); ViewportAnchor anchor(InnerViewportScrollNode(), OuterViewportScrollNode(), this); // Top/bottom controls always share the same shown ratio. - float controls_shown_ratio = + float top_controls_shown_ratio = top_controls_shown_ratio_->Current(IsActiveTree()); + float bottom_controls_shown_ratio = + bottom_controls_shown_ratio_->Current(IsActiveTree()); float top_controls_layout_height = browser_controls_shrink_blink_size() ? top_controls_height() : 0.f; - float top_content_offset = top_controls_height_ > 0 - ? top_controls_height_ * controls_shown_ratio - : 0.0f; + float top_content_offset = + top_controls_height() > 0 + ? top_controls_height() * top_controls_shown_ratio + : 0.f; float delta_from_top_controls = top_controls_layout_height - top_content_offset; float bottom_controls_layout_height = browser_controls_shrink_blink_size() ? bottom_controls_height() : 0.f; float bottom_content_offset = - bottom_controls_height_ > 0 - ? bottom_controls_height_ * controls_shown_ratio - : 0.0f; + bottom_controls_height() > 0 + ? bottom_controls_height() * bottom_controls_shown_ratio + : 0.f; delta_from_top_controls += bottom_controls_layout_height - bottom_content_offset; @@ -387,25 +404,24 @@ void LayerTreeImpl::UpdateViewportContainerSizes() { // Adjust the outer viewport container as well, since adjusting only the // inner may cause its bounds to exceed those of the outer, causing scroll // clamping. - if (auto* outer_scroll = OuterViewportScrollNode()) { - gfx::Vector2dF scaled_bounds_delta = - gfx::ScaleVector2d(bounds_delta, 1.f / min_page_scale_factor()); - - property_trees->SetOuterViewportContainerBoundsDelta(scaled_bounds_delta); - // outer_viewport_container_bounds_delta and - // inner_viewport_scroll_bounds_delta are the same thing. - DCHECK_EQ(scaled_bounds_delta, - property_trees->inner_viewport_scroll_bounds_delta()); - - if (auto* outer_clip_node = OuterViewportClipNode()) { - float adjusted_container_height = - outer_scroll->container_bounds.height() + scaled_bounds_delta.y(); - outer_clip_node->clip.set_height(adjusted_container_height); - } + gfx::Vector2dF scaled_bounds_delta = + gfx::ScaleVector2d(bounds_delta, 1.f / min_page_scale_factor()); + + property_trees->SetOuterViewportContainerBoundsDelta(scaled_bounds_delta); + // outer_viewport_container_bounds_delta and + // inner_viewport_scroll_bounds_delta are the same thing. + DCHECK_EQ(scaled_bounds_delta, + property_trees->inner_viewport_scroll_bounds_delta()); - anchor.ResetViewportToAnchoredPosition(); + if (auto* outer_clip_node = OuterViewportClipNode()) { + float adjusted_container_height = + OuterViewportScrollNode()->container_bounds.height() + + scaled_bounds_delta.y(); + outer_clip_node->clip.set_height(adjusted_container_height); } + anchor.ResetViewportToAnchoredPosition(); + property_trees->clip_tree.set_needs_update(true); property_trees->full_tree_damaged = true; set_needs_update_draw_properties(); @@ -424,11 +440,12 @@ gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const { gfx::ScrollOffset offset; const auto& scroll_tree = property_trees()->scroll_tree; - if (auto* inner_scroll = InnerViewportScrollNode()) + if (auto* inner_scroll = InnerViewportScrollNode()) { offset += scroll_tree.current_scroll_offset(inner_scroll->element_id); - - if (auto* outer_scroll = OuterViewportScrollNode()) - offset += scroll_tree.current_scroll_offset(outer_scroll->element_id); + DCHECK(OuterViewportScrollNode()); + offset += scroll_tree.current_scroll_offset( + OuterViewportScrollNode()->element_id); + } return offset; } @@ -543,11 +560,8 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { max_page_scale_factor()); target_tree->SetExternalPageScaleFactor(external_page_scale_factor_); - target_tree->set_browser_controls_shrink_blink_size( - browser_controls_shrink_blink_size_); - target_tree->SetTopControlsHeight(top_controls_height_); - target_tree->SetBottomControlsHeight(bottom_controls_height_); - target_tree->PushBrowserControls(nullptr); + target_tree->SetBrowserControlsParams(browser_controls_params_); + target_tree->PushBrowserControls(nullptr, nullptr); target_tree->set_overscroll_behavior(overscroll_behavior_); @@ -602,12 +616,12 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { } void LayerTreeImpl::HandleTickmarksVisibilityChange() { - if (!host_impl_->ViewportMainScrollNode()) + if (!host_impl_->OuterViewportScrollNode()) return; ScrollbarAnimationController* controller = host_impl_->ScrollbarAnimationControllerForElementId( - host_impl_->ViewportMainScrollNode()->element_id); + host_impl_->OuterViewportScrollNode()->element_id); if (!controller) return; @@ -994,28 +1008,17 @@ void LayerTreeImpl::PushPageScaleFactorAndLimits(const float* page_scale_factor, UpdatePageScaleNode(); } -void LayerTreeImpl::set_browser_controls_shrink_blink_size(bool shrink) { - if (browser_controls_shrink_blink_size_ == shrink) - return; - - browser_controls_shrink_blink_size_ = shrink; - UpdateViewportContainerSizes(); -} - -void LayerTreeImpl::SetTopControlsHeight(float top_controls_height) { - if (top_controls_height_ == top_controls_height) +void LayerTreeImpl::SetBrowserControlsParams( + const BrowserControlsParams& params) { + if (browser_controls_params_ == params) return; - top_controls_height_ = top_controls_height; + browser_controls_params_ = params; UpdateViewportContainerSizes(); -} - -void LayerTreeImpl::SetBottomControlsHeight(float bottom_controls_height) { - if (bottom_controls_height_ == bottom_controls_height) - return; - bottom_controls_height_ = bottom_controls_height; - UpdateViewportContainerSizes(); + if (IsActiveTree()) + host_impl_->browser_controls_manager()->OnBrowserControlsParamsChanged( + params.animate_browser_controls_height_changes); } void LayerTreeImpl::set_overscroll_behavior( @@ -1023,39 +1026,57 @@ void LayerTreeImpl::set_overscroll_behavior( overscroll_behavior_ = behavior; } -bool LayerTreeImpl::ClampBrowserControlsShownRatio() { +bool LayerTreeImpl::ClampTopControlsShownRatio() { float ratio = top_controls_shown_ratio_->Current(true); - ratio = std::max(ratio, 0.f); - ratio = std::min(ratio, 1.f); - return top_controls_shown_ratio_->SetCurrent(ratio); + return top_controls_shown_ratio_->SetCurrent( + base::ClampToRange(ratio, 0.f, 1.f)); +} + +bool LayerTreeImpl::ClampBottomControlsShownRatio() { + float ratio = bottom_controls_shown_ratio_->Current(true); + return bottom_controls_shown_ratio_->SetCurrent( + base::ClampToRange(ratio, 0.f, 1.f)); } -bool LayerTreeImpl::SetCurrentBrowserControlsShownRatio(float ratio) { - TRACE_EVENT1("cc", "LayerTreeImpl::SetCurrentBrowserControlsShownRatio", - "ratio", ratio); - bool changed = top_controls_shown_ratio_->SetCurrent(ratio); - changed |= ClampBrowserControlsShownRatio(); +bool LayerTreeImpl::SetCurrentBrowserControlsShownRatio(float top_ratio, + float bottom_ratio) { + TRACE_EVENT2("cc", "LayerTreeImpl::SetCurrentBrowserControlsShownRatio", + "top_ratio", top_ratio, "bottom_ratio", bottom_ratio); + bool changed = top_controls_shown_ratio_->SetCurrent(top_ratio); + changed |= ClampTopControlsShownRatio(); + changed |= bottom_controls_shown_ratio_->SetCurrent(bottom_ratio); + changed |= ClampBottomControlsShownRatio(); return changed; } void LayerTreeImpl::PushBrowserControlsFromMainThread( - float top_controls_shown_ratio) { - PushBrowserControls(&top_controls_shown_ratio); + float top_controls_shown_ratio, + float bottom_controls_shown_ratio) { + PushBrowserControls(&top_controls_shown_ratio, &bottom_controls_shown_ratio); } -void LayerTreeImpl::PushBrowserControls(const float* top_controls_shown_ratio) { +void LayerTreeImpl::PushBrowserControls( + const float* top_controls_shown_ratio, + const float* bottom_controls_shown_ratio) { + DCHECK(top_controls_shown_ratio || bottom_controls_shown_ratio || + IsActiveTree()); + DCHECK(!top_controls_shown_ratio || bottom_controls_shown_ratio); DCHECK(top_controls_shown_ratio || IsActiveTree()); if (top_controls_shown_ratio) { DCHECK(!IsActiveTree() || !host_impl_->pending_tree()); bool changed_pending = top_controls_shown_ratio_->PushMainToPending(*top_controls_shown_ratio); + changed_pending |= bottom_controls_shown_ratio_->PushMainToPending( + *bottom_controls_shown_ratio); if (!IsActiveTree() && changed_pending) UpdateViewportContainerSizes(); } if (IsActiveTree()) { bool changed_active = top_controls_shown_ratio_->PushPendingToActive(); - changed_active |= ClampBrowserControlsShownRatio(); + changed_active |= ClampTopControlsShownRatio(); + changed_active |= bottom_controls_shown_ratio_->PushPendingToActive(); + changed_active |= ClampBottomControlsShownRatio(); if (changed_active) host_impl_->DidChangeBrowserControlsPosition(); } @@ -1088,7 +1109,7 @@ void LayerTreeImpl::DidUpdatePageScale() { host_impl_->FlashAllScrollbars(true); return; } - if (auto* scroll_node = host_impl_->ViewportMainScrollNode()) { + if (auto* scroll_node = host_impl_->OuterViewportScrollNode()) { if (ScrollbarAnimationController* controller = host_impl_->ScrollbarAnimationControllerForElementId( scroll_node->element_id)) @@ -1186,10 +1207,10 @@ gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const { gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const { const ScrollNode* root_scroll_node = OuterViewportScrollNode(); - if (!root_scroll_node) - root_scroll_node = InnerViewportScrollNode(); - if (!root_scroll_node) + if (!root_scroll_node) { + DCHECK(!InnerViewportScrollNode()); return gfx::Rect(); + } return MathUtil::MapEnclosingClippedRect( property_trees()->transform_tree.ToScreen(root_scroll_node->transform_id), gfx::Rect(root_scroll_node->bounds)); @@ -1419,10 +1440,10 @@ const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const { gfx::SizeF LayerTreeImpl::ScrollableSize() const { auto* scroll_node = OuterViewportScrollNode(); - if (!scroll_node) - scroll_node = InnerViewportScrollNode(); - if (!scroll_node) + if (!scroll_node) { + DCHECK(!InnerViewportScrollNode()); return gfx::SizeF(); + } const auto& scroll_tree = property_trees()->scroll_tree; auto size = scroll_tree.scroll_bounds(scroll_node->id); size.SetToMax(gfx::SizeF(scroll_tree.container_bounds(scroll_node->id))); @@ -1918,7 +1939,7 @@ void LayerTreeImpl::UnregisterScrollbar( scrollbar_ids.vertical == Layer::INVALID_ID) { element_id_to_scrollbar_layer_ids_.erase(scroll_element_id); if (IsActiveTree()) { - host_impl_->UnregisterScrollbarAnimationController(scroll_element_id); + host_impl_->DidUnregisterScrollbarLayer(scroll_element_id); } } } @@ -2258,27 +2279,27 @@ static gfx::SelectionBound ComputeViewportSelectionBound( if (!layer || layer_bound.type == gfx::SelectionBound::EMPTY) return viewport_bound; - auto layer_top = gfx::PointF(layer_bound.edge_top); - auto layer_bottom = gfx::PointF(layer_bound.edge_bottom); + auto layer_start = gfx::PointF(layer_bound.edge_start); + auto layer_end = gfx::PointF(layer_bound.edge_end); gfx::Transform screen_space_transform = layer->ScreenSpaceTransform(); bool clipped = false; - gfx::PointF screen_top = - MathUtil::MapPoint(screen_space_transform, layer_top, &clipped); - gfx::PointF screen_bottom = - MathUtil::MapPoint(screen_space_transform, layer_bottom, &clipped); + gfx::PointF screen_start = + MathUtil::MapPoint(screen_space_transform, layer_start, &clipped); + gfx::PointF screen_end = + MathUtil::MapPoint(screen_space_transform, layer_end, &clipped); // MapPoint can produce points with NaN components (even when no inputs are - // NaN). Since consumers of gfx::SelectionBounds may round |edge_top| or - // |edge_bottom| (and since rounding will crash on NaN), we return an empty + // NaN). Since consumers of gfx::SelectionBounds may round |edge_start| or + // |edge_end| (and since rounding will crash on NaN), we return an empty // bound instead. - if (std::isnan(screen_top.x()) || std::isnan(screen_top.y()) || - std::isnan(screen_bottom.x()) || std::isnan(screen_bottom.y())) + if (std::isnan(screen_start.x()) || std::isnan(screen_start.y()) || + std::isnan(screen_end.x()) || std::isnan(screen_end.y())) return gfx::SelectionBound(); const float inv_scale = 1.f / device_scale_factor; - viewport_bound.SetEdgeTop(gfx::ScalePoint(screen_top, inv_scale)); - viewport_bound.SetEdgeBottom(gfx::ScalePoint(screen_bottom, inv_scale)); + viewport_bound.SetEdgeStart(gfx::ScalePoint(screen_start, inv_scale)); + viewport_bound.SetEdgeEnd(gfx::ScalePoint(screen_end, inv_scale)); // If |layer_bound| is already hidden due to being occluded by painted content // within the layer, it must remain hidden. Otherwise, check whether its @@ -2291,9 +2312,9 @@ static gfx::SelectionBound ComputeViewportSelectionBound( // Shifting the visibility point fractionally inward ensures that // neighboring or logically coincident layers aligned to integral DPI // coordinates will not spuriously occlude the bound. - gfx::Vector2dF visibility_offset = layer_top - layer_bottom; + gfx::Vector2dF visibility_offset = layer_start - layer_end; visibility_offset.Scale(device_scale_factor / visibility_offset.Length()); - gfx::PointF visibility_point = layer_bottom + visibility_offset; + gfx::PointF visibility_point = layer_end + visibility_offset; if (visibility_point.x() <= 0) visibility_point.set_x(visibility_point.x() + device_scale_factor); visibility_point = @@ -2304,6 +2325,31 @@ static gfx::SelectionBound ComputeViewportSelectionBound( PointHitsLayer(layer, visibility_point, &intersect_distance)); } + if (viewport_bound.visible()) { + viewport_bound.SetVisibleEdge(viewport_bound.edge_start(), + viewport_bound.edge_end()); + } else { + // The |layer_start| and |layer_end| might be clipped. + gfx::RectF visible_layer_rect(layer->visible_layer_rect()); + auto visible_layer_start = layer_start; + auto visible_layer_end = layer_end; + if (!visible_layer_rect.Contains(visible_layer_start) && + !visible_layer_rect.Contains(visible_layer_end)) + std::tie(visible_layer_start, visible_layer_end) = + GetVisibleSelectionEndPoints(visible_layer_rect, layer_start, + layer_end); + + gfx::PointF visible_screen_start = MathUtil::MapPoint( + screen_space_transform, visible_layer_start, &clipped); + gfx::PointF visible_screen_end = + MathUtil::MapPoint(screen_space_transform, visible_layer_end, &clipped); + + viewport_bound.SetVisibleEdgeStart( + gfx::ScalePoint(visible_screen_start, inv_scale)); + viewport_bound.SetVisibleEdgeEnd( + gfx::ScalePoint(visible_screen_end, inv_scale)); + } + return viewport_bound; } @@ -2346,6 +2392,11 @@ bool LayerTreeImpl::IsActivelyScrolling() const { return host_impl_->IsActivelyScrolling(); } +int LayerTreeImpl::GetMSAASampleCountForRaster( + const scoped_refptr<DisplayItemList>& display_list) { + return host_impl_->GetMSAASampleCountForRaster(display_list); +} + void LayerTreeImpl::SetPendingPageScaleAnimation( std::unique_ptr<PendingPageScaleAnimation> pending_animation) { pending_page_scale_animation_ = std::move(pending_animation); diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index 7cb74373eba..118f19d1d65 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -15,6 +15,7 @@ #include "base/time/time.h" #include "base/values.h" #include "cc/base/synced_property.h" +#include "cc/input/browser_controls_offset_manager.h" #include "cc/input/event_listener_properties.h" #include "cc/input/layer_selection_bound.h" #include "cc/input/overscroll_behavior.h" @@ -22,11 +23,13 @@ #include "cc/layers/layer_list_iterator.h" #include "cc/paint/discardable_image_map.h" #include "cc/resources/ui_resource_client.h" +#include "cc/trees/browser_controls_params.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/property_tree.h" #include "cc/trees/swap_promise.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" +#include "ui/gfx/overlay_transform.h" namespace base { namespace trace_event { @@ -95,10 +98,12 @@ class CC_EXPORT LayerTreeImpl { // This is the number of times a fixed point has to be hit continuously by a // layer to consider it as jittering. enum : int { kFixedPointHitsThreshold = 3 }; - LayerTreeImpl(LayerTreeHostImpl* host_impl, - scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, - scoped_refptr<SyncedBrowserControls> top_controls_shown_ratio, - scoped_refptr<SyncedElasticOverscroll> elastic_overscroll); + LayerTreeImpl( + LayerTreeHostImpl* host_impl, + scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, + scoped_refptr<SyncedBrowserControls> top_controls_shown_ratio, + scoped_refptr<SyncedBrowserControls> bottom_controls_shown_ratio, + scoped_refptr<SyncedElasticOverscroll> elastic_overscroll); LayerTreeImpl(const LayerTreeImpl&) = delete; virtual ~LayerTreeImpl(); @@ -149,6 +154,8 @@ class CC_EXPORT LayerTreeImpl { base::flat_map<PaintImage::Id, PaintImage::DecodingMode> decoding_mode_map); bool IsActivelyScrolling() const; + int GetMSAASampleCountForRaster( + const scoped_refptr<DisplayItemList>& display_list); // Tree specific methods exposed to layer-impl tree. // --------------------------------------------------------------------------- @@ -277,6 +284,9 @@ class CC_EXPORT LayerTreeImpl { return !presentation_callbacks_.empty(); } + // The following viewport related property nodes will only ever be set on the + // main-frame's renderer (i.e. OOPIF and UI compositors will not have these + // set. using ViewportPropertyIds = LayerTreeHost::ViewportPropertyIds; void SetViewportPropertyIds(const ViewportPropertyIds& ids); @@ -324,6 +334,13 @@ class CC_EXPORT LayerTreeImpl { SkColor background_color() const { return background_color_; } void set_background_color(SkColor color) { background_color_ = color; } + gfx::OverlayTransform display_transform_hint() const { + return display_transform_hint_; + } + void set_display_transform_hint(gfx::OverlayTransform hint) { + display_transform_hint_ = hint; + } + void UpdatePropertyTreeAnimationFromMainThread(); void SetPageScaleOnActiveTree(float active_page_scale); @@ -415,6 +432,12 @@ class CC_EXPORT LayerTreeImpl { const SyncedBrowserControls* top_controls_shown_ratio() const { return top_controls_shown_ratio_.get(); } + SyncedBrowserControls* bottom_controls_shown_ratio() { + return bottom_controls_shown_ratio_.get(); + } + const SyncedBrowserControls* bottom_controls_shown_ratio() const { + return bottom_controls_shown_ratio_.get(); + } gfx::Vector2dF current_elastic_overscroll() const { return elastic_overscroll()->Current(IsActiveTree()); } @@ -502,10 +525,6 @@ class CC_EXPORT LayerTreeImpl { // Used for accessing the task runner and debug assertions. TaskRunnerProvider* task_runner_provider() const; - void ApplyScroll(ScrollNode* scroll_node, ScrollState* scroll_state) { - host_impl_->ApplyScroll(scroll_node, scroll_state); - } - // Call this function when you expect there to be a swap buffer. // See swap_promise.h for how to use SwapPromise. // @@ -586,19 +605,31 @@ class CC_EXPORT LayerTreeImpl { // the viewport. void GetViewportSelection(viz::Selection<gfx::SelectionBound>* selection); - void set_browser_controls_shrink_blink_size(bool shrink); bool browser_controls_shrink_blink_size() const { - return browser_controls_shrink_blink_size_; + return browser_controls_params_.browser_controls_shrink_blink_size; } - bool SetCurrentBrowserControlsShownRatio(float ratio); - float CurrentBrowserControlsShownRatio() const { + bool SetCurrentBrowserControlsShownRatio(float top_ratio, float bottom_ratio); + float CurrentTopControlsShownRatio() const { return top_controls_shown_ratio_->Current(IsActiveTree()); } - void SetTopControlsHeight(float top_controls_height); - float top_controls_height() const { return top_controls_height_; } - void PushBrowserControlsFromMainThread(float top_controls_shown_ratio); - void SetBottomControlsHeight(float bottom_controls_height); - float bottom_controls_height() const { return bottom_controls_height_; } + float CurrentBottomControlsShownRatio() const { + return bottom_controls_shown_ratio_->Current(IsActiveTree()); + } + void SetBrowserControlsParams(const BrowserControlsParams& params); + float top_controls_height() const { + return browser_controls_params_.top_controls_height; + } + float top_controls_min_height() const { + return browser_controls_params_.top_controls_min_height; + } + void PushBrowserControlsFromMainThread(float top_controls_shown_ratio, + float bottom_controls_shown_ratio); + float bottom_controls_height() const { + return browser_controls_params_.bottom_controls_height; + } + float bottom_controls_min_height() const { + return browser_controls_params_.bottom_controls_min_height; + } void set_overscroll_behavior(const OverscrollBehavior& behavior); OverscrollBehavior overscroll_behavior() const { @@ -681,8 +712,10 @@ class CC_EXPORT LayerTreeImpl { bool SetPageScaleFactorLimits(float min_page_scale_factor, float max_page_scale_factor); void DidUpdatePageScale(); - void PushBrowserControls(const float* top_controls_shown_ratio); - bool ClampBrowserControlsShownRatio(); + void PushBrowserControls(const float* top_controls_shown_ratio, + const float* bottom_controls_shown_ratio); + bool ClampTopControlsShownRatio(); + bool ClampBottomControlsShownRatio(); private: friend class LayerTreeHost; @@ -800,17 +833,14 @@ class CC_EXPORT LayerTreeImpl { EventListenerProperties event_listener_properties_ [static_cast<size_t>(EventListenerClass::kLast) + 1]; - // Whether or not Blink's viewport size was shrunk by the height of the top - // controls at the time of the last layout. - bool browser_controls_shrink_blink_size_; - float top_controls_height_; - float bottom_controls_height_; + BrowserControlsParams browser_controls_params_; OverscrollBehavior overscroll_behavior_; // The amount that the browser controls are shown from 0 (hidden) to 1 (fully // shown). scoped_refptr<SyncedBrowserControls> top_controls_shown_ratio_; + scoped_refptr<SyncedBrowserControls> bottom_controls_shown_ratio_; std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation_; @@ -822,6 +852,9 @@ class CC_EXPORT LayerTreeImpl { // lifecycle states. See: |LayerTreeLifecycle|. LayerTreeLifecycle lifecycle_; + // Display transform hint to tag frames generated from this tree. + gfx::OverlayTransform display_transform_hint_ = gfx::OVERLAY_TRANSFORM_NONE; + std::vector<LayerTreeHost::PresentationTimeCallback> presentation_callbacks_; }; diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc index bdfe90cb9bc..dcce0e46683 100644 --- a/chromium/cc/trees/layer_tree_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_impl_unittest.cc @@ -4,6 +4,7 @@ #include "cc/trees/layer_tree_impl.h" +#include "base/numerics/ranges.h" #include "cc/layers/heads_up_display_layer_impl.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_raster_source.h" @@ -18,6 +19,17 @@ namespace cc { namespace { +std::pair<gfx::PointF, gfx::PointF> GetVisibleSelectionEndPoints( + const gfx::RectF& rect, + const gfx::PointF& top, + const gfx::PointF& bottom) { + gfx::PointF start(base::ClampToRange(top.x(), rect.x(), rect.right()), + base::ClampToRange(top.y(), rect.y(), rect.bottom())); + gfx::PointF end = + start + gfx::Vector2dF(bottom.x() - top.x(), bottom.y() - top.y()); + return {start, end}; +} + class LayerTreeImplTest : public LayerTreeImplTestBase, public testing::Test { public: LayerTreeImplTest() = default; @@ -1751,13 +1763,13 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) { LayerSelection input; input.start.type = gfx::SelectionBound::LEFT; - input.start.edge_top = gfx::Point(10, 10); - input.start.edge_bottom = gfx::Point(10, 20); + input.start.edge_start = gfx::Point(10, 10); + input.start.edge_end = gfx::Point(10, 20); input.start.layer_id = root->id(); input.end.type = gfx::SelectionBound::RIGHT; - input.end.edge_top = gfx::Point(50, 10); - input.end.edge_bottom = gfx::Point(50, 30); + input.end.edge_start = gfx::Point(50, 10); + input.end.edge_end = gfx::Point(50, 30); input.end.layer_id = root->id(); viz::Selection<gfx::SelectionBound> output; @@ -1771,28 +1783,65 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) { host_impl().active_tree()->RegisterSelection(input); host_impl().active_tree()->GetViewportSelection(&output); EXPECT_EQ(input.start.type, output.start.type()); - EXPECT_EQ(gfx::PointF(input.start.edge_bottom), output.start.edge_bottom()); - EXPECT_EQ(gfx::PointF(input.start.edge_top), output.start.edge_top()); + EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.edge_end()); + EXPECT_EQ(gfx::PointF(input.start.edge_start), output.start.edge_start()); + EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.visible_edge_end()); + EXPECT_EQ(gfx::PointF(input.start.edge_start), + output.start.visible_edge_start()); + EXPECT_TRUE(output.start.visible()); + EXPECT_EQ(input.end.type, output.end.type()); + EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.edge_end()); + EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.edge_start()); + EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.visible_edge_end()); + EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.visible_edge_start()); + EXPECT_TRUE(output.end.visible()); + + // Selection bounds should produce distinct left and right bounds for the + // vertical text. + input.start.type = gfx::SelectionBound::LEFT; + input.start.edge_start = gfx::Point(20, 10); + input.start.edge_end = gfx::Point(10, 10); + input.start.layer_id = root->id(); + + input.end.type = gfx::SelectionBound::RIGHT; + input.end.edge_start = gfx::Point(30, 20); + input.end.edge_end = gfx::Point(50, 20); + input.end.layer_id = root->id(); + + host_impl().active_tree()->RegisterSelection(input); + host_impl().active_tree()->GetViewportSelection(&output); + EXPECT_EQ(input.start.type, output.start.type()); + EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.edge_end()); + EXPECT_EQ(gfx::PointF(input.start.edge_start), output.start.edge_start()); + EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.visible_edge_end()); + EXPECT_EQ(gfx::PointF(input.start.edge_start), + output.start.visible_edge_start()); EXPECT_TRUE(output.start.visible()); EXPECT_EQ(input.end.type, output.end.type()); - EXPECT_EQ(gfx::PointF(input.end.edge_bottom), output.end.edge_bottom()); - EXPECT_EQ(gfx::PointF(input.end.edge_top), output.end.edge_top()); + EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.edge_end()); + EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.edge_start()); + EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.visible_edge_end()); + EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.visible_edge_start()); EXPECT_TRUE(output.end.visible()); // Insertion bounds should produce identical left and right bounds. LayerSelection insertion_input; insertion_input.start.type = gfx::SelectionBound::CENTER; - insertion_input.start.edge_top = gfx::Point(15, 10); - insertion_input.start.edge_bottom = gfx::Point(15, 30); + insertion_input.start.edge_start = gfx::Point(15, 10); + insertion_input.start.edge_end = gfx::Point(15, 30); insertion_input.start.layer_id = root->id(); insertion_input.end = insertion_input.start; host_impl().active_tree()->RegisterSelection(insertion_input); host_impl().active_tree()->GetViewportSelection(&output); EXPECT_EQ(insertion_input.start.type, output.start.type()); - EXPECT_EQ(gfx::PointF(insertion_input.start.edge_bottom), - output.start.edge_bottom()); - EXPECT_EQ(gfx::PointF(insertion_input.start.edge_top), - output.start.edge_top()); + EXPECT_EQ(gfx::PointF(insertion_input.start.edge_end), + output.start.edge_end()); + EXPECT_EQ(gfx::PointF(insertion_input.start.edge_start), + output.start.edge_start()); + EXPECT_EQ(gfx::PointF(insertion_input.start.edge_end), + output.start.visible_edge_end()); + EXPECT_EQ(gfx::PointF(insertion_input.start.edge_start), + output.start.visible_edge_start()); EXPECT_TRUE(output.start.visible()); EXPECT_EQ(output.start, output.end); } @@ -1827,52 +1876,117 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) { LayerSelection input; input.start.type = gfx::SelectionBound::LEFT; - input.start.edge_top = gfx::Point(25, 10); - input.start.edge_bottom = gfx::Point(25, 30); + input.start.edge_start = gfx::Point(25, 10); + input.start.edge_end = gfx::Point(25, 30); input.start.layer_id = clipped_layer->id(); input.end.type = gfx::SelectionBound::RIGHT; - input.end.edge_top = gfx::Point(75, 10); - input.end.edge_bottom = gfx::Point(75, 30); + input.end.edge_start = gfx::Point(75, 10); + input.end.edge_end = gfx::Point(75, 30); input.end.layer_id = clipped_layer->id(); host_impl().active_tree()->RegisterSelection(input); - // The left bound should be occluded by the clip layer. + // The right bound should be occluded by the clip layer. viz::Selection<gfx::SelectionBound> output; host_impl().active_tree()->GetViewportSelection(&output); EXPECT_EQ(input.start.type, output.start.type()); - auto expected_output_start_top = gfx::PointF(input.start.edge_top); - auto expected_output_edge_botom = gfx::PointF(input.start.edge_bottom); - expected_output_start_top.Offset(clipping_offset.x(), clipping_offset.y()); - expected_output_edge_botom.Offset(clipping_offset.x(), clipping_offset.y()); - EXPECT_EQ(expected_output_start_top, output.start.edge_top()); - EXPECT_EQ(expected_output_edge_botom, output.start.edge_bottom()); + auto expected_output_edge_start = gfx::PointF(input.start.edge_start); + auto expected_output_edge_end = gfx::PointF(input.start.edge_end); + expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y()); + expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y()); + EXPECT_EQ(expected_output_edge_start, output.start.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.edge_end()); + EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end()); + EXPECT_TRUE(output.start.visible()); + EXPECT_EQ(input.end.type, output.end.type()); + expected_output_edge_start = gfx::PointF(input.end.edge_start); + expected_output_edge_end = gfx::PointF(input.end.edge_end); + expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y()); + expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y()); + EXPECT_EQ(expected_output_edge_start, output.end.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.end.edge_end()); + + gfx::RectF visible_layer_rect(clipped_layer->visible_layer_rect()); + gfx::PointF expected_output_visible_edge_start; + gfx::PointF expected_output_visible_edge_end; + std::tie(expected_output_visible_edge_start, + expected_output_visible_edge_end) = + GetVisibleSelectionEndPoints(visible_layer_rect, + gfx::PointF(input.end.edge_start), + gfx::PointF(input.end.edge_end)); + expected_output_visible_edge_start.Offset(clipping_offset.x(), + clipping_offset.y()); + expected_output_visible_edge_end.Offset(clipping_offset.x(), + clipping_offset.y()); + + EXPECT_EQ(expected_output_visible_edge_start, + output.end.visible_edge_start()); + EXPECT_EQ(expected_output_visible_edge_end, output.end.visible_edge_end()); + EXPECT_FALSE(output.end.visible()); + + // The right bound should be occluded by the clip layer for the vertical text. + input.start.type = gfx::SelectionBound::LEFT; + input.start.edge_start = gfx::Point(25, 10); + input.start.edge_end = gfx::Point(15, 10); + input.start.layer_id = clipped_layer->id(); + + input.end.type = gfx::SelectionBound::RIGHT; + input.end.edge_start = gfx::Point(75, 30); + input.end.edge_end = gfx::Point(85, 30); + input.end.layer_id = clipped_layer->id(); + host_impl().active_tree()->RegisterSelection(input); + + host_impl().active_tree()->GetViewportSelection(&output); + EXPECT_EQ(input.start.type, output.start.type()); + expected_output_edge_start = gfx::PointF(input.start.edge_start); + expected_output_edge_end = gfx::PointF(input.start.edge_end); + expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y()); + expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y()); + EXPECT_EQ(expected_output_edge_start, output.start.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.edge_end()); + EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end()); EXPECT_TRUE(output.start.visible()); EXPECT_EQ(input.end.type, output.end.type()); - auto expected_output_end_top = gfx::PointF(input.end.edge_top); - auto expected_output_end_bottom = gfx::PointF(input.end.edge_bottom); - expected_output_end_bottom.Offset(clipping_offset.x(), clipping_offset.y()); - expected_output_end_top.Offset(clipping_offset.x(), clipping_offset.y()); - EXPECT_EQ(expected_output_end_top, output.end.edge_top()); - EXPECT_EQ(expected_output_end_bottom, output.end.edge_bottom()); + expected_output_edge_start = gfx::PointF(input.end.edge_start); + expected_output_edge_end = gfx::PointF(input.end.edge_end); + expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y()); + expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y()); + EXPECT_EQ(expected_output_edge_start, output.end.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.end.edge_end()); + + std::tie(expected_output_visible_edge_start, + expected_output_visible_edge_end) = + GetVisibleSelectionEndPoints(visible_layer_rect, + gfx::PointF(input.end.edge_start), + gfx::PointF(input.end.edge_end)); + expected_output_visible_edge_start.Offset(clipping_offset.x(), + clipping_offset.y()); + expected_output_visible_edge_end.Offset(clipping_offset.x(), + clipping_offset.y()); + + EXPECT_EQ(expected_output_visible_edge_start, + output.end.visible_edge_start()); + EXPECT_EQ(expected_output_visible_edge_end, output.end.visible_edge_end()); EXPECT_FALSE(output.end.visible()); // Handles outside the viewport bounds should be marked invisible. - input.start.edge_top = gfx::Point(-25, 0); - input.start.edge_bottom = gfx::Point(-25, 20); + input.start.edge_start = gfx::Point(-25, 0); + input.start.edge_end = gfx::Point(-25, 20); host_impl().active_tree()->RegisterSelection(input); host_impl().active_tree()->GetViewportSelection(&output); EXPECT_FALSE(output.start.visible()); - input.start.edge_top = gfx::Point(0, -25); - input.start.edge_bottom = gfx::Point(0, -5); + input.start.edge_start = gfx::Point(0, -25); + input.start.edge_end = gfx::Point(0, -5); host_impl().active_tree()->RegisterSelection(input); host_impl().active_tree()->GetViewportSelection(&output); EXPECT_FALSE(output.start.visible()); - // If the handle bottom is partially visible, the handle is marked visible. - input.start.edge_top = gfx::Point(0, -20); - input.start.edge_bottom = gfx::Point(0, 1); + // If the handle end is partially visible, the handle is marked visible. + input.start.edge_start = gfx::Point(0, -20); + input.start.edge_end = gfx::Point(0, 1); host_impl().active_tree()->RegisterSelection(input); host_impl().active_tree()->GetViewportSelection(&output); EXPECT_TRUE(output.start.visible()); @@ -1921,13 +2035,13 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) { LayerSelection input; input.start.type = gfx::SelectionBound::LEFT; - input.start.edge_top = gfx::Point(10, 10); - input.start.edge_bottom = gfx::Point(10, 30); + input.start.edge_start = gfx::Point(10, 10); + input.start.edge_end = gfx::Point(10, 30); input.start.layer_id = page_scale_layer->id(); input.end.type = gfx::SelectionBound::RIGHT; - input.end.edge_top = gfx::Point(0, 0); - input.end.edge_bottom = gfx::Point(0, 20); + input.end.edge_start = gfx::Point(0, 0); + input.end.edge_end = gfx::Point(0, 20); input.end.layer_id = sub_layer->id(); host_impl().active_tree()->RegisterSelection(input); @@ -1936,23 +2050,27 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) { viz::Selection<gfx::SelectionBound> output; host_impl().active_tree()->GetViewportSelection(&output); EXPECT_EQ(input.start.type, output.start.type()); - auto expected_output_start_top = gfx::PointF(input.start.edge_top); - auto expected_output_start_bottom = gfx::PointF(input.start.edge_bottom); - expected_output_start_top.Scale(page_scale_factor); - expected_output_start_bottom.Scale(page_scale_factor); - EXPECT_EQ(expected_output_start_top, output.start.edge_top()); - EXPECT_EQ(expected_output_start_bottom, output.start.edge_bottom()); + auto expected_output_edge_start = gfx::PointF(input.start.edge_start); + auto expected_output_edge_end = gfx::PointF(input.start.edge_end); + expected_output_edge_start.Scale(page_scale_factor); + expected_output_edge_end.Scale(page_scale_factor); + EXPECT_EQ(expected_output_edge_start, output.start.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.edge_end()); + EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end()); EXPECT_TRUE(output.start.visible()); EXPECT_EQ(input.end.type, output.end.type()); - auto expected_output_end_top = gfx::PointF(input.end.edge_top); - auto expected_output_end_bottom = gfx::PointF(input.end.edge_bottom); - expected_output_end_top.Offset(sub_layer_offset.x(), sub_layer_offset.y()); - expected_output_end_bottom.Offset(sub_layer_offset.x(), sub_layer_offset.y()); - expected_output_end_top.Scale(page_scale_factor); - expected_output_end_bottom.Scale(page_scale_factor); - EXPECT_EQ(expected_output_end_top, output.end.edge_top()); - EXPECT_EQ(expected_output_end_bottom, output.end.edge_bottom()); + expected_output_edge_start = gfx::PointF(input.end.edge_start); + expected_output_edge_end = gfx::PointF(input.end.edge_end); + expected_output_edge_start.Offset(sub_layer_offset.x(), sub_layer_offset.y()); + expected_output_edge_end.Offset(sub_layer_offset.x(), sub_layer_offset.y()); + expected_output_edge_start.Scale(page_scale_factor); + expected_output_edge_end.Scale(page_scale_factor); + EXPECT_EQ(expected_output_edge_start, output.end.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.end.edge_end()); + EXPECT_EQ(expected_output_edge_start, output.end.visible_edge_start()); + EXPECT_EQ(expected_output_edge_end, output.end.visible_edge_end()); EXPECT_TRUE(output.end.visible()); } @@ -1979,13 +2097,13 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForDSFEnabled) { LayerSelection input; input.start.type = gfx::SelectionBound::LEFT; - input.start.edge_top = gfx::Point(10, 10); - input.start.edge_bottom = gfx::Point(10, 30); + input.start.edge_start = gfx::Point(10, 10); + input.start.edge_end = gfx::Point(10, 30); input.start.layer_id = root->id(); input.end.type = gfx::SelectionBound::RIGHT; - input.end.edge_top = gfx::Point(0, 0); - input.end.edge_bottom = gfx::Point(0, 20); + input.end.edge_start = gfx::Point(0, 0); + input.end.edge_end = gfx::Point(0, 20); input.end.layer_id = sub_layer->id(); host_impl().active_tree()->RegisterSelection(input); @@ -1994,27 +2112,31 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForDSFEnabled) { viz::Selection<gfx::SelectionBound> output; host_impl().active_tree()->GetViewportSelection(&output); EXPECT_EQ(input.start.type, output.start.type()); - auto expected_output_start_top = gfx::PointF(input.start.edge_top); - auto expected_output_edge_bottom = gfx::PointF(input.start.edge_bottom); - expected_output_start_top.Scale( + auto expected_output_edge_start = gfx::PointF(input.start.edge_start); + auto expected_output_edge_end = gfx::PointF(input.start.edge_end); + expected_output_edge_start.Scale( 1.f / (device_scale_factor * painted_device_scale_factor)); - expected_output_edge_bottom.Scale( + expected_output_edge_end.Scale( 1.f / (device_scale_factor * painted_device_scale_factor)); - EXPECT_EQ(expected_output_start_top, output.start.edge_top()); - EXPECT_EQ(expected_output_edge_bottom, output.start.edge_bottom()); + EXPECT_EQ(expected_output_edge_start, output.start.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.edge_end()); + EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start()); + EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end()); EXPECT_TRUE(output.start.visible()); EXPECT_EQ(input.end.type, output.end.type()); - auto expected_output_end_top = gfx::PointF(input.end.edge_top); - auto expected_output_end_bottom = gfx::PointF(input.end.edge_bottom); - expected_output_end_top.Offset(sub_layer_offset.x(), sub_layer_offset.y()); - expected_output_end_bottom.Offset(sub_layer_offset.x(), sub_layer_offset.y()); - expected_output_end_top.Scale( + expected_output_edge_start = gfx::PointF(input.end.edge_start); + expected_output_edge_end = gfx::PointF(input.end.edge_end); + expected_output_edge_start.Offset(sub_layer_offset.x(), sub_layer_offset.y()); + expected_output_edge_end.Offset(sub_layer_offset.x(), sub_layer_offset.y()); + expected_output_edge_start.Scale( 1.f / (device_scale_factor * painted_device_scale_factor)); - expected_output_end_bottom.Scale( + expected_output_edge_end.Scale( 1.f / (device_scale_factor * painted_device_scale_factor)); - EXPECT_EQ(expected_output_end_top, output.end.edge_top()); - EXPECT_EQ(expected_output_end_bottom, output.end.edge_bottom()); + EXPECT_EQ(expected_output_edge_start, output.end.edge_start()); + EXPECT_EQ(expected_output_edge_end, output.end.edge_end()); + EXPECT_EQ(expected_output_edge_start, output.end.visible_edge_start()); + EXPECT_EQ(expected_output_edge_end, output.end.visible_edge_end()); EXPECT_TRUE(output.end.visible()); } @@ -2043,13 +2165,13 @@ TEST_F(LayerTreeImplTest, SelectionBoundsWithLargeTransforms) { LayerSelection input; input.start.type = gfx::SelectionBound::LEFT; - input.start.edge_top = gfx::Point(10, 10); - input.start.edge_bottom = gfx::Point(10, 20); + input.start.edge_start = gfx::Point(10, 10); + input.start.edge_end = gfx::Point(10, 20); input.start.layer_id = grand_child->id(); input.end.type = gfx::SelectionBound::RIGHT; - input.end.edge_top = gfx::Point(50, 10); - input.end.edge_bottom = gfx::Point(50, 30); + input.end.edge_start = gfx::Point(50, 10); + input.end.edge_end = gfx::Point(50, 30); input.end.layer_id = grand_child->id(); host_impl().active_tree()->RegisterSelection(input); @@ -2057,7 +2179,7 @@ TEST_F(LayerTreeImplTest, SelectionBoundsWithLargeTransforms) { viz::Selection<gfx::SelectionBound> output; host_impl().active_tree()->GetViewportSelection(&output); - // edge_bottom and edge_top aren't allowed to have NaNs, so the selection + // edge_end and edge_start aren't allowed to have NaNs, so the selection // should be empty. EXPECT_EQ(gfx::SelectionBound(), output.start); EXPECT_EQ(gfx::SelectionBound(), output.end); diff --git a/chromium/cc/trees/layer_tree_mutator.cc b/chromium/cc/trees/layer_tree_mutator.cc index 9e285596b4a..ecd0d6671bd 100644 --- a/chromium/cc/trees/layer_tree_mutator.cc +++ b/chromium/cc/trees/layer_tree_mutator.cc @@ -36,9 +36,6 @@ bool AnimationWorkletInput::ValidateId(int worklet_id) const { }) && std::all_of( removed_animations.cbegin(), removed_animations.cend(), - [worklet_id](auto& it) { return it.worklet_id == worklet_id; }) && - std::all_of( - peeked_animations.cbegin(), peeked_animations.cend(), [worklet_id](auto& it) { return it.worklet_id == worklet_id; }); } #endif @@ -80,12 +77,6 @@ void MutatorInputState::Remove(WorkletAnimationId worklet_animation_id) { worklet_input.removed_animations.push_back(worklet_animation_id); } -void MutatorInputState::Peek(WorkletAnimationId worklet_animation_id) { - AnimationWorkletInput& worklet_input = - EnsureWorkletEntry(worklet_animation_id.worklet_id); - worklet_input.peeked_animations.push_back(worklet_animation_id); -} - std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState( int worklet_id) { auto it = inputs_.find(worklet_id); diff --git a/chromium/cc/trees/layer_tree_mutator.h b/chromium/cc/trees/layer_tree_mutator.h index ff1c32579c6..dc9ea0f146a 100644 --- a/chromium/cc/trees/layer_tree_mutator.h +++ b/chromium/cc/trees/layer_tree_mutator.h @@ -51,10 +51,18 @@ struct CC_EXPORT WorkletAnimationId { // animation_id is only guaranteed to be unique per animation worklet. int animation_id; + // Initialize with invalid id. + WorkletAnimationId() : worklet_id(0), animation_id(0) {} + WorkletAnimationId(int worklet_id, int animation_id) + : worklet_id(worklet_id), animation_id(animation_id) {} + inline bool operator==(const WorkletAnimationId& rhs) const { return (this->worklet_id == rhs.worklet_id) && (this->animation_id == rhs.animation_id); } + // Returns true if the WorkletAnimationId has been initialized with a valid + // id. + explicit operator bool() const { return !!worklet_id || !!animation_id; } }; struct CC_EXPORT AnimationWorkletInput { @@ -87,7 +95,6 @@ struct CC_EXPORT AnimationWorkletInput { std::vector<AddAndUpdateState> added_and_updated_animations; std::vector<UpdateState> updated_animations; std::vector<WorkletAnimationId> removed_animations; - std::vector<WorkletAnimationId> peeked_animations; AnimationWorkletInput(); AnimationWorkletInput(const AnimationWorkletInput&) = delete; @@ -113,12 +120,6 @@ class CC_EXPORT MutatorInputState { void Add(AnimationWorkletInput::AddAndUpdateState&& state); void Update(AnimationWorkletInput::UpdateState&& state); void Remove(WorkletAnimationId worklet_animation_id); - // |Update| asks for the animation to *animate* given a current time and - // return the output value while |Peek| only asks for the last output value - // (if one available) without requiring animate or providing a current time. - // In particular, composited animations are updated from compositor and peeked - // from main thread. - void Peek(WorkletAnimationId worklet_animation_id); // Returns input for animation worklet with the given |scope_id| and nullptr // if there is no input. diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h index 182eb5f6873..0743417d59c 100644 --- a/chromium/cc/trees/layer_tree_settings.h +++ b/chromium/cc/trees/layer_tree_settings.h @@ -73,6 +73,10 @@ class CC_EXPORT LayerTreeSettings { // If set, indicates the largest tile size we will use for GPU Raster. If not // set, no limit is enforced. gfx::Size max_gpu_raster_tile_size; + // Even for really wide viewports, at some point GPU raster should use + // less than 4 tiles to fill the viewport. This is set to 256 as a + // sane minimum for now, but we might want to tune this for low-end. + int min_height_for_gpu_raster_tile = 256; gfx::Size minimum_occlusion_tracking_size; // 3000 pixels should give sufficient area for prepainting. // Note this value is specified with an ideal contents scale in mind. That @@ -150,10 +154,6 @@ class CC_EXPORT LayerTreeSettings { // the device scale factor. bool use_painted_device_scale_factor = false; - // Whether a HitTestRegionList should be built from the active layer tree when - // submitting a CompositorFrame. - bool build_hit_test_data = false; - // When false, sync tokens are expected to be present, and are verified, // before transfering gpu resources to the display compositor. bool delegated_sync_points_required = true; diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc index 6b306c718bd..2db1b0a5560 100644 --- a/chromium/cc/trees/property_tree.cc +++ b/chromium/cc/trees/property_tree.cc @@ -25,8 +25,7 @@ namespace cc { template <typename T> -PropertyTree<T>::PropertyTree() - : needs_update_(false) { +PropertyTree<T>::PropertyTree() : needs_update_(false) { nodes_.push_back(T()); back()->id = kRootNodeId; back()->parent_id = kInvalidNodeId; @@ -1148,11 +1147,12 @@ ScrollTree::~ScrollTree() = default; ScrollTree& ScrollTree::operator=(const ScrollTree& from) { PropertyTree::operator=(from); currently_scrolling_node_id_ = kInvalidNodeId; - // Maps for ScrollOffsets/SyncedScrollOffsets are intentionally ommitted here + // Maps for ScrollOffsets/SyncedScrollOffsets are intentionally omitted here // since we can not directly copy them. Pushing of these updates from main // currently depends on Layer properties for scroll offset animation changes // (setting clobber_active_value for scroll offset animations interrupted on // the main thread) being pushed to impl first. + // |callbacks_| is omitted because it's for the main thread only. return *this; } @@ -1161,6 +1161,8 @@ bool ScrollTree::operator==(const ScrollTree& other) const { return false; if (synced_scroll_offset_map_ != other.synced_scroll_offset_map_) return false; + if (callbacks_.get() != other.callbacks_.get()) + return false; bool is_currently_scrolling_node_equal = currently_scrolling_node_id_ == other.currently_scrolling_node_id_; @@ -1173,6 +1175,7 @@ void ScrollTree::CopyCompleteTreeState(const ScrollTree& other) { currently_scrolling_node_id_ = other.currently_scrolling_node_id_; scroll_offset_map_ = other.scroll_offset_map_; synced_scroll_offset_map_ = other.synced_scroll_offset_map_; + callbacks_ = other.callbacks_; } #endif @@ -1202,7 +1205,9 @@ void ScrollTree::clear() { #if DCHECK_IS_ON() ScrollTree tree; - if (!property_trees()->is_main_thread) { + if (property_trees()->is_main_thread) { + tree.callbacks_ = callbacks_; + } else { DCHECK(scroll_offset_map_.empty()); tree.currently_scrolling_node_id_ = currently_scrolling_node_id_; tree.synced_scroll_offset_map_ = synced_scroll_offset_map_; @@ -1417,6 +1422,7 @@ void ScrollTree::CollectScrollDeltas(ScrollAndScaleSet* scroll_info, ElementId inner_viewport_scroll_element_id, bool use_fractional_deltas) { DCHECK(!property_trees()->is_main_thread); + TRACE_EVENT0("cc", "ScrollTree::CollectScrollDeltas"); for (auto map_entry : synced_scroll_offset_map_) { gfx::ScrollOffset scroll_delta = PullDeltaForMainThread(map_entry.second.get(), use_fractional_deltas); @@ -1424,12 +1430,25 @@ void ScrollTree::CollectScrollDeltas(ScrollAndScaleSet* scroll_info, ElementId id = map_entry.first; if (!scroll_delta.IsZero()) { + TRACE_EVENT_INSTANT2("cc", "CollectScrollDeltas", + TRACE_EVENT_SCOPE_THREAD, "x", scroll_delta.x(), "y", + scroll_delta.y()); + // The snap targets will change on cc only if the node was scrolled, so it + // is safe to update the snap targets only when the scroll delta is not + // zero. + ScrollNode* scroll_node = FindNodeFromElementId(id); + base::Optional<TargetSnapAreaElementIds> snap_target_ids; + if (scroll_node && scroll_node->snap_container_data) { + snap_target_ids = scroll_node->snap_container_data.value() + .GetTargetSnapAreaElementIds(); + } + ScrollAndScaleSet::ScrollUpdateInfo update(id, scroll_delta, + snap_target_ids); if (id == inner_viewport_scroll_element_id) { // Inner (visual) viewport is stored separately. - scroll_info->inner_viewport_scroll.element_id = id; - scroll_info->inner_viewport_scroll.scroll_delta = scroll_delta; + scroll_info->inner_viewport_scroll = std::move(update); } else { - scroll_info->scrolls.push_back({id, scroll_delta}); + scroll_info->scrolls.push_back(std::move(update)); } } } @@ -1581,23 +1600,6 @@ const gfx::ScrollOffset ScrollTree::GetScrollOffsetDeltaForTesting( return gfx::ScrollOffset(); } -void ScrollTree::DistributeScroll(ScrollNode* scroll_node, - ScrollState* scroll_state) { - DCHECK(scroll_node && scroll_state); - if (scroll_state->FullyConsumed()) - return; - scroll_state->DistributeToScrollChainDescendant(); - - // If we're currently scrolling a node other than this one, prevent the scroll - // from propagating to this node. - if (scroll_state->delta_consumed_for_scroll_sequence() && - scroll_state->current_native_scrolling_node()->id != scroll_node->id) { - return; - } - - scroll_state->layer_tree_impl()->ApplyScroll(scroll_node, scroll_state); -} - gfx::Vector2dF ScrollTree::ScrollBy(ScrollNode* scroll_node, const gfx::Vector2dF& scroll, LayerTreeImpl* layer_tree_impl) { @@ -1626,6 +1628,27 @@ gfx::ScrollOffset ScrollTree::ClampScrollOffsetToLimits( return offset; } +void ScrollTree::SetScrollCallbacks(base::WeakPtr<ScrollCallbacks> callbacks) { + DCHECK(property_trees()->is_main_thread); + callbacks_ = std::move(callbacks); +} + +void ScrollTree::NotifyDidScroll( + ElementId scroll_element_id, + const gfx::ScrollOffset& scroll_offset, + const base::Optional<TargetSnapAreaElementIds>& snap_target_ids) { + DCHECK(property_trees()->is_main_thread); + if (callbacks_) + callbacks_->DidScroll(scroll_element_id, scroll_offset, snap_target_ids); +} + +void ScrollTree::NotifyDidChangeScrollbarsHidden(ElementId scroll_element_id, + bool hidden) { + DCHECK(property_trees()->is_main_thread); + if (callbacks_) + callbacks_->DidChangeScrollbarsHidden(scroll_element_id, hidden); +} + PropertyTreesCachedData::PropertyTreesCachedData() : transform_tree_update_number(0) { animation_scales.clear(); diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h index 8370ad169cf..7cde294f85c 100644 --- a/chromium/cc/trees/property_tree.h +++ b/chromium/cc/trees/property_tree.h @@ -11,9 +11,12 @@ #include <unordered_map> #include <vector> +#include "base/callback.h" #include "base/containers/flat_map.h" +#include "base/memory/weak_ptr.h" #include "cc/base/synced_property.h" #include "cc/cc_export.h" +#include "cc/input/scroll_snap_data.h" #include "cc/paint/element_id.h" #include "cc/paint/filter_operations.h" #include "cc/trees/mutator_host_client.h" @@ -26,7 +29,7 @@ namespace base { namespace trace_event { class TracedValue; } -} +} // namespace base namespace viz { class CopyOutputRequest; @@ -36,7 +39,6 @@ namespace cc { class LayerTreeImpl; class RenderSurfaceImpl; -class ScrollState; struct ClipNode; struct EffectNode; struct ScrollAndScaleSet; @@ -362,6 +364,23 @@ class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> { std::vector<std::unique_ptr<RenderSurfaceImpl>> render_surfaces_; }; +// These callbacks are called in the main thread to notify changes of scroll +// information in the compositor thread during commit. +class ScrollCallbacks { + public: + // Called after the composited scroll offset changed. + virtual void DidScroll(ElementId scroll_element_id, + const gfx::ScrollOffset&, + const base::Optional<TargetSnapAreaElementIds>&) = 0; + // Called after the hidden status of composited scrollbars changed. Note that + // |scroll_element_id| is the element id of the scroll not of the scrollbars. + virtual void DidChangeScrollbarsHidden(ElementId scroll_element_id, + bool hidden) = 0; + + protected: + virtual ~ScrollCallbacks() {} +}; + class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { public: ScrollTree(); @@ -442,7 +461,6 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { const gfx::ScrollOffset GetScrollOffsetDeltaForTesting(ElementId id) const; void CollectScrollDeltasForTesting(); - void DistributeScroll(ScrollNode* scroll_node, ScrollState* scroll_state); gfx::Vector2dF ScrollBy(ScrollNode* scroll_node, const gfx::Vector2dF& scroll, LayerTreeImpl* layer_tree_impl); @@ -459,6 +477,15 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { ScrollNode* FindNodeFromElementId(ElementId id); const ScrollNode* FindNodeFromElementId(ElementId id) const; + void SetScrollCallbacks(base::WeakPtr<ScrollCallbacks> callbacks); + + void NotifyDidScroll( + ElementId scroll_element_id, + const gfx::ScrollOffset& scroll_offset, + const base::Optional<TargetSnapAreaElementIds>& snap_target_ids); + void NotifyDidChangeScrollbarsHidden(ElementId scroll_element_id, + bool hidden); + private: using ScrollOffsetMap = base::flat_map<ElementId, gfx::ScrollOffset>; using SyncedScrollOffsetMap = @@ -474,6 +501,8 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { ScrollOffsetMap scroll_offset_map_; SyncedScrollOffsetMap synced_scroll_offset_map_; + base::WeakPtr<ScrollCallbacks> callbacks_; + SyncedScrollOffset* GetOrCreateSyncedScrollOffset(ElementId id); gfx::ScrollOffset PullDeltaForMainThread(SyncedScrollOffset* scroll_offset, bool use_fractional_deltas); diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc index a43c4b40b7d..e35b3cb4999 100644 --- a/chromium/cc/trees/proxy_impl.cc +++ b/chromium/cc/trees/proxy_impl.cc @@ -278,7 +278,13 @@ void ProxyImpl::NotifyReadyToCommitOnImpl( DCHECK(!blocked_main_commit().layer_tree_host); blocked_main_commit().layer_tree_host = layer_tree_host; - scheduler_->NotifyReadyToCommit(); + + // Extract metrics data from the layer tree host and send them to the + // scheduler to pass them to the compositor_timing_history object. + std::unique_ptr<BeginMainFrameMetrics> main_frame_metrics = + layer_tree_host->begin_main_frame_metrics(); + + scheduler_->NotifyReadyToCommit(std::move(main_frame_metrics)); } void ProxyImpl::DidLoseLayerTreeFrameSinkOnImplThread() { diff --git a/chromium/cc/trees/render_frame_metadata.cc b/chromium/cc/trees/render_frame_metadata.cc index b666e9c6633..158f4a63820 100644 --- a/chromium/cc/trees/render_frame_metadata.cc +++ b/chromium/cc/trees/render_frame_metadata.cc @@ -45,7 +45,8 @@ bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const { root_layer_size == other.root_layer_size && has_transparent_background == other.has_transparent_background && #endif - local_surface_id_allocation == other.local_surface_id_allocation; + local_surface_id_allocation == other.local_surface_id_allocation && + new_vertical_scroll_direction == other.new_vertical_scroll_direction; } bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) const { diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h index 400eeaefe0d..8d71c87c394 100644 --- a/chromium/cc/trees/render_frame_metadata.h +++ b/chromium/cc/trees/render_frame_metadata.h @@ -11,6 +11,7 @@ #include "cc/cc_export.h" #include "components/viz/common/quads/selection.h" #include "components/viz/common/surfaces/local_surface_id_allocation.h" +#include "components/viz/common/vertical_scroll_direction.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" @@ -75,6 +76,14 @@ class CC_EXPORT RenderFrameMetadata { float top_controls_height = 0.f; float top_controls_shown_ratio = 0.f; + // Indicates a change in the vertical scroll direction of the root layer since + // the last drawn render frame. If no change occurred, this value is |kNull|. + // Note that if a scroll in a given direction occurs, the scroll is completed, + // and then another scroll in the *same* direction occurs, we will not + // consider the second scroll event to have caused a change in direction. + viz::VerticalScrollDirection new_vertical_scroll_direction = + viz::VerticalScrollDirection::kNull; + #if defined(OS_ANDROID) // Used to position Android bottom bar, whose position is computed by the // renderer compositor. diff --git a/chromium/cc/trees/scroll_and_scale_set.cc b/chromium/cc/trees/scroll_and_scale_set.cc index e2d08c839c1..6049e60b436 100644 --- a/chromium/cc/trees/scroll_and_scale_set.cc +++ b/chromium/cc/trees/scroll_and_scale_set.cc @@ -12,6 +12,7 @@ ScrollAndScaleSet::ScrollAndScaleSet() : page_scale_delta(1.f), is_pinch_gesture_active(false), top_controls_delta(0.f), + bottom_controls_delta(0.f), browser_controls_constraint(BrowserControlsState::kBoth), browser_controls_constraint_changed(false), scroll_gesture_did_end(false), @@ -19,4 +20,20 @@ ScrollAndScaleSet::ScrollAndScaleSet() ScrollAndScaleSet::~ScrollAndScaleSet() = default; +ScrollAndScaleSet::ScrollUpdateInfo::ScrollUpdateInfo() = default; + +ScrollAndScaleSet::ScrollUpdateInfo::ScrollUpdateInfo( + ElementId id, + gfx::ScrollOffset delta, + base::Optional<TargetSnapAreaElementIds> snap_target_ids) + : element_id(id), + scroll_delta(delta), + snap_target_element_ids(snap_target_ids) {} + +ScrollAndScaleSet::ScrollUpdateInfo::ScrollUpdateInfo( + const ScrollUpdateInfo& other) = default; + +ScrollAndScaleSet::ScrollUpdateInfo& ScrollAndScaleSet::ScrollUpdateInfo:: +operator=(const ScrollUpdateInfo& other) = default; + } // namespace cc diff --git a/chromium/cc/trees/scroll_and_scale_set.h b/chromium/cc/trees/scroll_and_scale_set.h index 41687918fb2..cef0850f33b 100644 --- a/chromium/cc/trees/scroll_and_scale_set.h +++ b/chromium/cc/trees/scroll_and_scale_set.h @@ -9,6 +9,7 @@ #include "cc/cc_export.h" #include "cc/input/browser_controls_state.h" +#include "cc/input/scroll_snap_data.h" #include "cc/paint/element_id.h" #include "cc/trees/layer_tree_host_client.h" #include "ui/gfx/geometry/scroll_offset.h" @@ -27,12 +28,24 @@ struct CC_EXPORT ScrollAndScaleSet { ScrollAndScaleSet& operator=(const ScrollAndScaleSet&) = delete; struct CC_EXPORT ScrollUpdateInfo { + ScrollUpdateInfo(); + ScrollUpdateInfo(ElementId id, + gfx::ScrollOffset delta, + base::Optional<TargetSnapAreaElementIds> snap_target_ids); + ScrollUpdateInfo(const ScrollUpdateInfo& other); + ScrollUpdateInfo& operator=(const ScrollUpdateInfo&); ElementId element_id; gfx::ScrollOffset scroll_delta; + // The target snap area element ids of the scrolling element. + // This will have a value if the scrolled element's scroll node has snap + // container data and the scroll delta is non-zero. + base::Optional<TargetSnapAreaElementIds> snap_target_element_ids; + bool operator==(const ScrollUpdateInfo& other) const { return element_id == other.element_id && - scroll_delta == other.scroll_delta; + scroll_delta == other.scroll_delta && + snap_target_element_ids == other.snap_target_element_ids; } }; @@ -59,6 +72,7 @@ struct CC_EXPORT ScrollAndScaleSet { ElementId scroll_latched_element_id; float top_controls_delta; + float bottom_controls_delta; // Used to communicate scrollbar visibility from Impl thread to Blink. // Scrollbar input is handled by Blink but the compositor thread animates diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc index 64cf02bdbf2..2a235b6dd90 100644 --- a/chromium/cc/trees/single_thread_proxy.cc +++ b/chromium/cc/trees/single_thread_proxy.cc @@ -195,8 +195,9 @@ void SingleThreadProxy::DoCommit() { layer_tree_host_->FinishCommitOnImplThread(host_impl_.get()); - if (scheduler_on_impl_thread_) + if (scheduler_on_impl_thread_) { scheduler_on_impl_thread_->DidCommit(); + } IssueImageDecodeFinishedCallbacks(); host_impl_->CommitComplete(); @@ -872,8 +873,10 @@ void SingleThreadProxy::DoPainting() { // TODO(enne): SingleThreadProxy does not support cancelling commits yet, // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside // thread_proxy.cc - if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->NotifyReadyToCommit(); + if (scheduler_on_impl_thread_) { + scheduler_on_impl_thread_->NotifyReadyToCommit( + layer_tree_host_->begin_main_frame_metrics()); + } } void SingleThreadProxy::BeginMainFrameAbortedOnImplThread( diff --git a/chromium/cc/trees/ukm_manager.cc b/chromium/cc/trees/ukm_manager.cc index 7b8c98100d6..e860874015f 100644 --- a/chromium/cc/trees/ukm_manager.cc +++ b/chromium/cc/trees/ukm_manager.cc @@ -90,4 +90,83 @@ void UkmManager::RecordRenderingUkm() { total_num_of_checkerboarded_images_ = 0; } +void UkmManager::RecordThroughputUKM( + FrameSequenceTrackerType tracker_type, + FrameSequenceTracker::ThreadType thread_type, + int64_t throughput) const { + ukm::builders::Graphics_Smoothness_Throughput builder(source_id_); + switch (thread_type) { + case FrameSequenceTracker::ThreadType::kMain: { + switch (tracker_type) { +#define CASE_FOR_MAIN_THREAD_TRACKER(name) \ + case FrameSequenceTrackerType::k##name: \ + builder.SetMainThread_##name(throughput); \ + break; + CASE_FOR_MAIN_THREAD_TRACKER(CompositorAnimation); + CASE_FOR_MAIN_THREAD_TRACKER(MainThreadAnimation); + CASE_FOR_MAIN_THREAD_TRACKER(PinchZoom); + CASE_FOR_MAIN_THREAD_TRACKER(RAF); + CASE_FOR_MAIN_THREAD_TRACKER(TouchScroll); + CASE_FOR_MAIN_THREAD_TRACKER(Universal); + CASE_FOR_MAIN_THREAD_TRACKER(Video); + CASE_FOR_MAIN_THREAD_TRACKER(WheelScroll); +#undef CASE_FOR_MAIN_THREAD_TRACKER + default: + NOTREACHED(); + break; + } + + break; + } + + case FrameSequenceTracker::ThreadType::kCompositor: { + switch (tracker_type) { +#define CASE_FOR_COMPOSITOR_THREAD_TRACKER(name) \ + case FrameSequenceTrackerType::k##name: \ + builder.SetCompositorThread_##name(throughput); \ + break; + CASE_FOR_COMPOSITOR_THREAD_TRACKER(CompositorAnimation); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(MainThreadAnimation); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(PinchZoom); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(RAF); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(TouchScroll); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(Universal); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(Video); + CASE_FOR_COMPOSITOR_THREAD_TRACKER(WheelScroll); +#undef CASE_FOR_COMPOSITOR_THREAD_TRACKER + default: + NOTREACHED(); + break; + } + break; + } + + case FrameSequenceTracker::ThreadType::kSlower: { + switch (tracker_type) { +#define CASE_FOR_SLOWER_THREAD_TRACKER(name) \ + case FrameSequenceTrackerType::k##name: \ + builder.SetSlowerThread_##name(throughput); \ + break; + CASE_FOR_SLOWER_THREAD_TRACKER(CompositorAnimation); + CASE_FOR_SLOWER_THREAD_TRACKER(MainThreadAnimation); + CASE_FOR_SLOWER_THREAD_TRACKER(PinchZoom); + CASE_FOR_SLOWER_THREAD_TRACKER(RAF); + CASE_FOR_SLOWER_THREAD_TRACKER(TouchScroll); + CASE_FOR_SLOWER_THREAD_TRACKER(Universal); + CASE_FOR_SLOWER_THREAD_TRACKER(Video); + CASE_FOR_SLOWER_THREAD_TRACKER(WheelScroll); +#undef CASE_FOR_SLOWER_THREAD_TRACKER + default: + NOTREACHED(); + break; + } + break; + } + default: + NOTREACHED(); + break; + } + builder.Record(recorder_.get()); +} + } // namespace cc diff --git a/chromium/cc/trees/ukm_manager.h b/chromium/cc/trees/ukm_manager.h index aeeda10cd0a..a67bbb08269 100644 --- a/chromium/cc/trees/ukm_manager.h +++ b/chromium/cc/trees/ukm_manager.h @@ -6,6 +6,7 @@ #define CC_TREES_UKM_MANAGER_H_ #include "cc/cc_export.h" +#include "cc/metrics/frame_sequence_tracker.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "url/gurl.h" @@ -22,6 +23,7 @@ class CC_EXPORT UkmRecorderFactory { virtual std::unique_ptr<ukm::UkmRecorder> CreateRecorder() = 0; }; +// TODO(xidachen): rename the class to CompositorUkmManager. class CC_EXPORT UkmManager { public: explicit UkmManager(std::unique_ptr<ukm::UkmRecorder> recorder); @@ -38,6 +40,10 @@ class CC_EXPORT UkmManager { // These metrics are recorded until the source URL changes. void AddCheckerboardedImages(int num_of_checkerboarded_images); + void RecordThroughputUKM(FrameSequenceTrackerType tracker_type, + FrameSequenceTracker::ThreadType thread_type, + int64_t throughput) const; + ukm::UkmRecorder* recorder_for_testing() { return recorder_.get(); } private: diff --git a/chromium/cc/typemaps.gni b/chromium/cc/typemaps.gni new file mode 100644 index 00000000000..b22ff7bb574 --- /dev/null +++ b/chromium/cc/typemaps.gni @@ -0,0 +1,5 @@ +# Copyright 2019 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. + +typemaps = [ "//cc/mojom/touch_action.typemap" ] |