summaryrefslogtreecommitdiff
path: root/chromium/cc/input
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/input')
-rw-r--r--chromium/cc/input/input_handler.h7
-rw-r--r--chromium/cc/input/layer_selection_bound.h2
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason.h35
-rw-r--r--chromium/cc/input/page_scale_animation.h2
-rw-r--r--chromium/cc/input/scroll_elasticity_helper.h2
-rw-r--r--chromium/cc/input/scroll_state.h2
-rw-r--r--chromium/cc/input/scroll_state_data.h2
-rw-r--r--chromium/cc/input/scrollbar.h2
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.cc194
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.h66
-rw-r--r--chromium/cc/input/scrollbar_animation_controller_unittest.cc340
-rw-r--r--chromium/cc/input/selection.h2
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning.h2
13 files changed, 393 insertions, 265 deletions
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index 7e6124c0a07..6ffdcce5737 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/time/time.h"
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/input/event_listener_properties.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/scroll_state.h"
@@ -113,7 +113,8 @@ class CC_EXPORT InputHandler {
// Binds a client to this handler to receive notifications. Only one client
// can be bound to an InputHandler. The client must live at least until the
// handler calls WillShutdown() on the client.
- virtual void BindToClient(InputHandlerClient* client) = 0;
+ virtual void BindToClient(InputHandlerClient* client,
+ bool wheel_scroll_latching_enabled) = 0;
// Selects a layer to be scrolled using the |scroll_state| start position.
// Returns SCROLL_STARTED if the layer at the coordinates can be scrolled,
@@ -216,6 +217,8 @@ class CC_EXPORT InputHandler {
gfx::ScrollOffset* offset) = 0;
virtual bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) = 0;
+ virtual bool ScrollingShouldSwitchtoMainThread() = 0;
+
protected:
InputHandler() {}
virtual ~InputHandler() {}
diff --git a/chromium/cc/input/layer_selection_bound.h b/chromium/cc/input/layer_selection_bound.h
index be40a562a7a..abadc3c39e4 100644
--- a/chromium/cc/input/layer_selection_bound.h
+++ b/chromium/cc/input/layer_selection_bound.h
@@ -5,7 +5,7 @@
#ifndef CC_INPUT_LAYER_SELECTION_BOUND_H_
#define CC_INPUT_LAYER_SELECTION_BOUND_H_
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/input/selection.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/selection_bound.h"
diff --git a/chromium/cc/input/main_thread_scrolling_reason.h b/chromium/cc/input/main_thread_scrolling_reason.h
index a2a02222ad4..a8c586eee95 100644
--- a/chromium/cc/input/main_thread_scrolling_reason.h
+++ b/chromium/cc/input/main_thread_scrolling_reason.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/stl_util.h"
#include "base/trace_event/trace_event_argument.h"
namespace cc {
@@ -36,12 +37,14 @@ struct MainThreadScrollingReason {
// These *AndLCDText reasons are due to subpixel text rendering which can
// only be applied by blending glyphs with the background at a specific
// screen position; transparency and transforms break this.
+ kNonCompositedReasonsFirst = 16,
kHasOpacityAndLCDText = 1 << 16,
kHasTransformAndLCDText = 1 << 17,
kBackgroundNotOpaqueInRectAndLCDText = 1 << 18,
kHasBorderRadius = 1 << 19,
kHasClipRelatedProperty = 1 << 20,
kHasBoxShadowFromNonRootLayer = 1 << 21,
+ kNonCompositedReasonsLast = 21,
// Transient scrolling reasons. These are computed for each scroll begin.
kNonFastScrollableRegion = 1 << 5,
@@ -59,6 +62,11 @@ struct MainThreadScrollingReason {
kMainThreadScrollingReasonCount = 22,
};
+ static const uint32_t kNonCompositedReasons =
+ kHasOpacityAndLCDText | kHasTransformAndLCDText |
+ kBackgroundNotOpaqueInRectAndLCDText | kHasBorderRadius |
+ kHasClipRelatedProperty | kHasBoxShadowFromNonRootLayer;
+
// Returns true if the given MainThreadScrollingReason can be set by the main
// thread.
static bool MainThreadCanSetScrollReasons(uint32_t reasons) {
@@ -66,10 +74,7 @@ struct MainThreadScrollingReason {
kNotScrollingOnMain | kHasBackgroundAttachmentFixedObjects |
kHasNonLayerViewportConstrainedObjects | kThreadedScrollingDisabled |
kScrollbarScrolling | kPageOverlay | kHandlingScrollFromMainThread |
- kCustomScrollbarScrolling | kHasOpacityAndLCDText |
- kHasTransformAndLCDText | kBackgroundNotOpaqueInRectAndLCDText |
- kHasBorderRadius | kHasClipRelatedProperty |
- kHasBoxShadowFromNonRootLayer;
+ kCustomScrollbarScrolling;
return (reasons & reasons_set_by_main_thread) == reasons;
}
@@ -83,6 +88,12 @@ struct MainThreadScrollingReason {
return (reasons & reasons_set_by_compositor) == reasons;
}
+ // Returns true if there are any reasons that prevented the scroller
+ // from being composited.
+ static bool HasNonCompositedScrollReasons(uint32_t reasons) {
+ return (reasons & kNonCompositedReasons) != 0;
+ }
+
static std::string mainThreadScrollingReasonsAsText(uint32_t reasons) {
base::trace_event::TracedValue tracedValue;
mainThreadScrollingReasonsAsTracedValue(reasons, &tracedValue);
@@ -90,7 +101,7 @@ struct MainThreadScrollingReason {
// Remove '{main_thread_scrolling_reasons:[', ']}', and any '"' chars.
std::string result =
result_in_array_foramt.substr(34, result_in_array_foramt.length() - 36);
- result.erase(std::remove(result.begin(), result.end(), '\"'), result.end());
+ base::Erase(result, '\"');
return result;
}
@@ -147,20 +158,6 @@ struct MainThreadScrollingReason {
tracedValue->AppendString("Page-based scrolling");
tracedValue->EndArray();
}
-
- // For a given reason, return its index in enum
- static int getReasonIndex(uint32_t reason) {
- // Multiple reasons provided
- if (reason & (reason - 1))
- return -1;
-
- int index = -1;
- while (reason > 0) {
- reason = reason >> 1;
- ++index;
- }
- return index;
- }
};
} // namespace cc
diff --git a/chromium/cc/input/page_scale_animation.h b/chromium/cc/input/page_scale_animation.h
index b58f50b315c..9d66923e76b 100644
--- a/chromium/cc/input/page_scale_animation.h
+++ b/chromium/cc/input/page_scale_animation.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/time/time.h"
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "ui/gfx/geometry/cubic_bezier.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d.h"
diff --git a/chromium/cc/input/scroll_elasticity_helper.h b/chromium/cc/input/scroll_elasticity_helper.h
index 3ad28fb2cbd..0952bd02e52 100644
--- a/chromium/cc/input/scroll_elasticity_helper.h
+++ b/chromium/cc/input/scroll_elasticity_helper.h
@@ -6,7 +6,7 @@
#define CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
#include "base/time/time.h"
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/geometry/vector2d_f.h"
diff --git a/chromium/cc/input/scroll_state.h b/chromium/cc/input/scroll_state.h
index 384a934fc22..74823e4ba85 100644
--- a/chromium/cc/input/scroll_state.h
+++ b/chromium/cc/input/scroll_state.h
@@ -8,7 +8,7 @@
#include <list>
#include <memory>
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/input/scroll_state_data.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/vector2d.h"
diff --git a/chromium/cc/input/scroll_state_data.h b/chromium/cc/input/scroll_state_data.h
index 90339649f5f..f3559a89d07 100644
--- a/chromium/cc/input/scroll_state_data.h
+++ b/chromium/cc/input/scroll_state_data.h
@@ -9,7 +9,7 @@
#include <list>
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/trees/property_tree.h"
namespace cc {
diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h
index d159dba7b17..e0302bffcb6 100644
--- a/chromium/cc/input/scrollbar.h
+++ b/chromium/cc/input/scrollbar.h
@@ -5,7 +5,7 @@
#ifndef CC_INPUT_SCROLLBAR_H_
#define CC_INPUT_SCROLLBAR_H_
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/paint/paint_canvas.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc
index e30d8eb493a..8fb3c25a48b 100644
--- a/chromium/cc/input/scrollbar_animation_controller.cc
+++ b/chromium/cc/input/scrollbar_animation_controller.cc
@@ -15,44 +15,45 @@ std::unique_ptr<ScrollbarAnimationController>
ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid(
int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration) {
- return base::WrapUnique(new ScrollbarAnimationController(
- scroll_layer_id, client, fade_out_delay, fade_out_resize_delay,
- fade_out_duration));
+ base::TimeDelta fade_duration) {
+ return base::WrapUnique(
+ new ScrollbarAnimationController(scroll_layer_id, client, fade_delay,
+ fade_out_resize_delay, fade_duration));
}
std::unique_ptr<ScrollbarAnimationController>
ScrollbarAnimationController::CreateScrollbarAnimationControllerAuraOverlay(
int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta show_delay,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration,
+ base::TimeDelta fade_duration,
base::TimeDelta thinning_duration) {
return base::WrapUnique(new ScrollbarAnimationController(
- scroll_layer_id, client, show_delay, fade_out_delay,
- fade_out_resize_delay, fade_out_duration, thinning_duration));
+ scroll_layer_id, client, fade_delay, fade_out_resize_delay,
+ fade_duration, thinning_duration));
}
ScrollbarAnimationController::ScrollbarAnimationController(
int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration)
+ base::TimeDelta fade_duration)
: client_(client),
- fade_out_delay_(fade_out_delay),
+ fade_delay_(fade_delay),
fade_out_resize_delay_(fade_out_resize_delay),
+ fade_duration_(fade_duration),
need_trigger_scrollbar_show_(false),
is_animating_(false),
+ animation_change_(NONE),
scroll_layer_id_(scroll_layer_id),
currently_scrolling_(false),
- scroll_gesture_has_scrolled_(false),
+ show_in_fast_scroll_(false),
opacity_(0.0f),
- fade_out_duration_(fade_out_duration),
+ show_scrollbars_on_scroll_gesture_(false),
need_thinning_animation_(false),
weak_factory_(this) {
ApplyOpacityToScrollbars(0.0f);
@@ -61,22 +62,22 @@ ScrollbarAnimationController::ScrollbarAnimationController(
ScrollbarAnimationController::ScrollbarAnimationController(
int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta show_delay,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration,
+ base::TimeDelta fade_duration,
base::TimeDelta thinning_duration)
: client_(client),
- show_delay_(show_delay),
- fade_out_delay_(fade_out_delay),
+ fade_delay_(fade_delay),
fade_out_resize_delay_(fade_out_resize_delay),
+ fade_duration_(fade_duration),
need_trigger_scrollbar_show_(false),
is_animating_(false),
+ animation_change_(NONE),
scroll_layer_id_(scroll_layer_id),
currently_scrolling_(false),
- scroll_gesture_has_scrolled_(false),
+ show_in_fast_scroll_(false),
opacity_(0.0f),
- fade_out_duration_(fade_out_duration),
+ show_scrollbars_on_scroll_gesture_(true),
need_thinning_animation_(true),
weak_factory_(this) {
vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create(
@@ -105,41 +106,39 @@ ScrollbarAnimationController::GetScrollbarAnimationController(
}
void ScrollbarAnimationController::StartAnimation() {
- delayed_scrollbar_show_.Cancel();
- delayed_scrollbar_fade_out_.Cancel();
+ DCHECK(animation_change_ != NONE);
+ delayed_scrollbar_animation_.Cancel();
is_animating_ = true;
last_awaken_time_ = base::TimeTicks();
client_->SetNeedsAnimateForScrollbarAnimation();
}
void ScrollbarAnimationController::StopAnimation() {
- delayed_scrollbar_show_.Cancel();
- delayed_scrollbar_fade_out_.Cancel();
+ delayed_scrollbar_animation_.Cancel();
is_animating_ = false;
+ animation_change_ = NONE;
}
-void ScrollbarAnimationController::PostDelayedShow() {
- DCHECK(delayed_scrollbar_fade_out_.IsCancelled());
- delayed_scrollbar_show_.Reset(base::Bind(&ScrollbarAnimationController::Show,
- weak_factory_.GetWeakPtr()));
- client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_show_.callback(),
- show_delay_);
-}
+void ScrollbarAnimationController::PostDelayedAnimation(
+ AnimationChange animation_change,
+ bool on_resize) {
+ animation_change_ = animation_change;
+
+ base::TimeDelta delay = on_resize ? fade_out_resize_delay_ : fade_delay_;
-void ScrollbarAnimationController::PostDelayedFadeOut(bool on_resize) {
- DCHECK(delayed_scrollbar_show_.IsCancelled());
- base::TimeDelta delay = on_resize ? fade_out_resize_delay_ : fade_out_delay_;
- delayed_scrollbar_fade_out_.Reset(
+ delayed_scrollbar_animation_.Cancel();
+ delayed_scrollbar_animation_.Reset(
base::Bind(&ScrollbarAnimationController::StartAnimation,
weak_factory_.GetWeakPtr()));
client_->PostDelayedScrollbarAnimationTask(
- delayed_scrollbar_fade_out_.callback(), delay);
+ delayed_scrollbar_animation_.callback(), delay);
}
bool ScrollbarAnimationController::Animate(base::TimeTicks now) {
bool animated = false;
if (is_animating_) {
+ DCHECK(animation_change_ != NONE);
if (last_awaken_time_.is_null())
last_awaken_time_ = now;
@@ -162,59 +161,89 @@ bool ScrollbarAnimationController::Animate(base::TimeTicks now) {
float ScrollbarAnimationController::AnimationProgressAtTime(
base::TimeTicks now) {
base::TimeDelta delta = now - last_awaken_time_;
- float progress = delta.InSecondsF() / fade_out_duration_.InSecondsF();
+ float progress = delta.InSecondsF() / fade_duration_.InSecondsF();
return std::max(std::min(progress, 1.f), 0.f);
}
+void ScrollbarAnimationController::RunAnimationFrame(float progress) {
+ float opacity;
+
+ DCHECK(animation_change_ != NONE);
+ if (animation_change_ == FADE_IN) {
+ opacity = std::max(progress, opacity_);
+ } else {
+ opacity = std::min(1.f - progress, opacity_);
+ }
+
+ ApplyOpacityToScrollbars(opacity);
+ if (progress == 1.f)
+ StopAnimation();
+}
+
void ScrollbarAnimationController::DidScrollBegin() {
currently_scrolling_ = true;
}
-void ScrollbarAnimationController::RunAnimationFrame(float progress) {
- ApplyOpacityToScrollbars(1.f - progress);
- client_->SetNeedsRedrawForScrollbarAnimation();
- if (progress == 1.f)
- StopAnimation();
+void ScrollbarAnimationController::DidScrollEnd() {
+ bool has_scrolled = show_in_fast_scroll_;
+ show_in_fast_scroll_ = false;
+
+ currently_scrolling_ = false;
+
+ // We don't fade out scrollbar if they need thinning animation and mouse is
+ // near.
+ if (need_thinning_animation_ && MouseIsNearAnyScrollbar())
+ return;
+
+ if (has_scrolled)
+ PostDelayedAnimation(FADE_OUT, false);
}
-void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) {
+void ScrollbarAnimationController::DidScrollUpdate() {
if (need_thinning_animation_ && Captured())
return;
StopAnimation();
+ Show();
+
// As an optimization, we avoid spamming fade delay tasks during active fast
// scrolls. But if we're not within one, we need to post every scroll update.
if (!currently_scrolling_) {
// We don't fade out scrollbar if they need thinning animation and mouse is
// near.
- if (!need_thinning_animation_ || !mouse_is_near_any_scrollbar())
- PostDelayedFadeOut(on_resize);
+ if (!need_thinning_animation_ || !MouseIsNearAnyScrollbar())
+ PostDelayedAnimation(FADE_OUT, false);
} else {
- scroll_gesture_has_scrolled_ = true;
+ show_in_fast_scroll_ = true;
}
- Show();
-
if (need_thinning_animation_) {
vertical_controller_->UpdateThumbThicknessScale();
horizontal_controller_->UpdateThumbThicknessScale();
}
}
-void ScrollbarAnimationController::DidScrollEnd() {
- bool has_scrolled = scroll_gesture_has_scrolled_;
- scroll_gesture_has_scrolled_ = false;
+void ScrollbarAnimationController::WillUpdateScroll() {
+ if (show_scrollbars_on_scroll_gesture_)
+ DidScrollUpdate();
+}
- currently_scrolling_ = false;
+void ScrollbarAnimationController::DidRequestShowFromMainThread() {
+ // TODO(skobes): Call DidScrollUpdate here (suppressed for crbug.com/706927).
+}
- // We don't fade out scrollbar if they need thinning animation and mouse is
- // near.
- if (need_thinning_animation_ && mouse_is_near_any_scrollbar())
- return;
+void ScrollbarAnimationController::DidResize() {
+ StopAnimation();
+ Show();
- if (has_scrolled)
- PostDelayedFadeOut(false);
+ // As an optimization, we avoid spamming fade delay tasks during active fast
+ // scrolls.
+ if (!currently_scrolling_) {
+ PostDelayedAnimation(FADE_OUT, true);
+ } else {
+ show_in_fast_scroll_ = true;
+ }
}
void ScrollbarAnimationController::DidMouseDown() {
@@ -232,8 +261,8 @@ void ScrollbarAnimationController::DidMouseUp() {
vertical_controller_->DidMouseUp();
horizontal_controller_->DidMouseUp();
- if (!mouse_is_near_any_scrollbar())
- PostDelayedFadeOut(false);
+ if (!MouseIsNearAnyScrollbar())
+ PostDelayedAnimation(FADE_OUT, false);
}
void ScrollbarAnimationController::DidMouseLeave() {
@@ -243,10 +272,13 @@ void ScrollbarAnimationController::DidMouseLeave() {
vertical_controller_->DidMouseLeave();
horizontal_controller_->DidMouseLeave();
+ delayed_scrollbar_animation_.Cancel();
+ need_trigger_scrollbar_show_ = false;
+
if (ScrollbarsHidden() || Captured())
return;
- PostDelayedFadeOut(false);
+ PostDelayedAnimation(FADE_OUT, false);
}
void ScrollbarAnimationController::DidMouseMoveNear(
@@ -268,17 +300,17 @@ void ScrollbarAnimationController::DidMouseMoveNear(
if (ScrollbarsHidden()) {
if (need_trigger_scrollbar_show_before != need_trigger_scrollbar_show_) {
if (need_trigger_scrollbar_show_) {
- PostDelayedShow();
+ PostDelayedAnimation(FADE_IN, false);
} else {
- delayed_scrollbar_show_.Cancel();
+ delayed_scrollbar_animation_.Cancel();
}
}
} else {
- if (mouse_is_near_any_scrollbar()) {
+ if (MouseIsNearAnyScrollbar()) {
Show();
StopAnimation();
} else if (!is_animating_) {
- PostDelayedFadeOut(false);
+ PostDelayedAnimation(FADE_OUT, false);
}
}
}
@@ -296,27 +328,26 @@ bool ScrollbarAnimationController::CalcNeedTriggerScrollbarShow(
if (scrollbar->orientation() != orientation)
continue;
- if (distance <
- (kMouseMoveDistanceToTriggerShow - scrollbar->ThumbThickness()))
+ if (distance < kMouseMoveDistanceToTriggerFadeIn)
return true;
}
return false;
}
-bool ScrollbarAnimationController::mouse_is_over_scrollbar(
+bool ScrollbarAnimationController::MouseIsOverScrollbar(
ScrollbarOrientation orientation) const {
DCHECK(need_thinning_animation_);
return GetScrollbarAnimationController(orientation).mouse_is_over_scrollbar();
}
-bool ScrollbarAnimationController::mouse_is_near_scrollbar(
+bool ScrollbarAnimationController::MouseIsNearScrollbar(
ScrollbarOrientation orientation) const {
DCHECK(need_thinning_animation_);
return GetScrollbarAnimationController(orientation).mouse_is_near_scrollbar();
}
-bool ScrollbarAnimationController::mouse_is_near_any_scrollbar() const {
+bool ScrollbarAnimationController::MouseIsNearAnyScrollbar() const {
DCHECK(need_thinning_animation_);
return vertical_controller_->mouse_is_near_scrollbar() ||
horizontal_controller_->mouse_is_near_scrollbar();
@@ -332,6 +363,7 @@ bool ScrollbarAnimationController::Captured() const {
}
void ScrollbarAnimationController::Show() {
+ delayed_scrollbar_animation_.Cancel();
ApplyOpacityToScrollbars(1.0f);
}
@@ -340,25 +372,15 @@ void ScrollbarAnimationController::ApplyOpacityToScrollbars(float opacity) {
if (!scrollbar->is_overlay_scrollbar())
continue;
float effective_opacity = scrollbar->CanScrollOrientation() ? opacity : 0;
- PropertyTrees* property_trees =
- scrollbar->layer_tree_impl()->property_trees();
- // If this method is called during LayerImpl::PushPropertiesTo, we may not
- // yet have valid layer_id_to_effect_node_index entries as property trees
- // are pushed after layers during activation. We can skip updating opacity
- // in that case as we are only registering a scrollbar and because opacity
- // will be overwritten anyway when property trees are pushed.
- if (property_trees->IsInIdToIndexMap(PropertyTrees::TreeType::EFFECT,
- scrollbar->id())) {
- property_trees->effect_tree.OnOpacityAnimated(
- effective_opacity,
- property_trees->layer_id_to_effect_node_index[scrollbar->id()],
- scrollbar->layer_tree_impl());
- }
+ scrollbar->SetOverlayScrollbarLayerOpacityAnimated(effective_opacity);
}
bool previouslyVisible = opacity_ > 0.0f;
bool currentlyVisible = opacity > 0.0f;
+ if (opacity_ != opacity)
+ client_->SetNeedsRedrawForScrollbarAnimation();
+
opacity_ = opacity;
if (previouslyVisible != currentlyVisible)
diff --git a/chromium/cc/input/scrollbar_animation_controller.h b/chromium/cc/input/scrollbar_animation_controller.h
index 4dc68406839..60676d95044 100644
--- a/chromium/cc/input/scrollbar_animation_controller.h
+++ b/chromium/cc/input/scrollbar_animation_controller.h
@@ -8,7 +8,7 @@
#include "base/cancelable_callback.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/input/single_scrollbar_animation_controller_thinning.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
@@ -43,9 +43,9 @@ class CC_EXPORT ScrollbarAnimationController {
CreateScrollbarAnimationControllerAndroid(
int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration);
+ base::TimeDelta fade_duration);
// ScrollbarAnimationController for Desktop Overlay Scrollbar. It has show &
// fade out animation and thinning animation.
@@ -53,10 +53,9 @@ class CC_EXPORT ScrollbarAnimationController {
CreateScrollbarAnimationControllerAuraOverlay(
int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta show_delay,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration,
+ base::TimeDelta fade_duration,
base::TimeDelta thinning_duration);
~ScrollbarAnimationController();
@@ -65,8 +64,19 @@ class CC_EXPORT ScrollbarAnimationController {
bool Animate(base::TimeTicks now);
+ // WillUpdateScroll expects to be called even if the scroll position won't
+ // change as a result of the scroll. Only effect Aura Overlay Scrollbar.
+ void WillUpdateScroll();
+
+ // DidScrollUpdate expects to be called only if the scroll position change.
+ // Effect both Android and Aura Overlay Scrollbar.
+ void DidScrollUpdate();
+
+ // DidResize expects to be called when clip layer size changed or scroll layer
+ // size changed.
+ void DidResize();
+
void DidScrollBegin();
- void DidScrollUpdate(bool on_resize);
void DidScrollEnd();
void DidMouseDown();
@@ -74,25 +84,31 @@ class CC_EXPORT ScrollbarAnimationController {
void DidMouseLeave();
void DidMouseMoveNear(ScrollbarOrientation, float);
- bool mouse_is_over_scrollbar(ScrollbarOrientation orientation) const;
- bool mouse_is_near_scrollbar(ScrollbarOrientation orientation) const;
- bool mouse_is_near_any_scrollbar() const;
+ // Called when Blink wants to show the scrollbars (via
+ // ScrollableArea::showOverlayScrollbars).
+ void DidRequestShowFromMainThread();
- static constexpr float kMouseMoveDistanceToTriggerShow = 30.0f;
+ bool MouseIsOverScrollbar(ScrollbarOrientation orientation) const;
+ bool MouseIsNearScrollbar(ScrollbarOrientation orientation) const;
+ bool MouseIsNearAnyScrollbar() const;
+
+ static constexpr float kMouseMoveDistanceToTriggerFadeIn = 30.0f;
private:
+ // Describes whether the current animation should FadeIn or FadeOut.
+ enum AnimationChange { NONE, FADE_IN, FADE_OUT };
+
ScrollbarAnimationController(int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration);
+ base::TimeDelta fade_duration);
ScrollbarAnimationController(int scroll_layer_id,
ScrollbarAnimationControllerClient* client,
- base::TimeDelta show_delay,
- base::TimeDelta fade_out_delay,
+ base::TimeDelta fade_delay,
base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_out_duration,
+ base::TimeDelta fade_duration,
base::TimeDelta thinning_duration);
ScrollbarSet Scrollbars() const;
@@ -109,8 +125,7 @@ class CC_EXPORT ScrollbarAnimationController {
void Show();
- void PostDelayedShow();
- void PostDelayedFadeOut(bool on_resize);
+ void PostDelayedAnimation(AnimationChange animation_change, bool on_resize);
bool Captured() const;
@@ -123,26 +138,25 @@ class CC_EXPORT ScrollbarAnimationController {
base::TimeTicks last_awaken_time_;
- // show_delay_ is only for the case where the mouse hovers near the screen
- // edge.
- base::TimeDelta show_delay_;
- base::TimeDelta fade_out_delay_;
+ base::TimeDelta fade_delay_;
base::TimeDelta fade_out_resize_delay_;
+ base::TimeDelta fade_duration_;
+
bool need_trigger_scrollbar_show_;
bool is_animating_;
+ AnimationChange animation_change_;
const int scroll_layer_id_;
bool currently_scrolling_;
- bool scroll_gesture_has_scrolled_;
+ bool show_in_fast_scroll_;
- base::CancelableClosure delayed_scrollbar_show_;
- base::CancelableClosure delayed_scrollbar_fade_out_;
+ base::CancelableClosure delayed_scrollbar_animation_;
float opacity_;
- base::TimeDelta fade_out_duration_;
+ const bool show_scrollbars_on_scroll_gesture_;
const bool need_thinning_animation_;
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
vertical_controller_;
diff --git a/chromium/cc/input/scrollbar_animation_controller_unittest.cc b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
index c8ee16ecf75..ebb22757703 100644
--- a/chromium/cc/input/scrollbar_animation_controller_unittest.cc
+++ b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
@@ -26,8 +26,8 @@ const float kIdleThicknessScale =
const float kDefaultMouseMoveDistanceToTriggerAnimation =
SingleScrollbarAnimationControllerThinning::
kDefaultMouseMoveDistanceToTriggerAnimation;
-const float kMouseMoveDistanceToTriggerShow =
- ScrollbarAnimationController::kMouseMoveDistanceToTriggerShow;
+const float kMouseMoveDistanceToTriggerFadeIn =
+ ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
const int kThumbThickness = 10;
class MockScrollbarAnimationControllerClient
@@ -70,10 +70,9 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
}
protected:
- const base::TimeDelta kShowDelay = base::TimeDelta::FromSeconds(4);
- const base::TimeDelta kFadeOutDelay = base::TimeDelta::FromSeconds(2);
+ const base::TimeDelta kFadeDelay = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kResizeFadeOutDelay = base::TimeDelta::FromSeconds(5);
- const base::TimeDelta kFadeOutDuration = base::TimeDelta::FromSeconds(3);
+ const base::TimeDelta kFadeDuration = base::TimeDelta::FromSeconds(3);
const base::TimeDelta kThinningDuration = base::TimeDelta::FromSeconds(2);
void SetUp() override {
@@ -115,8 +114,8 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
scrollbar_controller_ = ScrollbarAnimationController::
CreateScrollbarAnimationControllerAuraOverlay(
- scroll_layer_ptr->id(), &client_, kShowDelay, kFadeOutDelay,
- kResizeFadeOutDelay, kFadeOutDuration, kThinningDuration);
+ scroll_layer_ptr->id(), &client_, kFadeDelay,
+ kResizeFadeOutDelay, kFadeDuration, kThinningDuration);
}
FakeImplTaskRunnerProvider task_runner_provider_;
@@ -145,18 +144,18 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, AppearOnResize) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
ExpectScrollbarsOpacity(1);
// Make the Layer non-scrollable, scrollbar disappears.
clip_layer_->SetBounds(gfx::Size(200, 200));
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
ExpectScrollbarsOpacity(0);
// Make the layer scrollable, scrollbar appears again.
clip_layer_->SetBounds(gfx::Size(100, 100));
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
ExpectScrollbarsOpacity(1);
}
@@ -175,7 +174,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, HideOnResize) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1, h_scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -187,7 +186,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, HideOnResize) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(0.0f, h_scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -207,7 +206,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, BasicAppearAndFadeOut) {
ExpectScrollbarsOpacity(0);
EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
ExpectScrollbarsOpacity(1);
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
@@ -216,13 +215,42 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, BasicAppearAndFadeOut) {
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
client_.start_fade().Run();
- // Scrollbar should fade out over kFadeOutDuration.
+ // Scrollbar should fade out over kFadeDuration.
scrollbar_controller_->Animate(time);
- time += kFadeOutDuration;
+ time += kFadeDuration;
+ scrollbar_controller_->Animate(time);
+
+ ExpectScrollbarsOpacity(0);
+ EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
+}
+
+// Confirm the scrollbar appears by WillUpdateScroll and fade out.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
+ BasicAppearByWillUpdateScrollThenFadeOut) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
+
+ // Scrollbar should be invisible.
+ ExpectScrollbarsOpacity(0);
+ EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
+
+ // Scrollbar should appear when scroll will update.
+ scrollbar_controller_->WillUpdateScroll();
+ ExpectScrollbarsOpacity(1);
+ EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
+
+ // An fade out animation should have been enqueued.
+ EXPECT_EQ(kFadeDelay, client_.delay());
+ EXPECT_FALSE(client_.start_fade().is_null());
+ client_.start_fade().Run();
+
+ // Scrollbar should fade out over kFadeDuration.
+ scrollbar_controller_->Animate(time);
+ time += kFadeDuration;
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(0);
@@ -236,11 +264,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MoveNearAndDontFadeOut) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
@@ -277,11 +305,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MoveOverAndDontFadeOut) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
@@ -319,11 +347,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
// Now move the mouse over the scrollbar and capture it. It should become
@@ -347,11 +375,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
// Now move the mouse over the scrollbar and capture it. It should become
@@ -383,11 +411,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, DontFadeWhileCaptured) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
@@ -420,11 +448,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAfterReleasedFar) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
@@ -471,11 +499,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, DontFadeAfterReleasedNear) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
@@ -510,11 +538,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// A fade out animation should have been enqueued. Start it.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
client_.start_fade().Run();
@@ -522,7 +550,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
ExpectScrollbarsOpacity(1);
// Proceed half way through the fade out animation.
- time += kFadeOutDuration / 2;
+ time += kFadeDuration / 2;
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(.5f);
@@ -550,10 +578,10 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TestCantCaptureWhenFaded) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
client_.start_fade().Run();
@@ -561,7 +589,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TestCantCaptureWhenFaded) {
ExpectScrollbarsOpacity(1);
// Fade the scrollbar out completely.
- time += kFadeOutDuration;
+ time += kFadeDuration;
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(0);
@@ -614,7 +642,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, ScrollWithMouseNear) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
// Now that we've received a scroll, we should be thick without an animation.
ExpectScrollbarsOpacity(1);
@@ -632,7 +660,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, ScrollWithMouseNear) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
// Scrollbar should still be thick and visible.
- time += kFadeOutDuration;
+ time += kFadeDuration;
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -649,20 +677,20 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// A ScrollUpdate without a ScrollBegin indicates a main thread scroll update
// so we should schedule a fade out animation without waiting for a ScrollEnd
// (which will never come).
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
client_.start_fade().Reset();
// If we got a ScrollBegin, we shouldn't schedule the fade out animation until
// we get a corresponding ScrollEnd.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_TRUE(client_.start_fade().is_null());
scrollbar_controller_->DidScrollEnd();
EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
}
// Make sure that if the scroll update is as a result of a resize, we use the
@@ -670,20 +698,20 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
TEST_F(ScrollbarAnimationControllerAuraOverlayTest, ResizeFadeDuration) {
ASSERT_TRUE(client_.delay().is_zero());
- scrollbar_controller_->DidScrollUpdate(true);
+ scrollbar_controller_->DidResize();
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_EQ(kResizeFadeOutDelay, client_.delay());
client_.delay() = base::TimeDelta();
// We should use the gesture delay rather than the resize delay if we're in a
- // gesture scroll, even if the resize param is set.
+ // gesture scroll, even if it is resizing.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(true);
+ scrollbar_controller_->DidResize();
scrollbar_controller_->DidScrollEnd();
EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
}
// Tests that the fade effect is animated.
@@ -693,14 +721,14 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAnimated) {
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// Appearance is instant.
ExpectScrollbarsOpacity(1);
// An fade out animation should have been enqueued.
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
client_.start_fade().Run();
@@ -708,11 +736,11 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAnimated) {
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(1);
- time += kFadeOutDuration / 2;
+ time += kFadeDuration / 2;
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(.5f);
- time += kFadeOutDuration / 2;
+ time += kFadeDuration / 2;
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(0);
}
@@ -725,7 +753,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, NotifyChangedVisibility) {
EXPECT_CALL(client_, DidChangeScrollbarVisibility()).Times(1);
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
Mock::VerifyAndClearExpectations(&client_);
@@ -738,20 +766,20 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, NotifyChangedVisibility) {
ASSERT_FALSE(client_.start_fade().is_null());
client_.start_fade().Run();
scrollbar_controller_->Animate(time);
- time += kFadeOutDuration / 4;
+ time += kFadeDuration / 4;
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
scrollbar_controller_->Animate(time);
- time += kFadeOutDuration / 4;
+ time += kFadeDuration / 4;
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
scrollbar_controller_->Animate(time);
- time += kFadeOutDuration / 4;
+ time += kFadeDuration / 4;
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(.25f);
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, DidChangeScrollbarVisibility()).Times(1);
- time += kFadeOutDuration / 4;
+ time += kFadeDuration / 4;
scrollbar_controller_->Animate(time);
EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
ExpectScrollbarsOpacity(0);
@@ -760,7 +788,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, NotifyChangedVisibility) {
// Calling DidScrollUpdate without a begin (i.e. update from commit) should
// also notify.
EXPECT_CALL(client_, DidChangeScrollbarVisibility()).Times(1);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
Mock::VerifyAndClearExpectations(&client_);
}
@@ -773,7 +801,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// Near vertical scrollbar
@@ -856,7 +884,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
// An fade out animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
}
// Move mouse near both scrollbars at the same time.
@@ -866,7 +894,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearBoth) {
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// Near both Scrollbar
@@ -896,7 +924,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// Near vertical scrollbar.
@@ -948,7 +976,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// An fade out animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
}
// Ensure we have a delay fadeout animation after mouse leave without a mouse
@@ -962,7 +990,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseLeaveFadeOut) {
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
// Should not have delay fadeout animation.
@@ -974,70 +1002,129 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseLeaveFadeOut) {
// An fade out animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeOutDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
}
-// Scrollbars should schedule a delay show when mouse hover hidden scrollbar.
-TEST_F(ScrollbarAnimationControllerAuraOverlayTest, BasicMouseHoverShow) {
+// Scrollbars should schedule a delay fade in when mouse hover the show
+// scrollbar region of a hidden scrollbar.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest, BasicMouseHoverFadeIn) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse over scrollbar.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Move mouse hover the fade in scrollbar region of scrollbar.
+ scrollbar_controller_->DidMouseMoveNear(
+ VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
- // An show animation should have been enqueued.
+ // An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- EXPECT_EQ(kShowDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
// Play the delay animation.
client_.start_fade().Run();
+ EXPECT_TRUE(client_.start_fade().IsCancelled());
+
+ scrollbar_controller_->Animate(time);
+ time += kFadeDuration / 2;
+ scrollbar_controller_->Animate(time);
+
+ ExpectScrollbarsOpacity(0.5);
+ EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
+
+ time += kFadeDuration / 2;
+ scrollbar_controller_->Animate(time);
+
+ ExpectScrollbarsOpacity(1);
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
}
-// Scrollbars should not schedule a new delay show when the mouse hovers inside
-// a scrollbar already scheduled a delay show.
+// Scrollbars should not schedule a new delay fade in when the mouse hovers
+// inside a scrollbar already scheduled a delay fade in.
TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
MouseHoverScrollbarAndMoveInside) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse over scrollbar.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Move mouse hover the fade in scrollbar region of scrollbar.
+ scrollbar_controller_->DidMouseMoveNear(
+ VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
- // An show animation should have been enqueued.
+ // An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- EXPECT_EQ(kShowDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
base::Closure& fade = client_.start_fade();
- // Move mouse inside scrollbar. should not post a new show.
+ // Move mouse still hover the fade in scrollbar region of scrollbar should not
+ // post a new fade in.
scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerShow - kThumbThickness - 1);
+ VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 2);
EXPECT_TRUE(fade.Equals(client_.start_fade()));
}
-// Scrollbars should cancel delay show when mouse hover hidden scrollbar then
-// move out.
+// Scrollbars should cancel delay fade in when mouse hover hidden scrollbar then
+// move far away.
TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
- MouseHoverThenOutShouldCancelShow) {
+ MouseHoverThenOutShouldCancelFadeIn) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse over scrollbar.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Move mouse hover the fade in scrollbar region of scrollbar.
+ scrollbar_controller_->DidMouseMoveNear(
+ VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
- // An show animation should have been enqueued.
+ // An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- EXPECT_EQ(kShowDelay, client_.delay());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Move mouse far away,delay fade in should be canceled.
+ scrollbar_controller_->DidMouseMoveNear(VERTICAL,
+ kMouseMoveDistanceToTriggerFadeIn);
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+}
+
+// Scrollbars should cancel delay fade in when mouse hover hidden scrollbar then
+// move out of window.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
+ MouseHoverThenLeaveShouldCancelShowThenEnterShouldFadeIn) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
- // Move mouse out of scrollbar,delay show should be canceled.
+ // Move mouse hover the fade in scrollbar region of scrollbar.
scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerShow - kThumbThickness);
+ VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+
+ // An fade in animation should have been enqueued.
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Move mouse out of window,delay fade in should be canceled.
+ scrollbar_controller_->DidMouseLeave();
EXPECT_TRUE(client_.start_fade().is_null() ||
client_.start_fade().IsCancelled());
+
+ // Move mouse hover the fade in scrollbar region of scrollbar.
+ scrollbar_controller_->DidMouseMoveNear(
+ VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+
+ // An fade in animation should have been enqueued.
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Play the delay animation.
+ client_.start_fade().Run();
+ EXPECT_TRUE(client_.start_fade().IsCancelled());
+
+ scrollbar_controller_->Animate(time);
+ time += kFadeDuration;
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
}
class ScrollbarAnimationControllerAndroidTest
@@ -1121,46 +1208,32 @@ class VerticalScrollbarAnimationControllerAndroidTest
};
TEST_F(ScrollbarAnimationControllerAndroidTest, DelayAnimationOnResize) {
- scrollbar_layer_->layer_tree_impl()
- ->property_trees()
- ->effect_tree.OnOpacityAnimated(0.0f,
- scrollbar_layer_->effect_tree_index(),
- scrollbar_layer_->layer_tree_impl());
+ scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
+ // We should use the gesture delay rather than the resize delay if we're in a
+ // gesture scroll, even if it is resizing.
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(true);
+ scrollbar_controller_->DidResize();
scrollbar_controller_->DidScrollEnd();
// Normal Animation delay of 2 seconds.
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
EXPECT_EQ(delay_, base::TimeDelta::FromSeconds(2));
- scrollbar_layer_->layer_tree_impl()
- ->property_trees()
- ->effect_tree.OnOpacityAnimated(0.0f,
- scrollbar_layer_->effect_tree_index(),
- scrollbar_layer_->layer_tree_impl());
- scrollbar_controller_->DidScrollUpdate(true);
+ scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
+ scrollbar_controller_->DidResize();
// Delay animation on resize to 5 seconds.
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
EXPECT_EQ(delay_, base::TimeDelta::FromSeconds(5));
}
TEST_F(ScrollbarAnimationControllerAndroidTest, HiddenInBegin) {
- scrollbar_layer_->layer_tree_impl()
- ->property_trees()
- ->effect_tree.OnOpacityAnimated(0.0f,
- scrollbar_layer_->effect_tree_index(),
- scrollbar_layer_->layer_tree_impl());
+ scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
scrollbar_controller_->Animate(base::TimeTicks());
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
}
TEST_F(ScrollbarAnimationControllerAndroidTest,
HiddenAfterNonScrollingGesture) {
- scrollbar_layer_->layer_tree_impl()
- ->property_trees()
- ->effect_tree.OnOpacityAnimated(0.0f,
- scrollbar_layer_->effect_tree_index(),
- scrollbar_layer_->layer_tree_impl());
+ scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
scrollbar_controller_->DidScrollBegin();
base::TimeTicks time;
@@ -1176,6 +1249,25 @@ TEST_F(ScrollbarAnimationControllerAndroidTest,
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
}
+// Confirm the scrollbar does not appear on WillUpdateScroll on Android.
+TEST_F(ScrollbarAnimationControllerAndroidTest,
+ WillUpdateScrollNotAppearScrollbar) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
+
+ // Scrollbar should be invisible.
+ EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+ EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
+
+ // Scrollbar should appear when scroll will update.
+ scrollbar_controller_->WillUpdateScroll();
+ EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+ EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
+
+ // No fade out animation should have been enqueued.
+ EXPECT_TRUE(start_fade_.Equals(base::Closure()));
+}
+
TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) {
LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
ASSERT_TRUE(scroll_layer);
@@ -1189,7 +1281,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1201,7 +1293,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1220,7 +1312,7 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest, HideOnResize) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1231,7 +1323,7 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest, HideOnResize) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1246,7 +1338,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnUserNonScrollableHorz) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1261,7 +1353,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, ShowOnUserNonScrollableVert) {
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1277,7 +1369,7 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest,
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1293,7 +1385,7 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest,
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
scrollbar_controller_->DidScrollEnd();
@@ -1305,7 +1397,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByScrollingGesture) {
scrollbar_controller_->DidScrollBegin();
EXPECT_FALSE(did_request_animate_);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(did_request_animate_);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
@@ -1343,7 +1435,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByScrollingGesture) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
start_fade_.Run();
@@ -1377,7 +1469,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByScrollingGesture) {
TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByProgrammaticScroll) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(did_request_animate_);
start_fade_.Run();
@@ -1393,7 +1485,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByProgrammaticScroll) {
EXPECT_TRUE(did_request_animate_);
did_request_animate_ = false;
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->Opacity());
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(did_request_animate_);
start_fade_.Run();
@@ -1418,7 +1510,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByProgrammaticScroll) {
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->Opacity());
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
start_fade_.Run();
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
@@ -1448,7 +1540,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest,
AnimationPreservedByNonScrollingGesture) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
start_fade_.Run();
EXPECT_TRUE(did_request_animate_);
did_request_animate_ = false;
@@ -1487,7 +1579,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest,
AnimationOverriddenByScrollingGesture) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(did_request_animate_);
start_fade_.Run();
EXPECT_TRUE(did_request_animate_);
@@ -1513,7 +1605,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest,
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->Opacity());
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollUpdate(false);
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FALSE(did_request_animate_);
EXPECT_FLOAT_EQ(1, scrollbar_layer_->Opacity());
diff --git a/chromium/cc/input/selection.h b/chromium/cc/input/selection.h
index bbd189a2295..1b95ec9b6c6 100644
--- a/chromium/cc/input/selection.h
+++ b/chromium/cc/input/selection.h
@@ -5,7 +5,7 @@
#ifndef CC_INPUT_SELECTION_H_
#define CC_INPUT_SELECTION_H_
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
namespace cc {
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.h b/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
index 1437ccde896..32ba069a12b 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/time/time.h"
-#include "cc/base/cc_export.h"
+#include "cc/cc_export.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"