LCOV - code coverage report
Current view: top level - layout/generic - ScrollbarActivity.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 248 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "ScrollbarActivity.h"
       7             : #include "nsIScrollbarMediator.h"
       8             : #include "nsIContent.h"
       9             : #include "nsICSSDeclaration.h"
      10             : #include "nsIDOMEvent.h"
      11             : #include "nsIDOMCSSStyleDeclaration.h"
      12             : #include "nsIFrame.h"
      13             : #include "nsContentUtils.h"
      14             : #include "nsAString.h"
      15             : #include "nsQueryFrame.h"
      16             : #include "nsComponentManagerUtils.h"
      17             : #include "nsStyledElement.h"
      18             : #include "mozilla/LookAndFeel.h"
      19             : #include "mozilla/Preferences.h"
      20             : 
      21             : namespace mozilla {
      22             : namespace layout {
      23             : 
      24           0 : NS_IMPL_ISUPPORTS(ScrollbarActivity, nsIDOMEventListener)
      25             : 
      26             : static bool
      27           0 : GetForceAlwaysVisiblePref()
      28             : {
      29             :   static bool sForceAlwaysVisible;
      30             :   static bool sForceAlwaysVisiblePrefCached = false;
      31           0 :   if (!sForceAlwaysVisiblePrefCached) {
      32             :     Preferences::AddBoolVarCache(&sForceAlwaysVisible,
      33           0 :                                  "layout.testing.overlay-scrollbars.always-visible");
      34           0 :     sForceAlwaysVisiblePrefCached = true;
      35             :   }
      36           0 :   return sForceAlwaysVisible;
      37             : }
      38             : 
      39             : void
      40           0 : ScrollbarActivity::QueryLookAndFeelVals()
      41             : {
      42             :   // Fade animation constants
      43           0 :   mScrollbarFadeBeginDelay =
      44           0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarFadeBeginDelay);
      45           0 :   mScrollbarFadeDuration =
      46           0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarFadeDuration);
      47             :   // Controls whether we keep the mouse move listener so we can display the
      48             :   // scrollbars whenever the user moves the mouse within the scroll area.
      49           0 :   mDisplayOnMouseMove =
      50           0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarDisplayOnMouseMove);
      51           0 : }
      52             : 
      53             : void
      54           0 : ScrollbarActivity::Destroy()
      55             : {
      56           0 :   StopListeningForScrollbarEvents();
      57           0 :   StopListeningForScrollAreaEvents();
      58           0 :   UnregisterFromRefreshDriver();
      59           0 :   CancelFadeBeginTimer();
      60           0 : }
      61             : 
      62             : void
      63           0 : ScrollbarActivity::ActivityOccurred()
      64             : {
      65           0 :   ActivityStarted();
      66           0 :   ActivityStopped();
      67           0 : }
      68             : 
      69             : void
      70           0 : ScrollbarActivity::ActivityStarted()
      71             : {
      72           0 :   mNestedActivityCounter++;
      73           0 :   CancelFadeBeginTimer();
      74           0 :   if (!SetIsFading(false)) {
      75           0 :     return;
      76             :   }
      77           0 :   UnregisterFromRefreshDriver();
      78           0 :   StartListeningForScrollbarEvents();
      79           0 :   StartListeningForScrollAreaEvents();
      80           0 :   SetIsActive(true);
      81             : 
      82           0 :   NS_ASSERTION(mIsActive, "need to be active during activity");
      83           0 :   NS_ASSERTION(!mIsFading, "must not be fading during activity");
      84             : }
      85             : 
      86             : void
      87           0 : ScrollbarActivity::ActivityStopped()
      88             : {
      89           0 :   if (!IsActivityOngoing()) {
      90             :     // This can happen if there was a frame reconstruction while the activity
      91             :     // was ongoing. In this case we just do nothing. We should probably handle
      92             :     // this case better.
      93           0 :     return;
      94             :   }
      95           0 :   NS_ASSERTION(mIsActive, "need to be active during activity");
      96           0 :   NS_ASSERTION(!mIsFading, "must not be fading during ongoing activity");
      97             : 
      98           0 :   mNestedActivityCounter--;
      99             : 
     100           0 :   if (!IsActivityOngoing()) {
     101           0 :     StartFadeBeginTimer();
     102             : 
     103           0 :     NS_ASSERTION(mIsActive, "need to be active right after activity");
     104           0 :     NS_ASSERTION(!mIsFading, "must not be fading right after activity");
     105             :   }
     106             : }
     107             : 
     108             : NS_IMETHODIMP
     109           0 : ScrollbarActivity::HandleEvent(nsIDOMEvent* aEvent)
     110             : {
     111           0 :   if (!mDisplayOnMouseMove && !mIsActive)
     112           0 :     return NS_OK;
     113             : 
     114           0 :   nsAutoString type;
     115           0 :   aEvent->GetType(type);
     116             : 
     117           0 :   if (type.EqualsLiteral("mousemove")) {
     118             :     // Mouse motions anywhere in the scrollable frame should keep the
     119             :     // scrollbars visible.
     120           0 :     ActivityOccurred();
     121           0 :     return NS_OK;
     122             :   }
     123             : 
     124           0 :   nsCOMPtr<nsIDOMEventTarget> target;
     125           0 :   aEvent->GetOriginalTarget(getter_AddRefs(target));
     126           0 :   nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
     127             : 
     128           0 :   HandleEventForScrollbar(type, targetContent, GetHorizontalScrollbar(),
     129           0 :                           &mHScrollbarHovered);
     130           0 :   HandleEventForScrollbar(type, targetContent, GetVerticalScrollbar(),
     131           0 :                           &mVScrollbarHovered);
     132             : 
     133           0 :   return NS_OK;
     134             : }
     135             : 
     136             : void
     137           0 : ScrollbarActivity::WillRefresh(TimeStamp aTime)
     138             : {
     139           0 :   NS_ASSERTION(mIsActive, "should only fade while scrollbars are visible");
     140           0 :   NS_ASSERTION(!IsActivityOngoing(), "why weren't we unregistered from the refresh driver when scrollbar activity started?");
     141           0 :   NS_ASSERTION(mIsFading, "should only animate fading during fade");
     142             : 
     143           0 :   if (!UpdateOpacity(aTime)) {
     144           0 :     return;
     145             :   }
     146             : 
     147           0 :   if (!IsStillFading(aTime)) {
     148           0 :     EndFade();
     149             :   }
     150             : }
     151             : 
     152             : bool
     153           0 : ScrollbarActivity::IsStillFading(TimeStamp aTime)
     154             : {
     155           0 :   return !mFadeBeginTime.IsNull() && (aTime - mFadeBeginTime < FadeDuration());
     156             : }
     157             : 
     158             : void
     159           0 : ScrollbarActivity::HandleEventForScrollbar(const nsAString& aType,
     160             :                                            nsIContent* aTarget,
     161             :                                            nsIContent* aScrollbar,
     162             :                                            bool* aStoredHoverState)
     163             : {
     164           0 :   if (!aTarget || !aScrollbar ||
     165           0 :       !nsContentUtils::ContentIsDescendantOf(aTarget, aScrollbar))
     166           0 :     return;
     167             : 
     168           0 :   if (aType.EqualsLiteral("mousedown")) {
     169           0 :     ActivityStarted();
     170           0 :   } else if (aType.EqualsLiteral("mouseup")) {
     171           0 :     ActivityStopped();
     172           0 :   } else if (aType.EqualsLiteral("mouseover") ||
     173           0 :              aType.EqualsLiteral("mouseout")) {
     174           0 :     bool newHoveredState = aType.EqualsLiteral("mouseover");
     175           0 :     if (newHoveredState && !*aStoredHoverState) {
     176           0 :       ActivityStarted();
     177           0 :       HoveredScrollbar(aScrollbar);
     178           0 :     } else if (*aStoredHoverState && !newHoveredState) {
     179           0 :       ActivityStopped();
     180             :       // Don't call HoveredScrollbar(nullptr) here because we want the hover
     181             :       // attribute to stick until the scrollbars are hidden.
     182             :     }
     183           0 :     *aStoredHoverState = newHoveredState;
     184             :   }
     185             : }
     186             : 
     187             : void
     188           0 : ScrollbarActivity::StartListeningForScrollbarEvents()
     189             : {
     190           0 :   if (mListeningForScrollbarEvents)
     191           0 :     return;
     192             : 
     193           0 :   mHorizontalScrollbar = do_QueryInterface(GetHorizontalScrollbar());
     194           0 :   mVerticalScrollbar = do_QueryInterface(GetVerticalScrollbar());
     195             : 
     196           0 :   AddScrollbarEventListeners(mHorizontalScrollbar);
     197           0 :   AddScrollbarEventListeners(mVerticalScrollbar);
     198             : 
     199           0 :   mListeningForScrollbarEvents = true;
     200             : }
     201             : 
     202             : void
     203           0 : ScrollbarActivity::StopListeningForScrollbarEvents()
     204             : {
     205           0 :   if (!mListeningForScrollbarEvents)
     206           0 :     return;
     207             : 
     208           0 :   RemoveScrollbarEventListeners(mHorizontalScrollbar);
     209           0 :   RemoveScrollbarEventListeners(mVerticalScrollbar);
     210             : 
     211           0 :   mHorizontalScrollbar = nullptr;
     212           0 :   mVerticalScrollbar = nullptr;
     213           0 :   mListeningForScrollbarEvents = false;
     214             : }
     215             : 
     216             : void
     217           0 : ScrollbarActivity::StartListeningForScrollAreaEvents()
     218             : {
     219           0 :   if (mListeningForScrollAreaEvents)
     220           0 :     return;
     221             : 
     222           0 :   nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
     223             :   nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget
     224           0 :     = do_QueryInterface(scrollArea->GetContent());
     225           0 :   if (scrollAreaTarget) {
     226           0 :     scrollAreaTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
     227           0 :                                        true);
     228             :   }
     229           0 :   mListeningForScrollAreaEvents = true;
     230             : }
     231             : 
     232             : void
     233           0 : ScrollbarActivity::StopListeningForScrollAreaEvents()
     234             : {
     235           0 :   if (!mListeningForScrollAreaEvents)
     236           0 :     return;
     237             : 
     238           0 :   nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
     239           0 :   nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget = do_QueryInterface(scrollArea->GetContent());
     240           0 :   if (scrollAreaTarget) {
     241           0 :     scrollAreaTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true);
     242             :   }
     243           0 :   mListeningForScrollAreaEvents = false;
     244             : }
     245             : 
     246             : void
     247           0 : ScrollbarActivity::AddScrollbarEventListeners(nsIDOMEventTarget* aScrollbar)
     248             : {
     249           0 :   if (aScrollbar) {
     250           0 :     aScrollbar->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
     251           0 :     aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true);
     252           0 :     aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true);
     253           0 :     aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true);
     254             :   }
     255           0 : }
     256             : 
     257             : void
     258           0 : ScrollbarActivity::RemoveScrollbarEventListeners(nsIDOMEventTarget* aScrollbar)
     259             : {
     260           0 :   if (aScrollbar) {
     261           0 :     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
     262           0 :     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true);
     263           0 :     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, true);
     264           0 :     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, true);
     265             :   }
     266           0 : }
     267             : 
     268             : void
     269           0 : ScrollbarActivity::BeginFade()
     270             : {
     271           0 :   NS_ASSERTION(mIsActive, "can't begin fade when we're already inactive");
     272           0 :   NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade begin timer cancelled when scrollbar activity started?");
     273           0 :   NS_ASSERTION(!mIsFading, "shouldn't be fading just yet");
     274             : 
     275           0 :   CancelFadeBeginTimer();
     276           0 :   mFadeBeginTime = TimeStamp::Now();
     277           0 :   if (!SetIsFading(true)) {
     278           0 :     return;
     279             :   }
     280           0 :   RegisterWithRefreshDriver();
     281             : 
     282           0 :   NS_ASSERTION(mIsActive, "only fade while scrollbars are visible");
     283           0 :   NS_ASSERTION(mIsFading, "should be fading now");
     284             : }
     285             : 
     286             : void
     287           0 : ScrollbarActivity::EndFade()
     288             : {
     289           0 :   NS_ASSERTION(mIsActive, "still need to be active at this point");
     290           0 :   NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade end timer cancelled when scrollbar activity started?");
     291             : 
     292           0 :   if (!SetIsFading(false)) {
     293           0 :     return;
     294             :   }
     295           0 :   SetIsActive(false);
     296           0 :   UnregisterFromRefreshDriver();
     297           0 :   StopListeningForScrollbarEvents();
     298           0 :   if (!mDisplayOnMouseMove) {
     299           0 :     StopListeningForScrollAreaEvents();
     300             :   }
     301             : 
     302           0 :   NS_ASSERTION(!mIsActive, "should have gone inactive after fade end");
     303           0 :   NS_ASSERTION(!mIsFading, "shouldn't be fading anymore");
     304             : }
     305             : 
     306             : void
     307           0 : ScrollbarActivity::RegisterWithRefreshDriver()
     308             : {
     309           0 :   nsRefreshDriver* refreshDriver = GetRefreshDriver();
     310           0 :   if (refreshDriver) {
     311           0 :     refreshDriver->AddRefreshObserver(this, FlushType::Style);
     312             :   }
     313           0 : }
     314             : 
     315             : void
     316           0 : ScrollbarActivity::UnregisterFromRefreshDriver()
     317             : {
     318           0 :   nsRefreshDriver* refreshDriver = GetRefreshDriver();
     319           0 :   if (refreshDriver) {
     320           0 :     refreshDriver->RemoveRefreshObserver(this, FlushType::Style);
     321             :   }
     322           0 : }
     323             : 
     324             : static void
     325           0 : SetBooleanAttribute(nsIContent* aContent, nsIAtom* aAttribute, bool aValue)
     326             : {
     327           0 :   if (aContent) {
     328           0 :     if (aValue) {
     329           0 :       aContent->SetAttr(kNameSpaceID_None, aAttribute,
     330           0 :                         NS_LITERAL_STRING("true"), true);
     331             :     } else {
     332           0 :       aContent->UnsetAttr(kNameSpaceID_None, aAttribute, true);
     333             :     }
     334             :   }
     335           0 : }
     336             : 
     337             : void
     338           0 : ScrollbarActivity::SetIsActive(bool aNewActive)
     339             : {
     340           0 :   if (mIsActive == aNewActive)
     341           0 :     return;
     342             : 
     343           0 :   mIsActive = aNewActive;
     344           0 :   if (!mIsActive) {
     345             :     // Clear sticky scrollbar hover status.
     346           0 :     HoveredScrollbar(nullptr);
     347             :   }
     348             : 
     349           0 :   SetBooleanAttribute(GetHorizontalScrollbar(), nsGkAtoms::active, mIsActive);
     350           0 :   SetBooleanAttribute(GetVerticalScrollbar(), nsGkAtoms::active, mIsActive);
     351             : }
     352             : 
     353             : static void
     354           0 : SetOpacityOnElement(nsIContent* aContent, double aOpacity)
     355             : {
     356             :   nsCOMPtr<nsStyledElement> inlineStyleContent =
     357           0 :     do_QueryInterface(aContent);
     358           0 :   if (inlineStyleContent) {
     359           0 :     nsICSSDeclaration* decl = inlineStyleContent->Style();
     360           0 :     nsAutoString str;
     361           0 :     str.AppendFloat(aOpacity);
     362           0 :     decl->SetProperty(NS_LITERAL_STRING("opacity"), str, EmptyString());
     363             :   }
     364           0 : }
     365             : 
     366             : bool
     367           0 : ScrollbarActivity::UpdateOpacity(TimeStamp aTime)
     368             : {
     369             :   // Avoid division by zero if mScrollbarFadeDuration is zero, just jump
     370             :   // to the end of the fade animation
     371           0 :   double progress = mScrollbarFadeDuration
     372           0 :     ? ((aTime - mFadeBeginTime) / FadeDuration())
     373           0 :     : 1.0;
     374           0 :   double opacity = 1.0 - std::max(0.0, std::min(1.0, progress));
     375             : 
     376             :   // 'this' may be getting destroyed during SetOpacityOnElement calls.
     377           0 :   AutoWeakFrame weakFrame((do_QueryFrame(mScrollableFrame)));
     378           0 :   SetOpacityOnElement(GetHorizontalScrollbar(), opacity);
     379           0 :   if (!weakFrame.IsAlive()) {
     380           0 :     return false;
     381             :   }
     382           0 :   SetOpacityOnElement(GetVerticalScrollbar(), opacity);
     383           0 :   if (!weakFrame.IsAlive()) {
     384           0 :     return false;
     385             :   }
     386           0 :   return true;
     387             : }
     388             : 
     389             : static void
     390           0 : UnsetOpacityOnElement(nsIContent* aContent)
     391             : {
     392             :   nsCOMPtr<nsStyledElement> inlineStyleContent =
     393           0 :     do_QueryInterface(aContent);
     394           0 :   if (inlineStyleContent) {
     395           0 :     nsICSSDeclaration* decl = inlineStyleContent->Style();
     396           0 :     nsAutoString dummy;
     397           0 :     decl->RemoveProperty(NS_LITERAL_STRING("opacity"), dummy);
     398             :   }
     399           0 : }
     400             : 
     401             : bool
     402           0 : ScrollbarActivity::SetIsFading(bool aNewFading)
     403             : {
     404           0 :   if (mIsFading == aNewFading)
     405           0 :     return true;
     406             : 
     407           0 :   mIsFading = aNewFading;
     408           0 :   if (!mIsFading) {
     409           0 :     mFadeBeginTime = TimeStamp();
     410             :     // 'this' may be getting destroyed during UnsetOpacityOnElement calls.
     411           0 :     AutoWeakFrame weakFrame((do_QueryFrame(mScrollableFrame)));
     412           0 :     UnsetOpacityOnElement(GetHorizontalScrollbar());
     413           0 :     if (!weakFrame.IsAlive()) {
     414           0 :       return false;
     415             :     }
     416           0 :     UnsetOpacityOnElement(GetVerticalScrollbar());
     417           0 :     if (!weakFrame.IsAlive()) {
     418           0 :       return false;
     419             :     }
     420             :   }
     421           0 :   return true;
     422             : }
     423             : 
     424             : void
     425           0 : ScrollbarActivity::StartFadeBeginTimer()
     426             : {
     427           0 :   if (GetForceAlwaysVisiblePref()) {
     428           0 :     return;
     429             :   }
     430           0 :   if (!mFadeBeginTimer) {
     431           0 :     mFadeBeginTimer = do_CreateInstance("@mozilla.org/timer;1");
     432             :   }
     433           0 :   mFadeBeginTimer->InitWithNamedFuncCallback(
     434           0 :     FadeBeginTimerFired, this, mScrollbarFadeBeginDelay,
     435           0 :     nsITimer::TYPE_ONE_SHOT, "ScrollbarActivity::FadeBeginTimerFired");
     436             : }
     437             : 
     438             : void
     439           0 : ScrollbarActivity::CancelFadeBeginTimer()
     440             : {
     441           0 :   if (mFadeBeginTimer) {
     442           0 :     mFadeBeginTimer->Cancel();
     443             :   }
     444           0 : }
     445             : 
     446             : void
     447           0 : ScrollbarActivity::HoveredScrollbar(nsIContent* aScrollbar)
     448             : {
     449           0 :   SetBooleanAttribute(GetHorizontalScrollbar(), nsGkAtoms::hover, false);
     450           0 :   SetBooleanAttribute(GetVerticalScrollbar(), nsGkAtoms::hover, false);
     451           0 :   SetBooleanAttribute(aScrollbar, nsGkAtoms::hover, true);
     452           0 : }
     453             : 
     454             : nsRefreshDriver*
     455           0 : ScrollbarActivity::GetRefreshDriver()
     456             : {
     457           0 :   nsIFrame* scrollableFrame = do_QueryFrame(mScrollableFrame);
     458           0 :   return scrollableFrame->PresContext()->RefreshDriver();
     459             : }
     460             : 
     461             : nsIContent*
     462           0 : ScrollbarActivity::GetScrollbarContent(bool aVertical)
     463             : {
     464           0 :   nsIFrame* box = mScrollableFrame->GetScrollbarBox(aVertical);
     465           0 :   return box ? box->GetContent() : nullptr;
     466             : }
     467             : 
     468             : } // namespace layout
     469             : } // namespace mozilla

Generated by: LCOV version 1.13