LCOV - code coverage report
Current view: top level - layout/xul - nsSliderFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 140 738 19.0 %
Date: 2017-07-14 16:53:18 Functions: 25 76 32.9 %
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             : //
       7             : // Eric Vaughan
       8             : // Netscape Communications
       9             : //
      10             : // See documentation in associated header file
      11             : //
      12             : 
      13             : #include "nsSliderFrame.h"
      14             : 
      15             : #include "gfxPrefs.h"
      16             : #include "nsStyleContext.h"
      17             : #include "nsPresContext.h"
      18             : #include "nsIContent.h"
      19             : #include "nsCOMPtr.h"
      20             : #include "nsNameSpaceManager.h"
      21             : #include "nsGkAtoms.h"
      22             : #include "nsHTMLParts.h"
      23             : #include "nsIPresShell.h"
      24             : #include "nsCSSRendering.h"
      25             : #include "nsIDOMEvent.h"
      26             : #include "nsIDOMMouseEvent.h"
      27             : #include "nsScrollbarButtonFrame.h"
      28             : #include "nsISliderListener.h"
      29             : #include "nsIScrollableFrame.h"
      30             : #include "nsIScrollbarMediator.h"
      31             : #include "nsISupportsImpl.h"
      32             : #include "nsScrollbarFrame.h"
      33             : #include "nsRepeatService.h"
      34             : #include "nsBoxLayoutState.h"
      35             : #include "nsSprocketLayout.h"
      36             : #include "nsIServiceManager.h"
      37             : #include "nsContentUtils.h"
      38             : #include "nsLayoutUtils.h"
      39             : #include "nsDisplayList.h"
      40             : #include "nsRefreshDriver.h"            // for nsAPostRefreshObserver
      41             : #include "nsSVGIntegrationUtils.h"
      42             : #include "mozilla/Assertions.h"         // for MOZ_ASSERT
      43             : #include "mozilla/Preferences.h"
      44             : #include "mozilla/LookAndFeel.h"
      45             : #include "mozilla/MouseEvents.h"
      46             : #include "mozilla/Telemetry.h"
      47             : #include "mozilla/layers/APZCCallbackHelper.h"
      48             : #include "mozilla/layers/AsyncDragMetrics.h"
      49             : #include "mozilla/layers/InputAPZContext.h"
      50             : #include "mozilla/layers/ScrollInputMethods.h"
      51             : #include <algorithm>
      52             : 
      53             : using namespace mozilla;
      54             : using mozilla::layers::APZCCallbackHelper;
      55             : using mozilla::layers::AsyncDragMetrics;
      56             : using mozilla::layers::InputAPZContext;
      57             : using mozilla::layers::ScrollDirection;
      58             : using mozilla::layers::ScrollInputMethod;
      59             : using mozilla::layers::ScrollThumbData;
      60             : 
      61             : bool nsSliderFrame::gMiddlePref = false;
      62             : int32_t nsSliderFrame::gSnapMultiplier;
      63             : 
      64             : // Turn this on if you want to debug slider frames.
      65             : #undef DEBUG_SLIDER
      66             : 
      67             : static already_AddRefed<nsIContent>
      68          18 : GetContentOfBox(nsIFrame *aBox)
      69             : {
      70          36 :   nsCOMPtr<nsIContent> content = aBox->GetContent();
      71          36 :   return content.forget();
      72             : }
      73             : 
      74             : nsIFrame*
      75           4 : NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
      76             : {
      77           4 :   return new (aPresShell) nsSliderFrame(aContext);
      78             : }
      79             : 
      80           4 : NS_IMPL_FRAMEARENA_HELPERS(nsSliderFrame)
      81             : 
      82          18 : NS_QUERYFRAME_HEAD(nsSliderFrame)
      83           0 :   NS_QUERYFRAME_ENTRY(nsSliderFrame)
      84          18 : NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
      85             : 
      86           4 : nsSliderFrame::nsSliderFrame(nsStyleContext* aContext)
      87             :   : nsBoxFrame(aContext, kClassID)
      88             :   , mRatio(0.0f)
      89             :   , mDragStart(0)
      90             :   , mThumbStart(0)
      91             :   , mCurPos(0)
      92             :   , mChange(0)
      93             :   , mDragFinished(true)
      94             :   , mUserChanged(false)
      95             :   , mScrollingWithAPZ(false)
      96           4 :   , mSuppressionActive(false)
      97             : {
      98           4 : }
      99             : 
     100             : // stop timer
     101           0 : nsSliderFrame::~nsSliderFrame()
     102             : {
     103           0 :   if (mSuppressionActive) {
     104           0 :     APZCCallbackHelper::SuppressDisplayport(false, PresContext() ?
     105           0 :                                                    PresContext()->PresShell() :
     106           0 :                                                    nullptr);
     107             :   }
     108           0 : }
     109             : 
     110             : void
     111           4 : nsSliderFrame::Init(nsIContent*       aContent,
     112             :                     nsContainerFrame* aParent,
     113             :                     nsIFrame*         aPrevInFlow)
     114             : {
     115           4 :   nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
     116             : 
     117             :   static bool gotPrefs = false;
     118           4 :   if (!gotPrefs) {
     119           2 :     gotPrefs = true;
     120             : 
     121           2 :     gMiddlePref = Preferences::GetBool("middlemouse.scrollbarPosition");
     122           2 :     gSnapMultiplier = Preferences::GetInt("slider.snapMultiplier");
     123             :   }
     124             : 
     125           4 :   mCurPos = GetCurrentPosition(aContent);
     126           4 : }
     127             : 
     128             : void
     129           0 : nsSliderFrame::RemoveFrame(ChildListID     aListID,
     130             :                            nsIFrame*       aOldFrame)
     131             : {
     132           0 :   nsBoxFrame::RemoveFrame(aListID, aOldFrame);
     133           0 :   if (mFrames.IsEmpty())
     134           0 :     RemoveListener();
     135           0 : }
     136             : 
     137             : void
     138           0 : nsSliderFrame::InsertFrames(ChildListID     aListID,
     139             :                             nsIFrame*       aPrevFrame,
     140             :                             nsFrameList&    aFrameList)
     141             : {
     142           0 :   bool wasEmpty = mFrames.IsEmpty();
     143           0 :   nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
     144           0 :   if (wasEmpty)
     145           0 :     AddListener();
     146           0 : }
     147             : 
     148             : void
     149           0 : nsSliderFrame::AppendFrames(ChildListID     aListID,
     150             :                             nsFrameList&    aFrameList)
     151             : {
     152             :   // if we have no children and on was added then make sure we add the
     153             :   // listener
     154           0 :   bool wasEmpty = mFrames.IsEmpty();
     155           0 :   nsBoxFrame::AppendFrames(aListID, aFrameList);
     156           0 :   if (wasEmpty)
     157           0 :     AddListener();
     158           0 : }
     159             : 
     160             : int32_t
     161          22 : nsSliderFrame::GetCurrentPosition(nsIContent* content)
     162             : {
     163          22 :   return GetIntegerAttribute(content, nsGkAtoms::curpos, 0);
     164             : }
     165             : 
     166             : int32_t
     167          14 : nsSliderFrame::GetMinPosition(nsIContent* content)
     168             : {
     169          14 :   return GetIntegerAttribute(content, nsGkAtoms::minpos, 0);
     170             : }
     171             : 
     172             : int32_t
     173          14 : nsSliderFrame::GetMaxPosition(nsIContent* content)
     174             : {
     175          14 :   return GetIntegerAttribute(content, nsGkAtoms::maxpos, 100);
     176             : }
     177             : 
     178             : int32_t
     179           0 : nsSliderFrame::GetIncrement(nsIContent* content)
     180             : {
     181           0 :   return GetIntegerAttribute(content, nsGkAtoms::increment, 1);
     182             : }
     183             : 
     184             : 
     185             : int32_t
     186          10 : nsSliderFrame::GetPageIncrement(nsIContent* content)
     187             : {
     188          10 :   return GetIntegerAttribute(content, nsGkAtoms::pageincrement, 10);
     189             : }
     190             : 
     191             : int32_t
     192          60 : nsSliderFrame::GetIntegerAttribute(nsIContent* content, nsIAtom* atom, int32_t defaultValue)
     193             : {
     194         120 :     nsAutoString value;
     195          60 :     content->GetAttr(kNameSpaceID_None, atom, value);
     196          60 :     if (!value.IsEmpty()) {
     197             :       nsresult error;
     198             : 
     199             :       // convert it to an integer
     200          30 :       defaultValue = value.ToInteger(&error);
     201             :     }
     202             : 
     203         120 :     return defaultValue;
     204             : }
     205             : 
     206           0 : class nsValueChangedRunnable : public Runnable
     207             : {
     208             : public:
     209           0 :   nsValueChangedRunnable(nsISliderListener* aListener,
     210             :                          nsIAtom* aWhich,
     211             :                          int32_t aValue,
     212             :                          bool aUserChanged)
     213           0 :     : mozilla::Runnable("nsValueChangedRunnable")
     214             :     , mListener(aListener)
     215             :     , mWhich(aWhich)
     216             :     , mValue(aValue)
     217           0 :     , mUserChanged(aUserChanged)
     218           0 :   {}
     219             : 
     220           0 :   NS_IMETHOD Run() override
     221             :   {
     222           0 :     return mListener->ValueChanged(nsDependentAtomString(mWhich),
     223           0 :                                    mValue, mUserChanged);
     224             :   }
     225             : 
     226             :   nsCOMPtr<nsISliderListener> mListener;
     227             :   nsCOMPtr<nsIAtom> mWhich;
     228             :   int32_t mValue;
     229             :   bool mUserChanged;
     230             : };
     231             : 
     232           0 : class nsDragStateChangedRunnable : public Runnable
     233             : {
     234             : public:
     235           0 :   nsDragStateChangedRunnable(nsISliderListener* aListener, bool aDragBeginning)
     236           0 :     : mozilla::Runnable("nsDragStateChangedRunnable")
     237             :     , mListener(aListener)
     238           0 :     , mDragBeginning(aDragBeginning)
     239           0 :   {}
     240             : 
     241           0 :   NS_IMETHOD Run() override
     242             :   {
     243           0 :     return mListener->DragStateChanged(mDragBeginning);
     244             :   }
     245             : 
     246             :   nsCOMPtr<nsISliderListener> mListener;
     247             :   bool mDragBeginning;
     248             : };
     249             : 
     250             : nsresult
     251          20 : nsSliderFrame::AttributeChanged(int32_t aNameSpaceID,
     252             :                                 nsIAtom* aAttribute,
     253             :                                 int32_t aModType)
     254             : {
     255          20 :   nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
     256          20 :                                              aModType);
     257             :   // if the current position changes
     258          20 :   if (aAttribute == nsGkAtoms::curpos) {
     259           4 :      CurrentPositionChanged();
     260          32 :   } else if (aAttribute == nsGkAtoms::minpos ||
     261          16 :              aAttribute == nsGkAtoms::maxpos) {
     262             :       // bounds check it.
     263             : 
     264           4 :       nsIFrame* scrollbarBox = GetScrollbar();
     265           8 :       nsCOMPtr<nsIContent> scrollbar;
     266           4 :       scrollbar = GetContentOfBox(scrollbarBox);
     267           4 :       int32_t current = GetCurrentPosition(scrollbar);
     268           4 :       int32_t min = GetMinPosition(scrollbar);
     269           4 :       int32_t max = GetMaxPosition(scrollbar);
     270             : 
     271             :       // inform the parent <scale> that the minimum or maximum changed
     272           4 :       nsIFrame* parent = GetParent();
     273           4 :       if (parent) {
     274           8 :         nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
     275           4 :         if (sliderListener) {
     276             :           nsContentUtils::AddScriptRunner(
     277             :             new nsValueChangedRunnable(sliderListener, aAttribute,
     278           0 :                                        aAttribute == nsGkAtoms::minpos ? min : max, false));
     279             :         }
     280             :       }
     281             : 
     282           4 :       if (current < min || current > max)
     283             :       {
     284           0 :         int32_t direction = 0;
     285           0 :         if (current < min || max < min) {
     286           0 :           current = min;
     287           0 :           direction = -1;
     288           0 :         } else if (current > max) {
     289           0 :           current = max;
     290           0 :           direction = 1;
     291             :         }
     292             : 
     293             :         // set the new position and notify observers
     294           0 :         nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox);
     295           0 :         if (scrollbarFrame) {
     296           0 :           nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator();
     297           0 :           scrollbarFrame->SetIncrementToWhole(direction);
     298           0 :           if (mediator) {
     299             :             mediator->ScrollByWhole(scrollbarFrame, direction,
     300           0 :                                     nsIScrollbarMediator::ENABLE_SNAP);
     301             :           }
     302             :         }
     303             :         // 'this' might be destroyed here
     304             : 
     305             :         nsContentUtils::AddScriptRunner(
     306           0 :           new nsSetAttrRunnable(scrollbar, nsGkAtoms::curpos, current));
     307             :       }
     308             :   }
     309             : 
     310          40 :   if (aAttribute == nsGkAtoms::minpos ||
     311          36 :       aAttribute == nsGkAtoms::maxpos ||
     312          28 :       aAttribute == nsGkAtoms::pageincrement ||
     313          12 :       aAttribute == nsGkAtoms::increment) {
     314             : 
     315          12 :       PresContext()->PresShell()->
     316          12 :         FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     317             :   }
     318             : 
     319          20 :   return rv;
     320             : }
     321             : 
     322             : void
     323           0 : nsSliderFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     324             :                                 const nsRect&           aDirtyRect,
     325             :                                 const nsDisplayListSet& aLists)
     326             : {
     327           0 :   if (aBuilder->IsForEventDelivery() && isDraggingThumb()) {
     328             :     // This is EVIL, we shouldn't be messing with event delivery just to get
     329             :     // thumb mouse drag events to arrive at the slider!
     330           0 :     aLists.Outlines()->AppendNewToTop(new (aBuilder)
     331           0 :       nsDisplayEventReceiver(aBuilder, this));
     332           0 :     return;
     333             :   }
     334             : 
     335           0 :   nsBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
     336             : }
     337             : 
     338             : static bool
     339           0 : UsesCustomScrollbarMediator(nsIFrame* scrollbarBox) {
     340           0 :   if (nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox)) {
     341           0 :     if (nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator()) {
     342           0 :       nsIScrollableFrame* scrollFrame = do_QueryFrame(mediator);
     343             :       // The scrollbar mediator is not the scroll frame.
     344             :       // That means this scroll frame has a custom scrollbar mediator.
     345           0 :       if (!scrollFrame) {
     346           0 :         return true;
     347             :       }
     348             :     }
     349             :   }
     350           0 :   return false;
     351             : }
     352             : 
     353             : void
     354           0 : nsSliderFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
     355             :                                            const nsRect&           aDirtyRect,
     356             :                                            const nsDisplayListSet& aLists)
     357             : {
     358             :   // if we are too small to have a thumb don't paint it.
     359           0 :   nsIFrame* thumb = nsBox::GetChildXULBox(this);
     360             : 
     361           0 :   if (thumb) {
     362           0 :     nsRect thumbRect(thumb->GetRect());
     363           0 :     nsMargin m;
     364           0 :     thumb->GetXULMargin(m);
     365           0 :     thumbRect.Inflate(m);
     366             : 
     367           0 :     nsRect sliderTrack;
     368           0 :     GetXULClientRect(sliderTrack);
     369             : 
     370           0 :     if (sliderTrack.width < thumbRect.width || sliderTrack.height < thumbRect.height)
     371           0 :       return;
     372             : 
     373             :     // If this scrollbar is the scrollbar of an actively scrolled scroll frame,
     374             :     // layerize the scrollbar thumb, wrap it in its own ContainerLayer and
     375             :     // attach scrolling information to it.
     376             :     // We do this here and not in the thumb's nsBoxFrame::BuildDisplayList so
     377             :     // that the event region that gets created for the thumb is included in
     378             :     // the nsDisplayOwnLayer contents.
     379             : 
     380           0 :     uint32_t flags = aBuilder->GetCurrentScrollbarFlags();
     381             :     mozilla::layers::FrameMetrics::ViewID scrollTargetId =
     382           0 :       aBuilder->GetCurrentScrollbarTarget();
     383           0 :     bool thumbGetsLayer = (scrollTargetId != layers::FrameMetrics::NULL_SCROLL_ID);
     384           0 :     nsLayoutUtils::SetScrollbarThumbLayerization(thumb, thumbGetsLayer);
     385             : 
     386           0 :     if (thumbGetsLayer) {
     387           0 :       MOZ_ASSERT((flags & nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR) ||
     388             :                  (flags & nsDisplayOwnLayer::VERTICAL_SCROLLBAR));
     389           0 :       bool isHorizontal = (flags & nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR);
     390             :       ScrollDirection scrollDirection = isHorizontal
     391           0 :           ? ScrollDirection::HORIZONTAL
     392           0 :           : ScrollDirection::VERTICAL;
     393           0 :       const float appUnitsPerCss = float(AppUnitsPerCSSPixel());
     394             :       CSSCoord thumbLength = NSAppUnitsToFloatPixels(
     395           0 :           isHorizontal ? thumbRect.width : thumbRect.height, appUnitsPerCss);
     396             : 
     397           0 :       nsIFrame* scrollbarBox = GetScrollbar();
     398           0 :       bool isAsyncDraggable = !UsesCustomScrollbarMediator(scrollbarBox);
     399             : 
     400           0 :       nsPoint scrollPortOrigin;
     401           0 :       if (nsIScrollableFrame* scrollFrame = do_QueryFrame(scrollbarBox->GetParent())) {
     402           0 :         scrollPortOrigin = scrollFrame->GetScrollPortRect().TopLeft();
     403             :       } else {
     404           0 :         isAsyncDraggable = false;
     405             :       }
     406             : 
     407             :       // This rect is the range in which the scroll thumb can slide in.
     408           0 :       sliderTrack = sliderTrack + GetRect().TopLeft() + scrollbarBox->GetPosition() -
     409             :                     scrollPortOrigin;
     410             :       CSSCoord sliderTrackStart = NSAppUnitsToFloatPixels(
     411           0 :           isHorizontal ? sliderTrack.x : sliderTrack.y, appUnitsPerCss);
     412             :       CSSCoord sliderTrackLength = NSAppUnitsToFloatPixels(
     413           0 :           isHorizontal ? sliderTrack.width : sliderTrack.height, appUnitsPerCss);
     414             :       CSSCoord thumbStart = NSAppUnitsToFloatPixels(
     415           0 :           isHorizontal ? thumbRect.x : thumbRect.y, appUnitsPerCss);
     416             : 
     417           0 :       nsRect overflow = thumb->GetVisualOverflowRectRelativeToParent();
     418           0 :       nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
     419           0 :       gfxSize scale = nsLayoutUtils::GetTransformToAncestorScale(thumb);
     420           0 :       if (scale.width != 0 && scale.height != 0) {
     421           0 :         refSize.width /= scale.width;
     422           0 :         refSize.height /= scale.height;
     423             :       }
     424           0 :       nsRect dirty = aDirtyRect.Intersect(thumbRect);
     425           0 :       dirty = nsLayoutUtils::ComputePartialPrerenderArea(aDirtyRect, overflow, refSize);
     426             : 
     427             :       // Clip the thumb layer to the slider track. This is necessary to ensure
     428             :       // FrameLayerBuilder is able to merge content before and after the
     429             :       // scrollframe into the same layer (otherwise it thinks the thumb could
     430             :       // potentially move anywhere within the existing clip).
     431           0 :       DisplayListClipState::AutoSaveRestore thumbClipState(aBuilder);
     432           0 :       aBuilder->GetCurrentReferenceFrame();
     433             :       thumbClipState.ClipContainingBlockDescendants(
     434           0 :           GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this));
     435             : 
     436             :       // Have the thumb's container layer capture the current clip, so
     437             :       // it doesn't apply to the thumb's contents. This allows the contents
     438             :       // to be fully rendered even if they're partially or fully offscreen,
     439             :       // so async scrolling can still bring it into view.
     440           0 :       DisplayListClipState::AutoSaveRestore thumbContentsClipState(aBuilder);
     441           0 :       thumbContentsClipState.Clear();
     442             : 
     443           0 :       nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
     444           0 :       nsDisplayListCollection tempLists;
     445           0 :       nsBoxFrame::BuildDisplayListForChildren(aBuilder, dirty, tempLists);
     446             : 
     447             :       // This is a bit of a hack. Collect up all descendant display items
     448             :       // and merge them into a single Content() list.
     449           0 :       nsDisplayList masterList;
     450           0 :       masterList.AppendToTop(tempLists.BorderBackground());
     451           0 :       masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
     452           0 :       masterList.AppendToTop(tempLists.Floats());
     453           0 :       masterList.AppendToTop(tempLists.Content());
     454           0 :       masterList.AppendToTop(tempLists.PositionedDescendants());
     455           0 :       masterList.AppendToTop(tempLists.Outlines());
     456             : 
     457             :       // Restore the saved clip so it applies to the thumb container layer.
     458           0 :       thumbContentsClipState.Restore();
     459             : 
     460             :       // Wrap the list to make it its own layer.
     461           0 :       const ActiveScrolledRoot* ownLayerASR = contASRTracker.GetContainerASR();
     462           0 :       aLists.Content()->AppendNewToTop(new (aBuilder)
     463             :         nsDisplayOwnLayer(aBuilder, this, &masterList, ownLayerASR,
     464             :                           flags, scrollTargetId,
     465           0 :                           ScrollThumbData{scrollDirection,
     466             :                                           GetThumbRatio(),
     467             :                                           thumbStart,
     468             :                                           thumbLength,
     469             :                                           isAsyncDraggable,
     470             :                                           sliderTrackStart,
     471           0 :                                           sliderTrackLength}));
     472             : 
     473           0 :       return;
     474             :     }
     475             :   }
     476             : 
     477           0 :   nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
     478             : }
     479             : 
     480             : NS_IMETHODIMP
     481          10 : nsSliderFrame::DoXULLayout(nsBoxLayoutState& aState)
     482             : {
     483             :   // get the thumb should be our only child
     484          10 :   nsIFrame* thumbBox = nsBox::GetChildXULBox(this);
     485             : 
     486          10 :   if (!thumbBox) {
     487           0 :     SyncLayout(aState);
     488           0 :     return NS_OK;
     489             :   }
     490             : 
     491          10 :   EnsureOrient();
     492             : 
     493             : #ifdef DEBUG_LAYOUT
     494             :   if (mState & NS_STATE_DEBUG_WAS_SET) {
     495             :       if (mState & NS_STATE_SET_TO_DEBUG)
     496             :           SetXULDebug(aState, true);
     497             :       else
     498             :           SetXULDebug(aState, false);
     499             :   }
     500             : #endif
     501             : 
     502             :   // get the content area inside our borders
     503          20 :   nsRect clientRect;
     504          10 :   GetXULClientRect(clientRect);
     505             : 
     506             :   // get the scrollbar
     507          10 :   nsIFrame* scrollbarBox = GetScrollbar();
     508          20 :   nsCOMPtr<nsIContent> scrollbar;
     509          10 :   scrollbar = GetContentOfBox(scrollbarBox);
     510             : 
     511             :   // get the thumb's pref size
     512          10 :   nsSize thumbSize = thumbBox->GetXULPrefSize(aState);
     513             : 
     514          10 :   if (IsXULHorizontal())
     515           5 :     thumbSize.height = clientRect.height;
     516             :   else
     517           5 :     thumbSize.width = clientRect.width;
     518             : 
     519          10 :   int32_t curPos = GetCurrentPosition(scrollbar);
     520          10 :   int32_t minPos = GetMinPosition(scrollbar);
     521          10 :   int32_t maxPos = GetMaxPosition(scrollbar);
     522          10 :   int32_t pageIncrement = GetPageIncrement(scrollbar);
     523             : 
     524          10 :   maxPos = std::max(minPos, maxPos);
     525          10 :   curPos = clamped(curPos, minPos, maxPos);
     526             : 
     527          10 :   nscoord& availableLength = IsXULHorizontal() ? clientRect.width : clientRect.height;
     528          10 :   nscoord& thumbLength = IsXULHorizontal() ? thumbSize.width : thumbSize.height;
     529             : 
     530          10 :   if ((pageIncrement + maxPos - minPos) > 0 && thumbBox->GetXULFlex() > 0) {
     531          10 :     float ratio = float(pageIncrement) / float(maxPos - minPos + pageIncrement);
     532          10 :     thumbLength = std::max(thumbLength, NSToCoordRound(availableLength * ratio));
     533             :   }
     534             : 
     535             :   // Round the thumb's length to device pixels.
     536          10 :   nsPresContext* presContext = PresContext();
     537          10 :   thumbLength = presContext->DevPixelsToAppUnits(
     538             :                   presContext->AppUnitsToDevPixels(thumbLength));
     539             : 
     540             :   // mRatio translates the thumb position in app units to the value.
     541          10 :   mRatio = (minPos != maxPos) ? float(availableLength - thumbLength) / float(maxPos - minPos) : 1;
     542             : 
     543             :   // in reverse mode, curpos is reversed such that lower values are to the
     544             :   // right or bottom and increase leftwards or upwards. In this case, use the
     545             :   // offset from the end instead of the beginning.
     546          10 :   bool reverse = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
     547          10 :                                          nsGkAtoms::reverse, eCaseMatters);
     548          10 :   nscoord pos = reverse ? (maxPos - curPos) : (curPos - minPos);
     549             : 
     550             :   // set the thumb's coord to be the current pos * the ratio.
     551          20 :   nsRect thumbRect(clientRect.x, clientRect.y, thumbSize.width, thumbSize.height);
     552          10 :   int32_t& thumbPos = (IsXULHorizontal() ? thumbRect.x : thumbRect.y);
     553          10 :   thumbPos += NSToCoordRound(pos * mRatio);
     554             : 
     555          20 :   nsRect oldThumbRect(thumbBox->GetRect());
     556          10 :   LayoutChildAt(aState, thumbBox, thumbRect);
     557             : 
     558          10 :   SyncLayout(aState);
     559             : 
     560             :   // Redraw only if thumb changed size.
     561          10 :   if (!oldThumbRect.IsEqualInterior(thumbRect))
     562           0 :     XULRedraw(aState);
     563             : 
     564          10 :   return NS_OK;
     565             : }
     566             : 
     567             : 
     568             : nsresult
     569           0 : nsSliderFrame::HandleEvent(nsPresContext* aPresContext,
     570             :                            WidgetGUIEvent* aEvent,
     571             :                            nsEventStatus* aEventStatus)
     572             : {
     573           0 :   NS_ENSURE_ARG_POINTER(aEventStatus);
     574             : 
     575             :   // If a web page calls event.preventDefault() we still want to
     576             :   // scroll when scroll arrow is clicked. See bug 511075.
     577           0 :   if (!mContent->IsInNativeAnonymousSubtree() &&
     578           0 :       nsEventStatus_eConsumeNoDefault == *aEventStatus) {
     579           0 :     return NS_OK;
     580             :   }
     581             : 
     582           0 :   if (!mDragFinished && !isDraggingThumb()) {
     583           0 :     StopDrag();
     584           0 :     return NS_OK;
     585             :   }
     586             : 
     587           0 :   nsIFrame* scrollbarBox = GetScrollbar();
     588           0 :   nsCOMPtr<nsIContent> scrollbar;
     589           0 :   scrollbar = GetContentOfBox(scrollbarBox);
     590           0 :   bool isHorizontal = IsXULHorizontal();
     591             : 
     592           0 :   if (isDraggingThumb())
     593             :   {
     594           0 :     switch (aEvent->mMessage) {
     595             :     case eTouchMove:
     596             :     case eMouseMove: {
     597           0 :       if (mScrollingWithAPZ) {
     598           0 :         break;
     599             :       }
     600           0 :       nsPoint eventPoint;
     601           0 :       if (!GetEventPoint(aEvent, eventPoint)) {
     602           0 :         break;
     603             :       }
     604           0 :       if (mChange) {
     605             :         // On Linux the destination point is determined by the initial click
     606             :         // on the scrollbar track and doesn't change until the mouse button
     607             :         // is released.
     608             : #ifndef MOZ_WIDGET_GTK
     609             :         // On the other platforms we need to update the destination point now.
     610             :         mDestinationPoint = eventPoint;
     611             :         StopRepeat();
     612             :         StartRepeat();
     613             : #endif
     614           0 :         break;
     615             :       }
     616             : 
     617           0 :       nscoord pos = isHorizontal ? eventPoint.x : eventPoint.y;
     618             : 
     619           0 :       nsIFrame* thumbFrame = mFrames.FirstChild();
     620           0 :       if (!thumbFrame) {
     621           0 :         return NS_OK;
     622             :       }
     623             : 
     624             :       mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
     625           0 :           (uint32_t) ScrollInputMethod::MainThreadScrollbarDrag);
     626             : 
     627             :       // take our current position and subtract the start location
     628           0 :       pos -= mDragStart;
     629           0 :       bool isMouseOutsideThumb = false;
     630           0 :       if (gSnapMultiplier) {
     631           0 :         nsSize thumbSize = thumbFrame->GetSize();
     632           0 :         if (isHorizontal) {
     633             :           // horizontal scrollbar - check if mouse is above or below thumb
     634             :           // XXXbz what about looking at the .y of the thumb's rect?  Is that
     635             :           // always zero here?
     636           0 :           if (eventPoint.y < -gSnapMultiplier * thumbSize.height ||
     637           0 :               eventPoint.y > thumbSize.height +
     638             :                                gSnapMultiplier * thumbSize.height)
     639           0 :             isMouseOutsideThumb = true;
     640             :         }
     641             :         else {
     642             :           // vertical scrollbar - check if mouse is left or right of thumb
     643           0 :           if (eventPoint.x < -gSnapMultiplier * thumbSize.width ||
     644           0 :               eventPoint.x > thumbSize.width +
     645             :                                gSnapMultiplier * thumbSize.width)
     646           0 :             isMouseOutsideThumb = true;
     647             :         }
     648             :       }
     649           0 :       if (aEvent->mClass == eTouchEventClass) {
     650           0 :         *aEventStatus = nsEventStatus_eConsumeNoDefault;
     651             :       }
     652           0 :       if (isMouseOutsideThumb)
     653             :       {
     654           0 :         SetCurrentThumbPosition(scrollbar, mThumbStart, false, false);
     655           0 :         return NS_OK;
     656             :       }
     657             : 
     658             :       // set it
     659           0 :       SetCurrentThumbPosition(scrollbar, pos, false, true); // with snapping
     660             :     }
     661           0 :     break;
     662             : 
     663             :     case eTouchEnd:
     664             :     case eMouseUp:
     665           0 :       if (ShouldScrollForEvent(aEvent)) {
     666           0 :         StopDrag();
     667             :         //we MUST call nsFrame HandleEvent for mouse ups to maintain the selection state and capture state.
     668           0 :         return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
     669             :       }
     670           0 :       break;
     671             : 
     672             :     default:
     673           0 :       break;
     674             :     }
     675             : 
     676             :     //return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
     677           0 :     return NS_OK;
     678           0 :   } else if (ShouldScrollToClickForEvent(aEvent)) {
     679           0 :     nsPoint eventPoint;
     680           0 :     if (!GetEventPoint(aEvent, eventPoint)) {
     681           0 :       return NS_OK;
     682             :     }
     683           0 :     nscoord pos = isHorizontal ? eventPoint.x : eventPoint.y;
     684             : 
     685             :     // adjust so that the middle of the thumb is placed under the click
     686           0 :     nsIFrame* thumbFrame = mFrames.FirstChild();
     687           0 :     if (!thumbFrame) {
     688           0 :       return NS_OK;
     689             :     }
     690           0 :     nsSize thumbSize = thumbFrame->GetSize();
     691           0 :     nscoord thumbLength = isHorizontal ? thumbSize.width : thumbSize.height;
     692             : 
     693             :     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
     694           0 :         (uint32_t) ScrollInputMethod::MainThreadScrollbarTrackClick);
     695             : 
     696             :     // set it
     697           0 :     AutoWeakFrame weakFrame(this);
     698             :     // should aMaySnap be true here?
     699           0 :     SetCurrentThumbPosition(scrollbar, pos - thumbLength/2, false, false);
     700           0 :     NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     701             : 
     702           0 :     DragThumb(true);
     703             : 
     704             : #ifdef MOZ_WIDGET_GTK
     705           0 :     nsCOMPtr<nsIContent> thumb = thumbFrame->GetContent();
     706           0 :     thumb->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
     707             : #endif
     708             : 
     709           0 :     if (aEvent->mClass == eTouchEventClass) {
     710           0 :       *aEventStatus = nsEventStatus_eConsumeNoDefault;
     711             :     }
     712             : 
     713           0 :     if (isHorizontal)
     714           0 :       mThumbStart = thumbFrame->GetPosition().x;
     715             :     else
     716           0 :       mThumbStart = thumbFrame->GetPosition().y;
     717             : 
     718           0 :     mDragStart = pos - mThumbStart;
     719             :   }
     720             : #ifdef MOZ_WIDGET_GTK
     721           0 :   else if (ShouldScrollForEvent(aEvent) &&
     722           0 :            aEvent->mClass == eMouseEventClass &&
     723           0 :            aEvent->AsMouseEvent()->button == WidgetMouseEvent::eRightButton) {
     724             :     // HandlePress and HandleRelease are usually called via
     725             :     // nsFrame::HandleEvent, but only for the left mouse button.
     726           0 :     if (aEvent->mMessage == eMouseDown) {
     727           0 :       HandlePress(aPresContext, aEvent, aEventStatus);
     728           0 :     } else if (aEvent->mMessage == eMouseUp) {
     729           0 :       HandleRelease(aPresContext, aEvent, aEventStatus);
     730             :     }
     731             : 
     732           0 :     return NS_OK;
     733             :   }
     734             : #endif
     735             : 
     736             :   // XXX hack until handle release is actually called in nsframe.
     737             :   //  if (aEvent->mMessage == eMouseOut ||
     738             :   //      aEvent->mMessage == NS_MOUSE_RIGHT_BUTTON_UP ||
     739             :   //      aEvent->mMessage == NS_MOUSE_LEFT_BUTTON_UP) {
     740             :   //    HandleRelease(aPresContext, aEvent, aEventStatus);
     741             :   //  }
     742             : 
     743           0 :   if (aEvent->mMessage == eMouseOut && mChange)
     744           0 :      HandleRelease(aPresContext, aEvent, aEventStatus);
     745             : 
     746           0 :   return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
     747             : }
     748             : 
     749             : // Helper function to collect the "scroll to click" metric. Beware of
     750             : // caching this, users expect to be able to change the system preference
     751             : // and see the browser change its behavior immediately.
     752             : bool
     753           0 : nsSliderFrame::GetScrollToClick()
     754             : {
     755           0 :   if (GetScrollbar() != this) {
     756           0 :     return LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollToClick, false);
     757             :   }
     758             : 
     759           0 :   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::movetoclick,
     760             :                             nsGkAtoms::_true, eCaseMatters)) {
     761           0 :     return true;
     762             :   }
     763           0 :   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::movetoclick,
     764             :                             nsGkAtoms::_false, eCaseMatters)) {
     765           0 :     return false;
     766             :   }
     767             : 
     768             : #ifdef XP_MACOSX
     769             :   return true;
     770             : #else
     771           0 :   return false;
     772             : #endif
     773             : }
     774             : 
     775             : nsIFrame*
     776          92 : nsSliderFrame::GetScrollbar()
     777             : {
     778             :   // if we are in a scrollbar then return the scrollbar's content node
     779             :   // if we are not then return ours.
     780             :    nsIFrame* scrollbar;
     781          92 :    nsScrollbarButtonFrame::GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
     782             : 
     783          92 :    if (scrollbar == nullptr)
     784           0 :        return this;
     785             : 
     786          92 :    return scrollbar->IsXULBoxFrame() ? scrollbar : this;
     787             : }
     788             : 
     789             : void
     790           0 : nsSliderFrame::PageUpDown(nscoord change)
     791             : {
     792             :   // on a page up or down get our page increment. We get this by getting the scrollbar we are in and
     793             :   // asking it for the current position and the page increment. If we are not in a scrollbar we will
     794             :   // get the values from our own node.
     795           0 :   nsIFrame* scrollbarBox = GetScrollbar();
     796           0 :   nsCOMPtr<nsIContent> scrollbar;
     797           0 :   scrollbar = GetContentOfBox(scrollbarBox);
     798             : 
     799           0 :   nscoord pageIncrement = GetPageIncrement(scrollbar);
     800           0 :   int32_t curpos = GetCurrentPosition(scrollbar);
     801           0 :   int32_t minpos = GetMinPosition(scrollbar);
     802           0 :   int32_t maxpos = GetMaxPosition(scrollbar);
     803             : 
     804             :   // get the new position and make sure it is in bounds
     805           0 :   int32_t newpos = curpos + change * pageIncrement;
     806           0 :   if (newpos < minpos || maxpos < minpos)
     807           0 :     newpos = minpos;
     808           0 :   else if (newpos > maxpos)
     809           0 :     newpos = maxpos;
     810             : 
     811           0 :   SetCurrentPositionInternal(scrollbar, newpos, true);
     812           0 : }
     813             : 
     814             : // called when the current position changed and we need to update the thumb's location
     815             : void
     816           4 : nsSliderFrame::CurrentPositionChanged()
     817             : {
     818           4 :   nsIFrame* scrollbarBox = GetScrollbar();
     819           4 :   nsCOMPtr<nsIContent> scrollbar;
     820           4 :   scrollbar = GetContentOfBox(scrollbarBox);
     821             : 
     822             :   // get the current position
     823           4 :   int32_t curPos = GetCurrentPosition(scrollbar);
     824             : 
     825             :   // do nothing if the position did not change
     826           4 :   if (mCurPos == curPos)
     827           4 :     return;
     828             : 
     829             :   // get our current min and max position from our content node
     830           0 :   int32_t minPos = GetMinPosition(scrollbar);
     831           0 :   int32_t maxPos = GetMaxPosition(scrollbar);
     832             : 
     833           0 :   maxPos = std::max(minPos, maxPos);
     834           0 :   curPos = clamped(curPos, minPos, maxPos);
     835             : 
     836             :   // get the thumb's rect
     837           0 :   nsIFrame* thumbFrame = mFrames.FirstChild();
     838           0 :   if (!thumbFrame)
     839           0 :     return; // The thumb may stream in asynchronously via XBL.
     840             : 
     841           0 :   nsRect thumbRect = thumbFrame->GetRect();
     842             : 
     843           0 :   nsRect clientRect;
     844           0 :   GetXULClientRect(clientRect);
     845             : 
     846             :   // figure out the new rect
     847           0 :   nsRect newThumbRect(thumbRect);
     848             : 
     849           0 :   bool reverse = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
     850           0 :                                          nsGkAtoms::reverse, eCaseMatters);
     851           0 :   nscoord pos = reverse ? (maxPos - curPos) : (curPos - minPos);
     852             : 
     853           0 :   if (IsXULHorizontal())
     854           0 :      newThumbRect.x = clientRect.x + NSToCoordRound(pos * mRatio);
     855             :   else
     856           0 :      newThumbRect.y = clientRect.y + NSToCoordRound(pos * mRatio);
     857             : 
     858             :   // avoid putting the scroll thumb at subpixel positions which cause needless invalidations
     859           0 :   nscoord appUnitsPerPixel = PresContext()->AppUnitsPerDevPixel();
     860             :   nsPoint snappedThumbLocation = ToAppUnits(
     861           0 :       newThumbRect.TopLeft().ToNearestPixels(appUnitsPerPixel),
     862           0 :       appUnitsPerPixel);
     863           0 :   if (IsXULHorizontal()) {
     864           0 :     newThumbRect.x = snappedThumbLocation.x;
     865             :   } else {
     866           0 :     newThumbRect.y = snappedThumbLocation.y;
     867             :   }
     868             : 
     869             :   // set the rect
     870           0 :   thumbFrame->SetRect(newThumbRect);
     871             : 
     872             :   // Request a repaint of the scrollbar
     873           0 :   nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox);
     874             :   nsIScrollbarMediator* mediator = scrollbarFrame
     875           0 :       ? scrollbarFrame->GetScrollbarMediator() : nullptr;
     876           0 :   if (!mediator || !mediator->ShouldSuppressScrollbarRepaints()) {
     877           0 :     SchedulePaint();
     878             :   }
     879             : 
     880           0 :   mCurPos = curPos;
     881             : 
     882             :   // inform the parent <scale> if it exists that the value changed
     883           0 :   nsIFrame* parent = GetParent();
     884           0 :   if (parent) {
     885           0 :     nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
     886           0 :     if (sliderListener) {
     887             :       nsContentUtils::AddScriptRunner(
     888           0 :         new nsValueChangedRunnable(sliderListener, nsGkAtoms::curpos, mCurPos, mUserChanged));
     889             :     }
     890             :   }
     891             : }
     892             : 
     893           0 : static void UpdateAttribute(nsIContent* aScrollbar, nscoord aNewPos, bool aNotify, bool aIsSmooth) {
     894           0 :   nsAutoString str;
     895           0 :   str.AppendInt(aNewPos);
     896             : 
     897           0 :   if (aIsSmooth) {
     898           0 :     aScrollbar->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false);
     899             :   }
     900           0 :   aScrollbar->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, str, aNotify);
     901           0 :   if (aIsSmooth) {
     902           0 :     aScrollbar->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false);
     903             :   }
     904           0 : }
     905             : 
     906             : // Use this function when you want to set the scroll position via the position
     907             : // of the scrollbar thumb, e.g. when dragging the slider. This function scrolls
     908             : // the content in such a way that thumbRect.x/.y becomes aNewThumbPos.
     909             : void
     910           0 : nsSliderFrame::SetCurrentThumbPosition(nsIContent* aScrollbar, nscoord aNewThumbPos,
     911             :                                        bool aIsSmooth, bool aMaySnap)
     912             : {
     913           0 :   nsRect crect;
     914           0 :   GetXULClientRect(crect);
     915           0 :   nscoord offset = IsXULHorizontal() ? crect.x : crect.y;
     916           0 :   int32_t newPos = NSToIntRound((aNewThumbPos - offset) / mRatio);
     917             : 
     918           0 :   if (aMaySnap && mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::snap,
     919             :                                         nsGkAtoms::_true, eCaseMatters)) {
     920             :     // If snap="true", then the slider may only be set to min + (increment * x).
     921             :     // Otherwise, the slider may be set to any positive integer.
     922           0 :     int32_t increment = GetIncrement(aScrollbar);
     923           0 :     newPos = NSToIntRound(newPos / float(increment)) * increment;
     924             :   }
     925             : 
     926           0 :   SetCurrentPosition(aScrollbar, newPos, aIsSmooth);
     927           0 : }
     928             : 
     929             : // Use this function when you know the target scroll position of the scrolled content.
     930             : // aNewPos should be passed to this function as a position as if the minpos is 0.
     931             : // That is, the minpos will be added to the position by this function. In a reverse
     932             : // direction slider, the newpos should be the distance from the end.
     933             : void
     934           0 : nsSliderFrame::SetCurrentPosition(nsIContent* aScrollbar, int32_t aNewPos,
     935             :                                   bool aIsSmooth)
     936             : {
     937             :    // get min and max position from our content node
     938           0 :   int32_t minpos = GetMinPosition(aScrollbar);
     939           0 :   int32_t maxpos = GetMaxPosition(aScrollbar);
     940             : 
     941             :   // in reverse direction sliders, flip the value so that it goes from
     942             :   // right to left, or bottom to top.
     943           0 :   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
     944             :                             nsGkAtoms::reverse, eCaseMatters))
     945           0 :     aNewPos = maxpos - aNewPos;
     946             :   else
     947           0 :     aNewPos += minpos;
     948             : 
     949             :   // get the new position and make sure it is in bounds
     950           0 :   if (aNewPos < minpos || maxpos < minpos)
     951           0 :     aNewPos = minpos;
     952           0 :   else if (aNewPos > maxpos)
     953           0 :     aNewPos = maxpos;
     954             : 
     955           0 :   SetCurrentPositionInternal(aScrollbar, aNewPos, aIsSmooth);
     956           0 : }
     957             : 
     958             : void
     959           0 : nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, int32_t aNewPos,
     960             :                                           bool aIsSmooth)
     961             : {
     962           0 :   nsCOMPtr<nsIContent> scrollbar = aScrollbar;
     963           0 :   nsIFrame* scrollbarBox = GetScrollbar();
     964           0 :   AutoWeakFrame weakFrame(this);
     965             : 
     966           0 :   mUserChanged = true;
     967             : 
     968           0 :   nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox);
     969           0 :   if (scrollbarFrame) {
     970             :     // See if we have a mediator.
     971           0 :     nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator();
     972           0 :     if (mediator) {
     973           0 :       nscoord oldPos = nsPresContext::CSSPixelsToAppUnits(GetCurrentPosition(scrollbar));
     974           0 :       nscoord newPos = nsPresContext::CSSPixelsToAppUnits(aNewPos);
     975           0 :       mediator->ThumbMoved(scrollbarFrame, oldPos, newPos);
     976           0 :       if (!weakFrame.IsAlive()) {
     977           0 :         return;
     978             :       }
     979           0 :       UpdateAttribute(scrollbar, aNewPos, /* aNotify */false, aIsSmooth);
     980           0 :       CurrentPositionChanged();
     981           0 :       mUserChanged = false;
     982           0 :       return;
     983             :     }
     984             :   }
     985             : 
     986           0 :   UpdateAttribute(scrollbar, aNewPos, true, aIsSmooth);
     987           0 :   if (!weakFrame.IsAlive()) {
     988           0 :     return;
     989             :   }
     990           0 :   mUserChanged = false;
     991             : 
     992             : #ifdef DEBUG_SLIDER
     993             :   printf("Current Pos=%d\n",aNewPos);
     994             : #endif
     995             : 
     996             : }
     997             : 
     998             : void
     999           4 : nsSliderFrame::SetInitialChildList(ChildListID     aListID,
    1000             :                                    nsFrameList&    aChildList)
    1001             : {
    1002           4 :   nsBoxFrame::SetInitialChildList(aListID, aChildList);
    1003           4 :   if (aListID == kPrincipalList) {
    1004           4 :     AddListener();
    1005             :   }
    1006           4 : }
    1007             : 
    1008             : nsresult
    1009           0 : nsSliderMediator::HandleEvent(nsIDOMEvent* aEvent)
    1010             : {
    1011             :   // Only process the event if the thumb is not being dragged.
    1012           0 :   if (mSlider && !mSlider->isDraggingThumb())
    1013           0 :     return mSlider->StartDrag(aEvent);
    1014             : 
    1015           0 :   return NS_OK;
    1016             : }
    1017             : 
    1018             : class AsyncScrollbarDragStarter : public nsAPostRefreshObserver {
    1019             : public:
    1020           0 :   AsyncScrollbarDragStarter(nsIPresShell* aPresShell,
    1021             :                             nsIWidget* aWidget,
    1022             :                             const AsyncDragMetrics& aDragMetrics)
    1023           0 :     : mPresShell(aPresShell)
    1024             :     , mWidget(aWidget)
    1025           0 :     , mDragMetrics(aDragMetrics)
    1026             :   {
    1027           0 :   }
    1028           0 :   virtual ~AsyncScrollbarDragStarter() {}
    1029             : 
    1030           0 :   void DidRefresh() override {
    1031           0 :     if (!mPresShell) {
    1032           0 :       MOZ_ASSERT_UNREACHABLE("Post-refresh observer fired again after failed attempt at unregistering it");
    1033             :       return;
    1034             :     }
    1035             : 
    1036           0 :     mWidget->StartAsyncScrollbarDrag(mDragMetrics);
    1037             : 
    1038           0 :     if (!mPresShell->RemovePostRefreshObserver(this)) {
    1039           0 :       MOZ_ASSERT_UNREACHABLE("Unable to unregister post-refresh observer! Leaking it instead of leaving garbage registered");
    1040             :       // Graceful handling, just in case...
    1041             :       mPresShell = nullptr;
    1042             :       mWidget = nullptr;
    1043             :       return;
    1044             :     }
    1045             : 
    1046           0 :     delete this;
    1047             :   }
    1048             : 
    1049             : private:
    1050             :   RefPtr<nsIPresShell> mPresShell;
    1051             :   RefPtr<nsIWidget> mWidget;
    1052             :   AsyncDragMetrics mDragMetrics;
    1053             : };
    1054             : 
    1055             : bool
    1056           0 : UsesSVGEffects(nsIFrame* aFrame)
    1057             : {
    1058           0 :   return aFrame->StyleEffects()->HasFilters()
    1059           0 :       || nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(aFrame);
    1060             : }
    1061             : 
    1062             : bool
    1063           0 : ScrollFrameWillBuildScrollInfoLayer(nsIFrame* aScrollFrame)
    1064             : {
    1065           0 :   nsIFrame* current = aScrollFrame;
    1066           0 :   while (current) {
    1067           0 :     if (UsesSVGEffects(current)) {
    1068           0 :       return true;
    1069             :     }
    1070           0 :     current = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(current);
    1071             :   }
    1072           0 :   return false;
    1073             : }
    1074             : 
    1075             : void
    1076           0 : nsSliderFrame::StartAPZDrag(WidgetGUIEvent* aEvent)
    1077             : {
    1078           0 :   if (!aEvent->mFlags.mHandledByAPZ) {
    1079           0 :     return;
    1080             :   }
    1081             : 
    1082           0 :   if (!gfxPlatform::GetPlatform()->SupportsApzDragInput()) {
    1083           0 :     return;
    1084             :   }
    1085             : 
    1086           0 :   nsIFrame* scrollbarBox = GetScrollbar();
    1087           0 :   nsContainerFrame* scrollFrame = scrollbarBox->GetParent();
    1088           0 :   if (!scrollFrame) {
    1089           0 :     return;
    1090             :   }
    1091             : 
    1092           0 :   nsIContent* scrollableContent = scrollFrame->GetContent();
    1093           0 :   if (!scrollableContent) {
    1094           0 :     return;
    1095             :   }
    1096             : 
    1097             :   // APZ dragging requires the scrollbar to be layerized, which doesn't
    1098             :   // happen for scroll info layers.
    1099           0 :   if (ScrollFrameWillBuildScrollInfoLayer(scrollFrame)) {
    1100           0 :     return;
    1101             :   }
    1102             : 
    1103             :   // Custom scrollbar mediators are not supported in the APZ codepath.
    1104           0 :   if (UsesCustomScrollbarMediator(scrollbarBox)) {
    1105           0 :     return;
    1106             :   }
    1107             : 
    1108           0 :   bool isHorizontal = IsXULHorizontal();
    1109             : 
    1110             :   mozilla::layers::FrameMetrics::ViewID scrollTargetId;
    1111           0 :   bool hasID = nsLayoutUtils::FindIDFor(scrollableContent, &scrollTargetId);
    1112           0 :   bool hasAPZView = hasID && (scrollTargetId != layers::FrameMetrics::NULL_SCROLL_ID);
    1113             : 
    1114           0 :   if (!hasAPZView) {
    1115           0 :     return;
    1116             :   }
    1117             : 
    1118           0 :   nsCOMPtr<nsIContent> scrollbar = GetContentOfBox(scrollbarBox);
    1119             : 
    1120           0 :   nsIPresShell* shell = PresContext()->PresShell();
    1121           0 :   uint64_t inputblockId = InputAPZContext::GetInputBlockId();
    1122           0 :   uint32_t presShellId = shell->GetPresShellId();
    1123             :   AsyncDragMetrics dragMetrics(scrollTargetId, presShellId, inputblockId,
    1124             :                                NSAppUnitsToFloatPixels(mDragStart,
    1125           0 :                                  float(AppUnitsPerCSSPixel())),
    1126             :                                isHorizontal ? ScrollDirection::HORIZONTAL :
    1127           0 :                                               ScrollDirection::VERTICAL);
    1128             : 
    1129           0 :   if (!nsLayoutUtils::HasDisplayPort(scrollableContent)) {
    1130           0 :     return;
    1131             :   }
    1132             : 
    1133             :   // It's important to set this before calling nsIWidget::StartAsyncScrollbarDrag(),
    1134             :   // because in some configurations, that can call AsyncScrollbarDragRejected()
    1135             :   // synchronously, which clears the flag (and we want it to stay cleared in
    1136             :   // that case).
    1137           0 :   mScrollingWithAPZ = true;
    1138             : 
    1139             :   // When we start an APZ drag, we wont get mouse events for the drag.
    1140             :   // APZ will consume them all and only notify us of the new scroll position.
    1141           0 :   bool waitForRefresh = InputAPZContext::HavePendingLayerization();
    1142           0 :   nsIWidget* widget = this->GetNearestWidget();
    1143           0 :   if (waitForRefresh) {
    1144             :     waitForRefresh = shell->AddPostRefreshObserver(
    1145           0 :         new AsyncScrollbarDragStarter(shell, widget, dragMetrics));
    1146             :   }
    1147           0 :   if (!waitForRefresh) {
    1148           0 :     widget->StartAsyncScrollbarDrag(dragMetrics);
    1149             :   }
    1150             : }
    1151             : 
    1152             : nsresult
    1153           0 : nsSliderFrame::StartDrag(nsIDOMEvent* aEvent)
    1154             : {
    1155             : #ifdef DEBUG_SLIDER
    1156             :   printf("Begin dragging\n");
    1157             : #endif
    1158           0 :   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
    1159             :                             nsGkAtoms::_true, eCaseMatters))
    1160           0 :     return NS_OK;
    1161             : 
    1162           0 :   WidgetGUIEvent* event = aEvent->WidgetEventPtr()->AsGUIEvent();
    1163             : 
    1164           0 :   if (!ShouldScrollForEvent(event)) {
    1165           0 :     return NS_OK;
    1166             :   }
    1167             : 
    1168           0 :   nsPoint pt;
    1169           0 :   if (!GetEventPoint(event, pt)) {
    1170           0 :     return NS_OK;
    1171             :   }
    1172           0 :   bool isHorizontal = IsXULHorizontal();
    1173           0 :   nscoord pos = isHorizontal ? pt.x : pt.y;
    1174             : 
    1175             :   // If we should scroll-to-click, first place the middle of the slider thumb
    1176             :   // under the mouse.
    1177           0 :   nsCOMPtr<nsIContent> scrollbar;
    1178           0 :   nscoord newpos = pos;
    1179           0 :   bool scrollToClick = ShouldScrollToClickForEvent(event);
    1180           0 :   if (scrollToClick) {
    1181             :     // adjust so that the middle of the thumb is placed under the click
    1182           0 :     nsIFrame* thumbFrame = mFrames.FirstChild();
    1183           0 :     if (!thumbFrame) {
    1184           0 :       return NS_OK;
    1185             :     }
    1186           0 :     nsSize thumbSize = thumbFrame->GetSize();
    1187           0 :     nscoord thumbLength = isHorizontal ? thumbSize.width : thumbSize.height;
    1188             : 
    1189           0 :     newpos -= (thumbLength/2);
    1190             : 
    1191           0 :     nsIFrame* scrollbarBox = GetScrollbar();
    1192           0 :     scrollbar = GetContentOfBox(scrollbarBox);
    1193             :   }
    1194             : 
    1195           0 :   DragThumb(true);
    1196             : 
    1197           0 :   if (scrollToClick) {
    1198             :     // should aMaySnap be true here?
    1199           0 :     SetCurrentThumbPosition(scrollbar, newpos, false, false);
    1200             :   }
    1201             : 
    1202           0 :   nsIFrame* thumbFrame = mFrames.FirstChild();
    1203           0 :   if (!thumbFrame) {
    1204           0 :     return NS_OK;
    1205             :   }
    1206             : 
    1207             : #ifdef MOZ_WIDGET_GTK
    1208           0 :   nsCOMPtr<nsIContent> thumb = thumbFrame->GetContent();
    1209           0 :   thumb->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
    1210             : #endif
    1211             : 
    1212           0 :   if (isHorizontal)
    1213           0 :     mThumbStart = thumbFrame->GetPosition().x;
    1214             :   else
    1215           0 :     mThumbStart = thumbFrame->GetPosition().y;
    1216             : 
    1217           0 :   mDragStart = pos - mThumbStart;
    1218             : 
    1219           0 :   mScrollingWithAPZ = false;
    1220           0 :   StartAPZDrag(event);  // sets mScrollingWithAPZ=true if appropriate
    1221             : 
    1222             : #ifdef DEBUG_SLIDER
    1223             :   printf("Pressed mDragStart=%d\n",mDragStart);
    1224             : #endif
    1225             : 
    1226           0 :   if (!mScrollingWithAPZ) {
    1227           0 :     SuppressDisplayport();
    1228             :   }
    1229             : 
    1230           0 :   return NS_OK;
    1231             : }
    1232             : 
    1233             : nsresult
    1234           0 : nsSliderFrame::StopDrag()
    1235             : {
    1236           0 :   AddListener();
    1237           0 :   DragThumb(false);
    1238             : 
    1239           0 :   mScrollingWithAPZ = false;
    1240             : 
    1241           0 :   UnsuppressDisplayport();
    1242             : 
    1243             : #ifdef MOZ_WIDGET_GTK
    1244           0 :   nsIFrame* thumbFrame = mFrames.FirstChild();
    1245           0 :   if (thumbFrame) {
    1246           0 :     nsCOMPtr<nsIContent> thumb = thumbFrame->GetContent();
    1247           0 :     thumb->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
    1248             :   }
    1249             : #endif
    1250             : 
    1251           0 :   if (mChange) {
    1252           0 :     StopRepeat();
    1253           0 :     mChange = 0;
    1254             :   }
    1255           0 :   return NS_OK;
    1256             : }
    1257             : 
    1258             : void
    1259           0 : nsSliderFrame::DragThumb(bool aGrabMouseEvents)
    1260             : {
    1261           0 :   mDragFinished = !aGrabMouseEvents;
    1262             : 
    1263             :   // inform the parent <scale> that a drag is beginning or ending
    1264           0 :   nsIFrame* parent = GetParent();
    1265           0 :   if (parent) {
    1266           0 :     nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
    1267           0 :     if (sliderListener) {
    1268             :       nsContentUtils::AddScriptRunner(
    1269           0 :         new nsDragStateChangedRunnable(sliderListener, aGrabMouseEvents));
    1270             :     }
    1271             :   }
    1272             : 
    1273           0 :   nsIPresShell::SetCapturingContent(aGrabMouseEvents ? GetContent() : nullptr,
    1274           0 :                                     aGrabMouseEvents ? CAPTURE_IGNOREALLOWED : 0);
    1275           0 : }
    1276             : 
    1277             : bool
    1278           0 : nsSliderFrame::isDraggingThumb()
    1279             : {
    1280           0 :   return (nsIPresShell::GetCapturingContent() == GetContent());
    1281             : }
    1282             : 
    1283             : void
    1284           4 : nsSliderFrame::AddListener()
    1285             : {
    1286           4 :   if (!mMediator) {
    1287           4 :     mMediator = new nsSliderMediator(this);
    1288             :   }
    1289             : 
    1290           4 :   nsIFrame* thumbFrame = mFrames.FirstChild();
    1291           4 :   if (!thumbFrame) {
    1292           0 :     return;
    1293             :   }
    1294           4 :   thumbFrame->GetContent()->
    1295          16 :     AddSystemEventListener(NS_LITERAL_STRING("mousedown"), mMediator,
    1296          12 :                            false, false);
    1297           4 :   thumbFrame->GetContent()->
    1298          16 :     AddSystemEventListener(NS_LITERAL_STRING("touchstart"), mMediator,
    1299          12 :                            false, false);
    1300             : }
    1301             : 
    1302             : void
    1303           0 : nsSliderFrame::RemoveListener()
    1304             : {
    1305           0 :   NS_ASSERTION(mMediator, "No listener was ever added!!");
    1306             : 
    1307           0 :   nsIFrame* thumbFrame = mFrames.FirstChild();
    1308           0 :   if (!thumbFrame)
    1309           0 :     return;
    1310             : 
    1311           0 :   thumbFrame->GetContent()->
    1312           0 :     RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), mMediator, false);
    1313             : }
    1314             : 
    1315             : bool
    1316           0 : nsSliderFrame::ShouldScrollForEvent(WidgetGUIEvent* aEvent)
    1317             : {
    1318           0 :   switch (aEvent->mMessage) {
    1319             :     case eTouchStart:
    1320             :     case eTouchEnd:
    1321           0 :       return true;
    1322             :     case eMouseDown:
    1323             :     case eMouseUp: {
    1324           0 :       uint16_t button = aEvent->AsMouseEvent()->button;
    1325             : #ifdef MOZ_WIDGET_GTK
    1326           0 :       return (button == WidgetMouseEvent::eLeftButton) ||
    1327           0 :              (button == WidgetMouseEvent::eRightButton && GetScrollToClick()) ||
    1328           0 :              (button == WidgetMouseEvent::eMiddleButton && gMiddlePref && !GetScrollToClick());
    1329             : #else
    1330             :       return (button == WidgetMouseEvent::eLeftButton) ||
    1331             :              (button == WidgetMouseEvent::eMiddleButton && gMiddlePref);
    1332             : #endif
    1333             :     }
    1334             :     default:
    1335           0 :       return false;
    1336             :   }
    1337             : }
    1338             : 
    1339             : bool
    1340           0 : nsSliderFrame::ShouldScrollToClickForEvent(WidgetGUIEvent* aEvent)
    1341             : {
    1342           0 :   if (!ShouldScrollForEvent(aEvent)) {
    1343           0 :     return false;
    1344             :   }
    1345             : 
    1346           0 :   if (aEvent->mMessage == eTouchStart) {
    1347           0 :     return GetScrollToClick();
    1348             :   }
    1349             : 
    1350           0 :   if (aEvent->mMessage != eMouseDown) {
    1351           0 :     return false;
    1352             :   }
    1353             : 
    1354             : #if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
    1355             :   // On Mac and Linux, clicking the scrollbar thumb should never scroll to click.
    1356           0 :   if (IsEventOverThumb(aEvent)) {
    1357           0 :     return false;
    1358             :   }
    1359             : #endif
    1360             : 
    1361           0 :   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    1362           0 :   if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
    1363             : #ifdef XP_MACOSX
    1364             :     bool invertPref = mouseEvent->IsAlt();
    1365             : #else
    1366           0 :     bool invertPref = mouseEvent->IsShift();
    1367             : #endif
    1368           0 :     return GetScrollToClick() != invertPref;
    1369             :   }
    1370             : 
    1371             : #ifdef MOZ_WIDGET_GTK
    1372           0 :   if (mouseEvent->button == WidgetMouseEvent::eRightButton) {
    1373           0 :     return !GetScrollToClick();
    1374             :   }
    1375             : #endif
    1376             : 
    1377           0 :   return true;
    1378             : }
    1379             : 
    1380             : bool
    1381           0 : nsSliderFrame::IsEventOverThumb(WidgetGUIEvent* aEvent)
    1382             : {
    1383           0 :   nsIFrame* thumbFrame = mFrames.FirstChild();
    1384           0 :   if (!thumbFrame) {
    1385           0 :     return false;
    1386             :   }
    1387             : 
    1388           0 :   nsPoint eventPoint;
    1389           0 :   if (!GetEventPoint(aEvent, eventPoint)) {
    1390           0 :     return false;
    1391             :   }
    1392             : 
    1393           0 :   nsRect thumbRect = thumbFrame->GetRect();
    1394             : #if defined(MOZ_WIDGET_GTK)
    1395             :   /* Scrollbar track can have padding, so it's better to check that eventPoint
    1396             :    * is inside of actual thumb, not just its one axis. The part of the scrollbar
    1397             :    * track adjacent to thumb can actually receive events in GTK3 */
    1398           0 :   return eventPoint.x >= thumbRect.x && eventPoint.x < thumbRect.XMost() &&
    1399           0 :          eventPoint.y >= thumbRect.y && eventPoint.y < thumbRect.YMost();
    1400             : #else
    1401             :   bool isHorizontal = IsXULHorizontal();
    1402             :   nscoord eventPos = isHorizontal ? eventPoint.x : eventPoint.y;
    1403             :   nscoord thumbStart = isHorizontal ? thumbRect.x : thumbRect.y;
    1404             :   nscoord thumbEnd = isHorizontal ? thumbRect.XMost() : thumbRect.YMost();
    1405             : 
    1406             :   return eventPos >= thumbStart && eventPos < thumbEnd;
    1407             : #endif
    1408             : }
    1409             : 
    1410             : NS_IMETHODIMP
    1411           0 : nsSliderFrame::HandlePress(nsPresContext* aPresContext,
    1412             :                            WidgetGUIEvent* aEvent,
    1413             :                            nsEventStatus* aEventStatus)
    1414             : {
    1415           0 :   if (!ShouldScrollForEvent(aEvent) || ShouldScrollToClickForEvent(aEvent)) {
    1416           0 :     return NS_OK;
    1417             :   }
    1418             : 
    1419           0 :   if (IsEventOverThumb(aEvent)) {
    1420           0 :     return NS_OK;
    1421             :   }
    1422             : 
    1423           0 :   nsIFrame* thumbFrame = mFrames.FirstChild();
    1424           0 :   if (!thumbFrame) // display:none?
    1425           0 :     return NS_OK;
    1426             : 
    1427           0 :   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
    1428             :                             nsGkAtoms::_true, eCaseMatters))
    1429           0 :     return NS_OK;
    1430             : 
    1431           0 :   nsRect thumbRect = thumbFrame->GetRect();
    1432             : 
    1433           0 :   nscoord change = 1;
    1434           0 :   nsPoint eventPoint;
    1435           0 :   if (!GetEventPoint(aEvent, eventPoint)) {
    1436           0 :     return NS_OK;
    1437             :   }
    1438             : 
    1439             :   mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
    1440           0 :       (uint32_t) ScrollInputMethod::MainThreadScrollbarTrackClick);
    1441             : 
    1442           0 :   if (IsXULHorizontal() ? eventPoint.x < thumbRect.x
    1443           0 :                         : eventPoint.y < thumbRect.y)
    1444           0 :     change = -1;
    1445             : 
    1446           0 :   mChange = change;
    1447           0 :   DragThumb(true);
    1448             :   // On Linux we want to keep scrolling in the direction indicated by |change|
    1449             :   // until the mouse is released. On the other platforms we want to stop
    1450             :   // scrolling as soon as the scrollbar thumb has reached the current mouse
    1451             :   // position.
    1452             : #ifdef MOZ_WIDGET_GTK
    1453           0 :   nsRect clientRect;
    1454           0 :   GetXULClientRect(clientRect);
    1455             : 
    1456             :   // Set the destination point to the very end of the scrollbar so that
    1457             :   // scrolling doesn't stop halfway through.
    1458           0 :   if (change > 0) {
    1459           0 :     mDestinationPoint = nsPoint(clientRect.width, clientRect.height);
    1460             :   }
    1461             :   else {
    1462           0 :     mDestinationPoint = nsPoint(0, 0);
    1463             :   }
    1464             : #else
    1465             :   mDestinationPoint = eventPoint;
    1466             : #endif
    1467           0 :   StartRepeat();
    1468           0 :   PageScroll(change);
    1469             : 
    1470           0 :   return NS_OK;
    1471             : }
    1472             : 
    1473             : NS_IMETHODIMP
    1474           0 : nsSliderFrame::HandleRelease(nsPresContext* aPresContext,
    1475             :                              WidgetGUIEvent* aEvent,
    1476             :                              nsEventStatus* aEventStatus)
    1477             : {
    1478           0 :   StopRepeat();
    1479             : 
    1480           0 :   nsIFrame* scrollbar = GetScrollbar();
    1481           0 :   nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
    1482           0 :   if (sb) {
    1483           0 :     nsIScrollbarMediator* m = sb->GetScrollbarMediator();
    1484           0 :     if (m) {
    1485           0 :       m->ScrollbarReleased(sb);
    1486             :     }
    1487             :   }
    1488           0 :   return NS_OK;
    1489             : }
    1490             : 
    1491             : void
    1492           0 : nsSliderFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1493             : {
    1494             :   // tell our mediator if we have one we are gone.
    1495           0 :   if (mMediator) {
    1496           0 :     mMediator->SetSlider(nullptr);
    1497           0 :     mMediator = nullptr;
    1498             :   }
    1499           0 :   StopRepeat();
    1500             : 
    1501             :   // call base class Destroy()
    1502           0 :   nsBoxFrame::DestroyFrom(aDestructRoot);
    1503           0 : }
    1504             : 
    1505             : nsSize
    1506          12 : nsSliderFrame::GetXULPrefSize(nsBoxLayoutState& aState)
    1507             : {
    1508          12 :   EnsureOrient();
    1509          12 :   return nsBoxFrame::GetXULPrefSize(aState);
    1510             : }
    1511             : 
    1512             : nsSize
    1513          26 : nsSliderFrame::GetXULMinSize(nsBoxLayoutState& aState)
    1514             : {
    1515          26 :   EnsureOrient();
    1516             : 
    1517             :   // our min size is just our borders and padding
    1518          26 :   return nsBox::GetXULMinSize(aState);
    1519             : }
    1520             : 
    1521             : nsSize
    1522          26 : nsSliderFrame::GetXULMaxSize(nsBoxLayoutState& aState)
    1523             : {
    1524          26 :   EnsureOrient();
    1525          26 :   return nsBoxFrame::GetXULMaxSize(aState);
    1526             : }
    1527             : 
    1528             : void
    1529          74 : nsSliderFrame::EnsureOrient()
    1530             : {
    1531          74 :   nsIFrame* scrollbarBox = GetScrollbar();
    1532             : 
    1533          74 :   bool isHorizontal = (scrollbarBox->GetStateBits() & NS_STATE_IS_HORIZONTAL) != 0;
    1534          74 :   if (isHorizontal)
    1535          34 :       mState |= NS_STATE_IS_HORIZONTAL;
    1536             :   else
    1537          40 :       mState &= ~NS_STATE_IS_HORIZONTAL;
    1538          74 : }
    1539             : 
    1540             : 
    1541             : void
    1542           0 : nsSliderFrame::Notify(void)
    1543             : {
    1544           0 :     bool stop = false;
    1545             : 
    1546           0 :     nsIFrame* thumbFrame = mFrames.FirstChild();
    1547           0 :     if (!thumbFrame) {
    1548           0 :       StopRepeat();
    1549           0 :       return;
    1550             :     }
    1551           0 :     nsRect thumbRect = thumbFrame->GetRect();
    1552             : 
    1553           0 :     bool isHorizontal = IsXULHorizontal();
    1554             : 
    1555             :     // See if the thumb has moved past our destination point.
    1556             :     // if it has we want to stop.
    1557           0 :     if (isHorizontal) {
    1558           0 :         if (mChange < 0) {
    1559           0 :             if (thumbRect.x < mDestinationPoint.x)
    1560           0 :                 stop = true;
    1561             :         } else {
    1562           0 :             if (thumbRect.x + thumbRect.width > mDestinationPoint.x)
    1563           0 :                 stop = true;
    1564             :         }
    1565             :     } else {
    1566           0 :          if (mChange < 0) {
    1567           0 :             if (thumbRect.y < mDestinationPoint.y)
    1568           0 :                 stop = true;
    1569             :         } else {
    1570           0 :             if (thumbRect.y + thumbRect.height > mDestinationPoint.y)
    1571           0 :                 stop = true;
    1572             :         }
    1573             :     }
    1574             : 
    1575             : 
    1576           0 :     if (stop) {
    1577           0 :       StopRepeat();
    1578             :     } else {
    1579           0 :       PageScroll(mChange);
    1580             :     }
    1581             : }
    1582             : 
    1583             : void
    1584           0 : nsSliderFrame::PageScroll(nscoord aChange)
    1585             : {
    1586           0 :   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
    1587             :                             nsGkAtoms::reverse, eCaseMatters)) {
    1588           0 :     aChange = -aChange;
    1589             :   }
    1590           0 :   nsIFrame* scrollbar = GetScrollbar();
    1591           0 :   nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
    1592           0 :   if (sb) {
    1593           0 :     nsIScrollbarMediator* m = sb->GetScrollbarMediator();
    1594           0 :     sb->SetIncrementToPage(aChange);
    1595           0 :     if (m) {
    1596           0 :       m->ScrollByPage(sb, aChange, nsIScrollbarMediator::ENABLE_SNAP);
    1597           0 :       return;
    1598             :     }
    1599             :   }
    1600           0 :   PageUpDown(aChange);
    1601             : }
    1602             : 
    1603             : float
    1604           0 : nsSliderFrame::GetThumbRatio() const
    1605             : {
    1606             :   // mRatio is in thumb app units per scrolled css pixels. Convert it to a
    1607             :   // ratio of the thumb's CSS pixels per scrolled CSS pixels. (Note the thumb
    1608             :   // is in the scrollframe's parent's space whereas the scrolled CSS pixels
    1609             :   // are in the scrollframe's space).
    1610           0 :   return mRatio / mozilla::AppUnitsPerCSSPixel();
    1611             : }
    1612             : 
    1613             : void
    1614           0 : nsSliderFrame::AsyncScrollbarDragRejected()
    1615             : {
    1616           0 :   mScrollingWithAPZ = false;
    1617             :   // Only suppress the displayport if we're still dragging the thumb.
    1618             :   // Otherwise, no one will unsuppress it.
    1619           0 :   if (isDraggingThumb()) {
    1620           0 :     SuppressDisplayport();
    1621             :   }
    1622           0 : }
    1623             : 
    1624             : void
    1625           0 : nsSliderFrame::SuppressDisplayport()
    1626             : {
    1627           0 :   if (!mSuppressionActive) {
    1628           0 :     MOZ_ASSERT(PresContext()->PresShell());
    1629           0 :     APZCCallbackHelper::SuppressDisplayport(true, PresContext()->PresShell());
    1630           0 :     mSuppressionActive = true;
    1631             :   }
    1632           0 : }
    1633             : 
    1634             : void
    1635           0 : nsSliderFrame::UnsuppressDisplayport()
    1636             : {
    1637           0 :   if (mSuppressionActive) {
    1638           0 :     MOZ_ASSERT(PresContext()->PresShell());
    1639           0 :     APZCCallbackHelper::SuppressDisplayport(false, PresContext()->PresShell());
    1640           0 :     mSuppressionActive = false;
    1641             :   }
    1642           0 : }
    1643             : 
    1644             : bool
    1645           0 : nsSliderFrame::OnlySystemGroupDispatch(EventMessage aMessage) const
    1646             : {
    1647             :   // If we are in a native anonymous subtree, do not dispatch mouse-move events
    1648             :   // targeted at this slider frame to web content. This matches the behaviour
    1649             :   // of other browsers.
    1650           0 :   return aMessage == eMouseMove && GetContent()->IsInNativeAnonymousSubtree();
    1651             : }
    1652             : 
    1653          29 : NS_IMPL_ISUPPORTS(nsSliderMediator,
    1654             :                   nsIDOMEventListener)

Generated by: LCOV version 1.13