diff --git a/layout/xul/nsIScrollbarMediator.h b/layout/xul/nsIScrollbarMediator.h index 8733416666be..15c2c73fd9a7 100644 --- a/layout/xul/nsIScrollbarMediator.h +++ b/layout/xul/nsIScrollbarMediator.h @@ -7,6 +7,7 @@ #define nsIScrollbarMediator_h___ #include "nsQueryFrame.h" +#include "nsCoord.h" class nsScrollbarFrame; @@ -15,11 +16,35 @@ class nsIScrollbarMediator public: NS_DECL_QUERYFRAME_TARGET(nsIScrollbarMediator) - // The aScrollbar argument denotes the scrollbar that's firing the notification. - NS_IMETHOD PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t& aNewIndex) = 0; - NS_IMETHOD ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t aNewIndex) = 0; + /** + * The aScrollbar argument denotes the scrollbar that's firing the notification. + * aScrollbar is never null. + * aDirection is either -1, 0, or 1. + */ - NS_IMETHOD VisibilityChanged(bool aVisible) = 0; + /** + * One of the following three methods is called when the scrollbar's button is + * clicked. + * @note These methods might destroy the frame, pres shell, and other objects. + */ + virtual void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection) = 0; + virtual void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection) = 0; + virtual void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection) = 0; + /** + * RepeatButtonScroll is called when the scrollbar's button is held down. When the + * button is first clicked the increment is set; RepeatButtonScroll adds this + * increment to the current position. + * @note This method might destroy the frame, pres shell, and other objects. + */ + virtual void RepeatButtonScroll(nsScrollbarFrame* aScrollbar) = 0; + /** + * aOldPos and aNewPos are scroll positions. + * @note This method might destroy the frame, pres shell, and other objects. + */ + virtual void ThumbMoved(nsScrollbarFrame* aScrollbar, + nscoord aOldPos, + nscoord aNewPos) = 0; + virtual void VisibilityChanged(bool aVisible) = 0; }; #endif diff --git a/layout/xul/nsListBoxBodyFrame.cpp b/layout/xul/nsListBoxBodyFrame.cpp index f197a257de2e..c61341b2944d 100644 --- a/layout/xul/nsListBoxBodyFrame.cpp +++ b/layout/xul/nsListBoxBodyFrame.cpp @@ -324,16 +324,56 @@ nsListBoxBodyFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState) ///////////// nsIScrollbarMediator /////////////// -NS_IMETHODIMP -nsListBoxBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t& aNewIndex) +void +nsListBoxBodyFrame::ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection) +{ + MOZ_ASSERT(aScrollbar != nullptr); + UpdateIndex(aDirection); + aScrollbar->SetIncrementToPage(aDirection); + aScrollbar->MoveToNewPosition(); +} + +void +nsListBoxBodyFrame::ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection) +{ + MOZ_ASSERT(aScrollbar != nullptr); + UpdateIndex(aDirection); + aScrollbar->SetIncrementToWhole(aDirection); + aScrollbar->MoveToNewPosition(); +} + +void +nsListBoxBodyFrame::ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection) +{ + MOZ_ASSERT(aScrollbar != nullptr); + UpdateIndex(aDirection); + aScrollbar->SetIncrementToLine(aDirection); + aScrollbar->MoveToNewPosition(); +} + +void +nsListBoxBodyFrame::RepeatButtonScroll(nsScrollbarFrame* aScrollbar) +{ + int32_t increment = aScrollbar->GetIncrement(); + if (increment < 0) { + UpdateIndex(-1); + } else if (increment > 0) { + UpdateIndex(1); + } + aScrollbar->MoveToNewPosition(); +} + +void +nsListBoxBodyFrame::ThumbMoved(nsScrollbarFrame* aScrollbar, + nscoord aOldPos, + nscoord aNewPos) { if (mScrolling || mRowHeight == 0) - return NS_OK; + return; - nscoord oldTwipIndex, newTwipIndex; + nscoord oldTwipIndex; oldTwipIndex = mCurrentIndex*mRowHeight; - newTwipIndex = nsPresContext::CSSPixelsToAppUnits(aNewIndex); - int32_t twipDelta = newTwipIndex > oldTwipIndex ? newTwipIndex - oldTwipIndex : oldTwipIndex - newTwipIndex; + int32_t twipDelta = aNewPos > oldTwipIndex ? aNewPos - oldTwipIndex : oldTwipIndex - aNewPos; int32_t rowDelta = twipDelta / mRowHeight; int32_t remainder = twipDelta % mRowHeight; @@ -341,11 +381,11 @@ nsListBoxBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIn rowDelta++; if (rowDelta == 0) - return NS_OK; + return; // update the position to be row based. - int32_t newIndex = newTwipIndex > oldTwipIndex ? mCurrentIndex + rowDelta : mCurrentIndex - rowDelta; + int32_t newIndex = aNewPos > oldTwipIndex ? mCurrentIndex + rowDelta : mCurrentIndex - rowDelta; //aNewIndex = newIndex*mRowHeight/mOnePixel; nsListScrollSmoother* smoother = GetSmoother(); @@ -356,11 +396,11 @@ nsListBoxBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIn smoother->Stop(); - smoother->mDelta = newTwipIndex > oldTwipIndex ? rowDelta : -rowDelta; + smoother->mDelta = aNewPos > oldTwipIndex ? rowDelta : -rowDelta; smoother->Start(); - return NS_OK; + return; } smoother->Stop(); @@ -370,17 +410,16 @@ nsListBoxBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIn if (mCurrentIndex < 0) { mCurrentIndex = 0; - return NS_OK; + return; } - - return InternalPositionChanged(newTwipIndex < oldTwipIndex, rowDelta); + InternalPositionChanged(aNewPos < oldTwipIndex, rowDelta); } -NS_IMETHODIMP +void nsListBoxBodyFrame::VisibilityChanged(bool aVisible) { if (mRowHeight == 0) - return NS_OK; + return; int32_t lastPageTopRow = GetRowCount() - (GetAvailableHeight() / mRowHeight); if (lastPageTopRow < 0) @@ -390,27 +429,23 @@ nsListBoxBodyFrame::VisibilityChanged(bool aVisible) mCurrentIndex = lastPageTopRow; InternalPositionChanged(true, delta); } - - return NS_OK; } -NS_IMETHODIMP -nsListBoxBodyFrame::ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t aNewIndex) +void +nsListBoxBodyFrame::UpdateIndex(int32_t aDirection) { - if (aOldIndex == aNewIndex) - return NS_OK; - if (aNewIndex < aOldIndex) + if (aDirection == 0) + return; + if (aDirection < 0) mCurrentIndex--; else mCurrentIndex++; if (mCurrentIndex < 0) { mCurrentIndex = 0; - return NS_OK; + return; } - InternalPositionChanged(aNewIndex < aOldIndex, 1); - - return NS_OK; + InternalPositionChanged(aDirection < 0, 1); } - + ///////////// nsIReflowCallback /////////////// bool diff --git a/layout/xul/nsListBoxBodyFrame.h b/layout/xul/nsListBoxBodyFrame.h index 5016dfa3e4ca..d0e726b453d1 100644 --- a/layout/xul/nsListBoxBodyFrame.h +++ b/layout/xul/nsListBoxBodyFrame.h @@ -56,9 +56,15 @@ public: virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType) MOZ_OVERRIDE; // nsIScrollbarMediator - NS_IMETHOD PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t& aNewIndex) MOZ_OVERRIDE; - NS_IMETHOD ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE; - NS_IMETHOD VisibilityChanged(bool aVisible) MOZ_OVERRIDE; + virtual void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection) MOZ_OVERRIDE; + virtual void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection) MOZ_OVERRIDE; + virtual void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection) MOZ_OVERRIDE; + virtual void RepeatButtonScroll(nsScrollbarFrame* aScrollbar) MOZ_OVERRIDE; + virtual void ThumbMoved(nsScrollbarFrame* aScrollbar, + int32_t aOldPos, + int32_t aNewPos) MOZ_OVERRIDE; + virtual void VisibilityChanged(bool aVisible) MOZ_OVERRIDE; + // nsIReflowCallback virtual bool ReflowFinished() MOZ_OVERRIDE; @@ -89,6 +95,7 @@ public: nsresult DoInternalPositionChanged(bool aUp, int32_t aDelta); nsListScrollSmoother* GetSmoother(); void VerticalScroll(int32_t aDelta); + void UpdateIndex(int32_t aDirection); // frames nsIFrame* GetFirstFrame(); diff --git a/layout/xul/nsScrollbarButtonFrame.cpp b/layout/xul/nsScrollbarButtonFrame.cpp index 05aa9b665cac..12cbfff48908 100644 --- a/layout/xul/nsScrollbarButtonFrame.cpp +++ b/layout/xul/nsScrollbarButtonFrame.cpp @@ -78,7 +78,6 @@ nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext, return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } - bool nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, @@ -109,10 +108,7 @@ nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext, if (scrollbar == nullptr) return false; - - // get the scrollbars content node - nsIContent* content = scrollbar->GetContent(); - + static nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::increment, &nsGkAtoms::decrement, nullptr }; @@ -120,51 +116,65 @@ nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext, nsGkAtoms::type, strings, eCaseMatters); int32_t direction; - if (index == 0) + if (index == 0) direction = 1; else if (index == 1) direction = -1; else return false; - // Whether or not to repeat the click action. - bool repeat = true; - // Use smooth scrolling by default. - bool smoothScroll = true; - switch (pressedButtonAction) { - case 0: - mIncrement = direction * nsSliderFrame::GetIncrement(content); - break; - case 1: - mIncrement = direction * nsSliderFrame::GetPageIncrement(content); - break; - case 2: - if (direction == -1) - mIncrement = -nsSliderFrame::GetCurrentPosition(content); - else - mIncrement = nsSliderFrame::GetMaxPosition(content) - - nsSliderFrame::GetCurrentPosition(content); - // Don't repeat or use smooth scrolling if scrolling to beginning or end - // of a page. - repeat = smoothScroll = false; - break; - case 3: - default: - // We were told to ignore this click, or someone assigned a non-standard - // value to the button's action. - return false; - } + bool repeat = pressedButtonAction != 2; // set this attribute so we can style it later nsWeakFrame weakFrame(this); mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true); nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED); - if (weakFrame.IsAlive()) { - DoButtonAction(smoothScroll); + if (!weakFrame.IsAlive()) { + return false; } - if (repeat) + + nsScrollbarFrame* sb = do_QueryFrame(scrollbar); + if (sb) { + nsIScrollbarMediator* m = sb->GetScrollbarMediator(); + switch (pressedButtonAction) { + case 0: + sb->SetIncrementToLine(direction); + if (m) { + m->ScrollByLine(sb, direction); + } + break; + case 1: + sb->SetIncrementToPage(direction); + if (m) { + m->ScrollByPage(sb, direction); + } + break; + case 2: + sb->SetIncrementToWhole(direction); + if (m) { + m->ScrollByWhole(sb, direction); + } + break; + case 3: + default: + // We were told to ignore this click, or someone assigned a non-standard + // value to the button's action. + return false; + } + if (!weakFrame.IsAlive()) { + return false; + } + if (!m) { + sb->MoveToNewPosition(); + if (!weakFrame.IsAlive()) { + return false; + } + } + } + if (repeat) { StartRepeat(); + } return true; } @@ -182,12 +192,21 @@ nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext, void nsScrollbarButtonFrame::Notify() { - // Since this is only going to get called if we're scrolling a page length - // or a line increment, we will always use smooth scrolling. if (mCursorOnThis || LookAndFeel::GetInt( LookAndFeel::eIntID_ScrollbarButtonAutoRepeatBehavior, 0)) { - DoButtonAction(true); + // get the scrollbar control + nsIFrame* scrollbar; + GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar); + nsScrollbarFrame* sb = do_QueryFrame(scrollbar); + if (sb) { + nsIScrollbarMediator* m = sb->GetScrollbarMediator(); + if (m) { + m->RepeatButtonScroll(sb); + } else { + sb->MoveToNewPosition(); + } + } } } @@ -199,56 +218,6 @@ nsScrollbarButtonFrame::MouseClicked(nsPresContext* aPresContext, //MouseClicked(); } -void -nsScrollbarButtonFrame::DoButtonAction(bool aSmoothScroll) -{ - // get the scrollbar control - nsIFrame* scrollbar; - GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar); - - if (scrollbar == nullptr) - return; - - // get the scrollbars content node - nsCOMPtr content = scrollbar->GetContent(); - - // get the current pos - int32_t curpos = nsSliderFrame::GetCurrentPosition(content); - int32_t oldpos = curpos; - - // get the max pos - int32_t maxpos = nsSliderFrame::GetMaxPosition(content); - - // increment the given amount - if (mIncrement) - curpos += mIncrement; - - // make sure the current position is between the current and max positions - if (curpos < 0) - curpos = 0; - else if (curpos > maxpos) - curpos = maxpos; - - nsScrollbarFrame* sb = do_QueryFrame(scrollbar); - if (sb) { - nsIScrollbarMediator* m = sb->GetScrollbarMediator(); - if (m) { - m->ScrollbarButtonPressed(sb, oldpos, curpos); - return; - } - } - - // set the current position of the slider. - nsAutoString curposStr; - curposStr.AppendInt(curpos); - - if (aSmoothScroll) - content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false); - content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, true); - if (aSmoothScroll) - content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false); -} - nsresult nsScrollbarButtonFrame::GetChildWithTag(nsPresContext* aPresContext, nsIAtom* atom, nsIFrame* start, diff --git a/layout/xul/nsScrollbarButtonFrame.h b/layout/xul/nsScrollbarButtonFrame.h index 7d2bfde3ea51..2a575167e177 100644 --- a/layout/xul/nsScrollbarButtonFrame.h +++ b/layout/xul/nsScrollbarButtonFrame.h @@ -67,7 +67,6 @@ public: protected: virtual void MouseClicked(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent) MOZ_OVERRIDE; - void DoButtonAction(bool aSmoothScroll); void StartRepeat() { nsRepeatService::GetInstance()->Start(Notify, this); @@ -80,7 +79,6 @@ protected: static_cast(aData)->Notify(); } - int32_t mIncrement; bool mCursorOnThis; }; diff --git a/layout/xul/nsScrollbarFrame.cpp b/layout/xul/nsScrollbarFrame.cpp index 5e21d175f6b2..6f70caddb8de 100644 --- a/layout/xul/nsScrollbarFrame.cpp +++ b/layout/xul/nsScrollbarFrame.cpp @@ -11,6 +11,7 @@ // #include "nsScrollbarFrame.h" +#include "nsSliderFrame.h" #include "nsScrollbarButtonFrame.h" #include "nsGkAtoms.h" #include "nsIScrollableFrame.h" @@ -19,6 +20,7 @@ #include "nsThemeConstants.h" #include "nsRenderingContext.h" #include "nsIContent.h" +#include "nsIDOMMutationEvent.h" using namespace mozilla; @@ -186,3 +188,103 @@ nsScrollbarFrame::GetMargin(nsMargin& aMargin) return nsBox::GetMargin(aMargin); } + +void +nsScrollbarFrame::SetIncrementToLine(int32_t aDirection) +{ + // get the scrollbar's content node + nsIContent* content = GetContent(); + mSmoothScroll = true; + mIncrement = aDirection * nsSliderFrame::GetIncrement(content); +} + +void +nsScrollbarFrame::SetIncrementToPage(int32_t aDirection) +{ + // get the scrollbar's content node + nsIContent* content = GetContent(); + mSmoothScroll = true; + mIncrement = aDirection * nsSliderFrame::GetPageIncrement(content); +} + +void +nsScrollbarFrame::SetIncrementToWhole(int32_t aDirection) +{ + // get the scrollbar's content node + nsIContent* content = GetContent(); + if (aDirection == -1) + mIncrement = -nsSliderFrame::GetCurrentPosition(content); + else + mIncrement = nsSliderFrame::GetMaxPosition(content) - + nsSliderFrame::GetCurrentPosition(content); + // Don't repeat or use smooth scrolling if scrolling to beginning or end + // of a page. + mSmoothScroll = false; +} + +int32_t +nsScrollbarFrame::MoveToNewPosition() +{ + // get the scrollbar's content node + nsCOMPtr content = GetContent(); + + // get the current pos + int32_t curpos = nsSliderFrame::GetCurrentPosition(content); + + // get the max pos + int32_t maxpos = nsSliderFrame::GetMaxPosition(content); + + // increment the given amount + if (mIncrement) { + curpos += mIncrement; + } + + // make sure the current position is between the current and max positions + if (curpos < 0) { + curpos = 0; + } else if (curpos > maxpos) { + curpos = maxpos; + } + + // set the current position of the slider. + nsAutoString curposStr; + curposStr.AppendInt(curpos); + + nsWeakFrame weakFrame(this); + if (mSmoothScroll) { + content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false); + } + content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, false); + // notify the nsScrollbarFrame of the change + AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos, nsIDOMMutationEvent::MODIFICATION); + if (!weakFrame.IsAlive()) { + return curpos; + } + // notify all nsSliderFrames of the change + nsIFrame::ChildListIterator childLists(this); + for (; !childLists.IsDone(); childLists.Next()) { + nsFrameList::Enumerator childFrames(childLists.CurrentList()); + for (; !childFrames.AtEnd(); childFrames.Next()) { + nsIFrame* f = childFrames.get(); + nsSliderFrame* sliderFrame = do_QueryFrame(f); + if (sliderFrame) { + sliderFrame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos, nsIDOMMutationEvent::MODIFICATION); + if (!weakFrame.IsAlive()) { + return curpos; + } + } + } + } + // See if we have appearance information for a theme. + const nsStyleDisplay* disp = StyleDisplay(); + nsPresContext* presContext = PresContext(); + if (disp->mAppearance) { + nsITheme *theme = presContext->GetTheme(); + if (theme && theme->ThemeSupportsWidget(presContext, this, disp->mAppearance)) { + bool repaint; + theme->WidgetStateChanged(this, disp->mAppearance, nsGkAtoms::curpos, &repaint); + } + } + content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false); + return curpos; +} diff --git a/layout/xul/nsScrollbarFrame.h b/layout/xul/nsScrollbarFrame.h index ef260622c141..b6fac307c549 100644 --- a/layout/xul/nsScrollbarFrame.h +++ b/layout/xul/nsScrollbarFrame.h @@ -83,6 +83,25 @@ public: virtual nsresult GetMargin(nsMargin& aMargin) MOZ_OVERRIDE; + /** + * The following three methods set the value of mIncrement when a + * scrollbar button is pressed. + */ + void SetIncrementToLine(int32_t aDirection); + void SetIncrementToPage(int32_t aDirection); + void SetIncrementToWhole(int32_t aDirection); + /** + * MoveToNewPosition() adds mIncrement to the current position and + * updates the curpos attribute. + * @note This method might destroy the frame, pres shell, and other objects. + */ + int32_t MoveToNewPosition(); + int32_t GetIncrement() { return mIncrement; } + +protected: + int32_t mIncrement; // Amount to scroll, in CSSPixels + bool mSmoothScroll; + private: nsCOMPtr mScrollbarMediator; }; // class nsScrollbarFrame diff --git a/layout/xul/nsSliderFrame.cpp b/layout/xul/nsSliderFrame.cpp index 7b9c0f571f18..d430272f8c11 100644 --- a/layout/xul/nsSliderFrame.cpp +++ b/layout/xul/nsSliderFrame.cpp @@ -60,6 +60,10 @@ NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) NS_IMPL_FRAMEARENA_HELPERS(nsSliderFrame) +NS_QUERYFRAME_HEAD(nsSliderFrame) + NS_QUERYFRAME_ENTRY(nsSliderFrame) +NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) + nsSliderFrame::nsSliderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext): nsBoxFrame(aPresShell, aContext), mCurPos(0), @@ -245,19 +249,25 @@ nsSliderFrame::AttributeChanged(int32_t aNameSpaceID, if (current < min || current > max) { - if (current < min || max < min) - current = min; - else if (current > max) - current = max; + int32_t direction = 0; + if (current < min || max < min) { + current = min; + direction = -1; + } else if (current > max) { + current = max; + direction = 1; + } // set the new position and notify observers nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox); if (scrollbarFrame) { nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator(); + scrollbarFrame->SetIncrementToWhole(direction); if (mediator) { - mediator->PositionChanged(scrollbarFrame, GetCurrentPosition(scrollbar), current); + mediator->ScrollByWhole(scrollbarFrame, direction); } } + // 'this' might be destroyed here nsContentUtils::AddScriptRunner( new nsSetAttrRunnable(scrollbar, nsGkAtoms::curpos, current)); @@ -619,10 +629,6 @@ nsSliderFrame::PageUpDown(nscoord change) nsCOMPtr scrollbar; scrollbar = GetContentOfBox(scrollbarBox); - if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, - nsGkAtoms::reverse, eCaseMatters)) - change = -change; - nscoord pageIncrement = GetPageIncrement(scrollbar); int32_t curpos = GetCurrentPosition(scrollbar); int32_t minpos = GetMinPosition(scrollbar); @@ -776,6 +782,7 @@ nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, int32_t aNewPo { nsCOMPtr scrollbar = aScrollbar; nsIFrame* scrollbarBox = GetScrollbar(); + nsWeakFrame weakFrame(this); mUserChanged = true; @@ -784,21 +791,23 @@ nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, int32_t aNewPo // See if we have a mediator. nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator(); if (mediator) { - nsRefPtr context = PresContext(); nsCOMPtr content = GetContent(); - mediator->PositionChanged(scrollbarFrame, GetCurrentPosition(scrollbar), aNewPos); - // 'mediator' might be dangling now... - UpdateAttribute(scrollbar, aNewPos, false, aIsSmooth); - nsIFrame* frame = content->GetPrimaryFrame(); - if (frame && frame->GetType() == nsGkAtoms::sliderFrame) { - static_cast(frame)->CurrentPositionChanged(); + nscoord oldPos = nsPresContext::CSSPixelsToAppUnits(GetCurrentPosition(scrollbar)); + nscoord newPos = nsPresContext::CSSPixelsToAppUnits(aNewPos); + mediator->ThumbMoved(scrollbarFrame, oldPos, newPos); + if (!weakFrame.IsAlive()) { + return; } + CurrentPositionChanged(); mUserChanged = false; return; } } UpdateAttribute(scrollbar, aNewPos, true, aIsSmooth); + if (!weakFrame.IsAlive()) { + return; + } mUserChanged = false; #ifdef DEBUG_SLIDER @@ -1124,7 +1133,8 @@ nsSliderFrame::HandlePress(nsPresContext* aPresContext, mDestinationPoint = eventPoint; #endif StartRepeat(); - PageUpDown(change); + PageScroll(change); + return NS_OK; } @@ -1188,7 +1198,8 @@ nsSliderFrame::EnsureOrient() } -void nsSliderFrame::Notify(void) +void +nsSliderFrame::Notify(void) { bool stop = false; @@ -1225,9 +1236,29 @@ void nsSliderFrame::Notify(void) if (stop) { StopRepeat(); } else { - PageUpDown(mChange); + PageScroll(mChange); } } +void +nsSliderFrame::PageScroll(nscoord aChange) +{ + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, + nsGkAtoms::reverse, eCaseMatters)) { + aChange = -aChange; + } + nsIFrame* scrollbar = GetScrollbar(); + nsScrollbarFrame* sb = do_QueryFrame(scrollbar); + if (sb) { + nsIScrollbarMediator* m = sb->GetScrollbarMediator(); + sb->SetIncrementToPage(aChange); + if (m) { + m->ScrollByPage(sb, aChange); + return; + } + } + PageUpDown(aChange); +} + NS_IMPL_ISUPPORTS(nsSliderMediator, nsIDOMEventListener) diff --git a/layout/xul/nsSliderFrame.h b/layout/xul/nsSliderFrame.h index cd71e0ee28c9..43715b47416e 100644 --- a/layout/xul/nsSliderFrame.h +++ b/layout/xul/nsSliderFrame.h @@ -42,6 +42,8 @@ class nsSliderFrame : public nsBoxFrame { public: NS_DECL_FRAMEARENA_HELPERS + NS_DECL_QUERYFRAME_TARGET(nsSliderFrame) + NS_DECL_QUERYFRAME friend class nsSliderMediator; @@ -161,6 +163,7 @@ private: static void Notify(void* aData) { (static_cast(aData))->Notify(); } + void PageScroll(nscoord aChange); nsPoint mDestinationPoint; nsRefPtr mMediator; diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index 64edae7b3668..a6f8a6a08fff 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -4155,48 +4155,85 @@ nsTreeBodyFrame::ScrollHorzInternal(const ScrollParts& aParts, int32_t aPosition return NS_OK; } -NS_IMETHODIMP -nsTreeBodyFrame::ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t aNewIndex) +void +nsTreeBodyFrame::ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection) +{ + MOZ_ASSERT(aScrollbar != nullptr); + ScrollByPages(aDirection); +} + +void +nsTreeBodyFrame::ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection) +{ + MOZ_ASSERT(aScrollbar != nullptr); + int32_t newIndex = aDirection < 0 ? 0 : mTopRowIndex; + ScrollToRow(newIndex); +} + +void +nsTreeBodyFrame::ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection) +{ + MOZ_ASSERT(aScrollbar != nullptr); + ScrollByLines(aDirection); +} + +void +nsTreeBodyFrame::RepeatButtonScroll(nsScrollbarFrame* aScrollbar) { ScrollParts parts = GetScrollParts(); + int32_t increment = aScrollbar->GetIncrement(); + int32_t direction = 0; + if (increment < 0) { + direction = -1; + } else if (increment > 0) { + direction = 1; + } + bool isHorizontal = aScrollbar->IsHorizontal(); - if (aScrollbar == parts.mVScrollbar) { - if (aNewIndex > aOldIndex) - ScrollToRowInternal(parts, mTopRowIndex+1); - else if (aNewIndex < aOldIndex) - ScrollToRowInternal(parts, mTopRowIndex-1); + nsWeakFrame weakFrame(this); + if (isHorizontal) { + int32_t curpos = aScrollbar->MoveToNewPosition(); + if (weakFrame.IsAlive()) { + ScrollHorzInternal(parts, curpos); + } } else { - nsresult rv = ScrollHorzInternal(parts, aNewIndex); - if (NS_FAILED(rv)) return rv; + ScrollToRowInternal(parts, mTopRowIndex+direction); } - UpdateScrollbars(parts); - - return NS_OK; + if (weakFrame.IsAlive() && mScrollbarActivity) { + mScrollbarActivity->ActivityOccurred(); + } + if (weakFrame.IsAlive()) { + UpdateScrollbars(parts); + } } - -NS_IMETHODIMP -nsTreeBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t& aNewIndex) + +void +nsTreeBodyFrame::ThumbMoved(nsScrollbarFrame* aScrollbar, + nscoord aOldPos, + nscoord aNewPos) { ScrollParts parts = GetScrollParts(); - if (aOldIndex == aNewIndex) - return NS_OK; + if (aOldPos == aNewPos) + return; + + nsWeakFrame weakFrame(this); // Vertical Scrollbar if (parts.mVScrollbar == aScrollbar) { nscoord rh = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight); - - nscoord newrow = aNewIndex/rh; + nscoord newIndex = nsPresContext::AppUnitsToIntCSSPixels(aNewPos); + nscoord newrow = newIndex/rh; ScrollInternal(parts, newrow); // Horizontal Scrollbar } else if (parts.mHScrollbar == aScrollbar) { - nsresult rv = ScrollHorzInternal(parts, aNewIndex); - if (NS_FAILED(rv)) return rv; + int32_t newIndex = nsPresContext::AppUnitsToIntCSSPixels(aNewPos); + ScrollHorzInternal(parts, newIndex); + } + if (weakFrame.IsAlive()) { + UpdateScrollbars(parts); } - - UpdateScrollbars(parts); - return NS_OK; } // The style cache. diff --git a/layout/xul/tree/nsTreeBodyFrame.h b/layout/xul/tree/nsTreeBodyFrame.h index c0ea326064c5..f37bf886322f 100644 --- a/layout/xul/tree/nsTreeBodyFrame.h +++ b/layout/xul/tree/nsTreeBodyFrame.h @@ -134,9 +134,14 @@ public: virtual bool PseudoMatches(nsCSSSelector* aSelector) MOZ_OVERRIDE; // nsIScrollbarMediator - NS_IMETHOD PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t& aNewIndex) MOZ_OVERRIDE; - NS_IMETHOD ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE; - NS_IMETHOD VisibilityChanged(bool aVisible) MOZ_OVERRIDE { Invalidate(); return NS_OK; } + virtual void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection) MOZ_OVERRIDE; + virtual void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection) MOZ_OVERRIDE; + virtual void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection) MOZ_OVERRIDE; + virtual void RepeatButtonScroll(nsScrollbarFrame* aScrollbar) MOZ_OVERRIDE; + virtual void ThumbMoved(nsScrollbarFrame* aScrollbar, + nscoord aOldPos, + nscoord aNewPos) MOZ_OVERRIDE; + virtual void VisibilityChanged(bool aVisible) MOZ_OVERRIDE { Invalidate(); } // nsIScrollbarOwner virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {