1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef ScrollbarActivity_h___
8 #define ScrollbarActivity_h___
9 
10 #include "mozilla/Attributes.h"
11 #include "nsCOMPtr.h"
12 #include "nsIDOMEventListener.h"
13 #include "mozilla/TimeStamp.h"
14 #include "nsRefreshObservers.h"
15 
16 class nsIContent;
17 class nsIScrollbarMediator;
18 class nsITimer;
19 class nsRefreshDriver;
20 
21 namespace mozilla {
22 
23 namespace dom {
24 class Element;
25 class EventTarget;
26 }  // namespace dom
27 
28 namespace layout {
29 
30 /**
31  * ScrollbarActivity
32  *
33  * This class manages scrollbar behavior that imitates the native Mac OS X
34  * Lion overlay scrollbar behavior: Scrollbars are only shown while "scrollbar
35  * activity" occurs, and they're hidden with a fade animation after a short
36  * delay.
37  *
38  * Scrollbar activity has these states:
39  *  - inactive:
40  *      Scrollbars are hidden.
41  *  - ongoing activity:
42  *      Scrollbars are visible and being operated on in some way, for example
43  *      because they're hovered or pressed.
44  *  - active, but waiting for fade out
45  *      Scrollbars are still completely visible but are about to fade away.
46  *  - fading out
47  *      Scrollbars are subject to a fade-out animation.
48  *
49  * Initial scrollbar activity needs to be reported by the scrollbar holder that
50  * owns the ScrollbarActivity instance. This needs to happen via a call to
51  * ActivityOccurred(), for example when the current scroll position or the size
52  * of the scroll area changes.
53  *
54  * As soon as scrollbars are visible, the ScrollbarActivity class manages the
55  * rest of the activity behavior: It ensures that mouse motions inside the
56  * scroll area keep the scrollbars visible, and that scrollbars don't fade away
57  * while they're being hovered / dragged. It also sets a sticky hover attribute
58  * on the most recently hovered scrollbar.
59  *
60  * ScrollbarActivity falls into hibernation after the scrollbars have faded
61  * out. It only starts acting after the next call to ActivityOccurred() /
62  * ActivityStarted().
63  */
64 
65 class ScrollbarActivity final : public nsIDOMEventListener,
66                                 public nsARefreshObserver {
67  public:
ScrollbarActivity(nsIScrollbarMediator * aScrollableFrame)68   explicit ScrollbarActivity(nsIScrollbarMediator* aScrollableFrame)
69       : mScrollableFrame(aScrollableFrame),
70         mNestedActivityCounter(0),
71         mIsActive(false),
72         mIsFading(false),
73         mListeningForScrollbarEvents(false),
74         mListeningForScrollAreaEvents(false),
75         mHScrollbarHovered(false),
76         mVScrollbarHovered(false),
77         mDisplayOnMouseMove(false),
78         mScrollbarFadeBeginDelay(0),
79         mScrollbarFadeDuration(0) {
80     QueryLookAndFeelVals();
81   }
82 
83   NS_DECL_ISUPPORTS
84   NS_DECL_NSIDOMEVENTLISTENER
85 
86   void Destroy();
87 
88   void ActivityOccurred();
89   void ActivityStarted();
90   void ActivityStopped();
91 
92   virtual void WillRefresh(TimeStamp aTime) override;
93 
FadeBeginTimerFired(nsITimer * aTimer,void * aSelf)94   static void FadeBeginTimerFired(nsITimer* aTimer, void* aSelf) {
95     RefPtr<ScrollbarActivity> scrollbarActivity(
96         reinterpret_cast<ScrollbarActivity*>(aSelf));
97     scrollbarActivity->BeginFade();
98   }
99 
100  protected:
101   virtual ~ScrollbarActivity() = default;
102 
IsActivityOngoing()103   bool IsActivityOngoing() { return mNestedActivityCounter > 0; }
104   bool IsStillFading(TimeStamp aTime);
105   void QueryLookAndFeelVals();
106 
107   void HandleEventForScrollbar(const nsAString& aType, nsIContent* aTarget,
108                                dom::Element* aScrollbar,
109                                bool* aStoredHoverState);
110 
111   void SetIsActive(bool aNewActive);
112   bool SetIsFading(bool aNewFading);  // returns false if 'this' was destroyed
113 
114   void BeginFade();
115   void EndFade();
116 
117   void StartFadeBeginTimer();
118   void CancelFadeBeginTimer();
119 
120   void StartListeningForScrollbarEvents();
121   void StartListeningForScrollAreaEvents();
122   void StopListeningForScrollbarEvents();
123   void StopListeningForScrollAreaEvents();
124   void AddScrollbarEventListeners(dom::EventTarget* aScrollbar);
125   void RemoveScrollbarEventListeners(dom::EventTarget* aScrollbar);
126 
127   void RegisterWithRefreshDriver();
128   void UnregisterFromRefreshDriver();
129 
130   bool UpdateOpacity(TimeStamp aTime);  // returns false if 'this' was destroyed
131   void HoveredScrollbar(dom::Element* aScrollbar);
132 
133   nsRefreshDriver* GetRefreshDriver();
134   dom::Element* GetScrollbarContent(bool aVertical);
GetHorizontalScrollbar()135   dom::Element* GetHorizontalScrollbar() { return GetScrollbarContent(false); }
GetVerticalScrollbar()136   dom::Element* GetVerticalScrollbar() { return GetScrollbarContent(true); }
137 
FadeDuration()138   const TimeDuration FadeDuration() {
139     return TimeDuration::FromMilliseconds(mScrollbarFadeDuration);
140   }
141 
142   nsIScrollbarMediator* mScrollableFrame;
143   TimeStamp mFadeBeginTime;
144   nsCOMPtr<nsITimer> mFadeBeginTimer;
145   nsCOMPtr<dom::EventTarget> mHorizontalScrollbar;  // null while inactive
146   nsCOMPtr<dom::EventTarget> mVerticalScrollbar;    // null while inactive
147   int mNestedActivityCounter;
148   bool mIsActive;
149   bool mIsFading;
150   bool mListeningForScrollbarEvents;
151   bool mListeningForScrollAreaEvents;
152   bool mHScrollbarHovered;
153   bool mVScrollbarHovered;
154 
155   // LookAndFeel values we load on creation
156   bool mDisplayOnMouseMove;
157   int mScrollbarFadeBeginDelay;
158   int mScrollbarFadeDuration;
159 };
160 
161 }  // namespace layout
162 }  // namespace mozilla
163 
164 #endif /* ScrollbarActivity_h___ */
165