1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Neil Cronin (neil@rackle.com)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsScrollPortView.h"
40 #include "nsIWidget.h"
41 #include "nsIDeviceContext.h"
42 #include "nsGUIEvent.h"
43 #include "nsWidgetsCID.h"
44 #include "nsViewsCID.h"
45 #include "nsIScrollableView.h"
46 #include "nsILookAndFeel.h"
47 #include "nsISupportsArray.h"
48 #include "nsIScrollPositionListener.h"
49 #include "nsIRegion.h"
50 #include "nsViewManager.h"
51 #include "nsIPrefBranch.h"
52 #include "nsIPrefService.h"
54 #include "nsServiceManagerUtils.h"
58 static NS_DEFINE_IID(kWidgetCID
, NS_CHILD_CID
);
60 #define SMOOTH_SCROLL_MSECS_PER_FRAME 10
61 #define SMOOTH_SCROLL_FRAMES 10
63 #define SMOOTH_SCROLL_PREF_NAME "general.smoothScroll"
69 if (mScrollAnimationTimer
) mScrollAnimationTimer
->Cancel();
72 nsCOMPtr
<nsITimer
> mScrollAnimationTimer
;
73 PRInt32 mVelocities
[SMOOTH_SCROLL_FRAMES
*2];
75 nscoord mDestinationX
;
76 nscoord mDestinationY
;
79 nsScrollPortView::nsScrollPortView(nsViewManager
* aViewManager
)
80 : nsView(aViewManager
)
82 mOffsetX
= mOffsetY
= 0;
83 nsCOMPtr
<nsIDeviceContext
> dev
;
84 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
85 mLineHeight
= dev
->AppUnitsPerInch() / 6; // 12 pt
88 mSmoothScroll
= nsnull
;
91 nsScrollPortView::~nsScrollPortView()
93 if (nsnull
!= mListeners
) {
95 NS_RELEASE(mListeners
);
98 if (nsnull
!= mViewManager
) {
99 nsIScrollableView
* scrollingView
;
100 mViewManager
->GetRootScrollableView(&scrollingView
);
101 if ((nsnull
!= scrollingView
) && (this == scrollingView
)) {
102 mViewManager
->SetRootScrollableView(nsnull
);
106 delete mSmoothScroll
;
109 nsresult
nsScrollPortView::QueryInterface(const nsIID
& aIID
, void** aInstancePtr
)
111 if (nsnull
== aInstancePtr
) {
112 return NS_ERROR_NULL_POINTER
;
114 *aInstancePtr
= nsnull
;
115 if (aIID
.Equals(NS_GET_IID(nsIScrollableView
))) {
116 *aInstancePtr
= (void*)(nsIScrollableView
*)this;
120 return nsView::QueryInterface(aIID
, aInstancePtr
);
123 NS_IMETHODIMP_(nsIView
*) nsScrollPortView::View()
128 NS_IMETHODIMP
nsScrollPortView::AddScrollPositionListener(nsIScrollPositionListener
* aListener
)
130 if (nsnull
== mListeners
) {
131 nsresult rv
= NS_NewISupportsArray(&mListeners
);
135 return mListeners
->AppendElement(aListener
);
138 NS_IMETHODIMP
nsScrollPortView::RemoveScrollPositionListener(nsIScrollPositionListener
* aListener
)
140 if (nsnull
!= mListeners
) {
141 return mListeners
->RemoveElement(aListener
);
143 return NS_ERROR_FAILURE
;
146 NS_IMETHODIMP
nsScrollPortView::CreateScrollControls(nsNativeWidget aNative
)
148 nsWidgetInitData initData
;
149 initData
.clipChildren
= PR_TRUE
;
150 initData
.clipSiblings
= PR_TRUE
;
152 CreateWidget(kWidgetCID
, &initData
,
153 mWindow
? nsnull
: aNative
);
158 NS_IMETHODIMP
nsScrollPortView::GetContainerSize(nscoord
*aWidth
, nscoord
*aHeight
) const
160 if (!aWidth
|| !aHeight
)
161 return NS_ERROR_NULL_POINTER
;
166 nsView
*scrolledView
= GetScrolledView();
169 return NS_ERROR_FAILURE
;
172 scrolledView
->GetDimensions(sz
);
174 *aHeight
= sz
.height
;
178 static void ComputeVelocities(PRInt32 aCurVelocity
, nscoord aCurPos
, nscoord aDstPos
,
179 PRInt32
* aVelocities
, PRInt32 aP2A
) {
180 // scrolling always works in units of whole pixels. So compute velocities
181 // in pixels and then scale them up. This ensures, for example, that
182 // a 1-pixel scroll isn't broken into N frames of 1/N pixels each, each
183 // frame increment being rounded to 0 whole pixels.
184 aCurPos
= NSAppUnitsToIntPixels(aCurPos
, aP2A
);
185 aDstPos
= NSAppUnitsToIntPixels(aDstPos
, aP2A
);
188 PRInt32 direction
= (aCurPos
< aDstPos
? 1 : -1);
189 PRInt32 absDelta
= (aDstPos
- aCurPos
)*direction
;
190 PRInt32 baseVelocity
= absDelta
/SMOOTH_SCROLL_FRAMES
;
192 for (i
= 0; i
< SMOOTH_SCROLL_FRAMES
; i
++) {
193 aVelocities
[i
*2] = baseVelocity
;
195 nscoord total
= baseVelocity
*SMOOTH_SCROLL_FRAMES
;
196 for (i
= 0; i
< SMOOTH_SCROLL_FRAMES
; i
++) {
197 if (total
< absDelta
) {
202 NS_ASSERTION(total
== absDelta
, "Invalid velocity sum");
204 PRInt32 scale
= NSIntPixelsToAppUnits(direction
, aP2A
);
205 for (i
= 0; i
< SMOOTH_SCROLL_FRAMES
; i
++) {
206 aVelocities
[i
*2] *= scale
;
210 static nsresult
ClampScrollValues(nscoord
& aX
, nscoord
& aY
, nsScrollPortView
* aThis
) {
211 // make sure the new position in in bounds
212 nsView
* scrolledView
= aThis
->GetScrolledView();
213 if (!scrolledView
) return NS_ERROR_FAILURE
;
216 scrolledView
->GetDimensions(scrolledRect
);
219 aThis
->GetDimensions(portSize
);
221 nscoord maxX
= scrolledRect
.XMost() - portSize
.width
;
222 nscoord maxY
= scrolledRect
.YMost() - portSize
.height
;
230 if (aX
< scrolledRect
.x
)
233 if (aY
< scrolledRect
.y
)
240 * this method wraps calls to ScrollToImpl(), either in one shot or incrementally,
241 * based on the setting of the smooth scroll pref
243 NS_IMETHODIMP
nsScrollPortView::ScrollTo(nscoord aDestinationX
, nscoord aDestinationY
,
244 PRUint32 aUpdateFlags
)
246 // do nothing if the we aren't scrolling.
247 if (aDestinationX
== mOffsetX
&& aDestinationY
== mOffsetY
) {
248 // kill any in-progress smooth scroll
249 delete mSmoothScroll
;
250 mSmoothScroll
= nsnull
;
254 if ((aUpdateFlags
& NS_VMREFRESH_SMOOTHSCROLL
) == 0
255 || !IsSmoothScrollingEnabled()) {
256 // Smooth scrolling is not allowed, so we'll kill any existing smooth-scrolling process
257 // and do an instant scroll
258 delete mSmoothScroll
;
259 mSmoothScroll
= nsnull
;
260 return ScrollToImpl(aDestinationX
, aDestinationY
, aUpdateFlags
);
263 PRInt32 currentVelocityX
;
264 PRInt32 currentVelocityY
;
267 currentVelocityX
= mSmoothScroll
->mVelocities
[mSmoothScroll
->mFrameIndex
*2];
268 currentVelocityY
= mSmoothScroll
->mVelocities
[mSmoothScroll
->mFrameIndex
*2 + 1];
270 currentVelocityX
= 0;
271 currentVelocityY
= 0;
273 mSmoothScroll
= new SmoothScroll
;
275 mSmoothScroll
->mScrollAnimationTimer
= do_CreateInstance("@mozilla.org/timer;1");
276 if (!mSmoothScroll
->mScrollAnimationTimer
) {
277 delete mSmoothScroll
;
278 mSmoothScroll
= nsnull
;
281 if (!mSmoothScroll
) {
282 // some allocation failed. Scroll the normal way.
283 return ScrollToImpl(aDestinationX
, aDestinationY
, aUpdateFlags
);
285 mSmoothScroll
->mScrollAnimationTimer
->InitWithFuncCallback(
286 SmoothScrollAnimationCallback
, this, SMOOTH_SCROLL_MSECS_PER_FRAME
,
287 nsITimer::TYPE_REPEATING_PRECISE
);
288 mSmoothScroll
->mDestinationX
= mOffsetX
;
289 mSmoothScroll
->mDestinationY
= mOffsetY
;
292 // need to store these so we know when to stop scrolling
293 // Treat the desired scroll destination as an offset
294 // relative to the current position. This makes things
295 // work when someone starts a smooth scroll
296 // while an existing smooth scroll has not yet been
298 mSmoothScroll
->mDestinationX
+= aDestinationX
- mOffsetX
;
299 mSmoothScroll
->mDestinationY
+= aDestinationY
- mOffsetY
;
300 mSmoothScroll
->mFrameIndex
= 0;
301 ClampScrollValues(mSmoothScroll
->mDestinationX
, mSmoothScroll
->mDestinationY
, this);
303 nsCOMPtr
<nsIDeviceContext
> dev
;
304 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
305 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
307 // compute velocity vectors
308 ComputeVelocities(currentVelocityX
, mOffsetX
,
309 mSmoothScroll
->mDestinationX
, mSmoothScroll
->mVelocities
,
311 ComputeVelocities(currentVelocityY
, mOffsetY
,
312 mSmoothScroll
->mDestinationY
, mSmoothScroll
->mVelocities
+ 1,
318 static void AdjustChildWidgets(nsView
*aView
,
319 nsPoint aWidgetToParentViewOrigin
, PRInt32 aP2A
, PRBool aInvalidate
)
321 if (aView
->HasWidget()) {
322 nsIWidget
* widget
= aView
->GetWidget();
324 widget
->GetWindowType(type
);
325 if (type
!= eWindowType_popup
) {
326 nsRect bounds
= aView
->GetBounds();
327 nsPoint widgetOrigin
= aWidgetToParentViewOrigin
328 + nsPoint(bounds
.x
, bounds
.y
);
329 widget
->Move(NSAppUnitsToIntPixels(widgetOrigin
.x
, aP2A
),
330 NSAppUnitsToIntPixels(widgetOrigin
.y
, aP2A
));
332 // Force the widget and everything in it to repaint. We can't
333 // just use Invalidate because the widget might have child
334 // widgets and they wouldn't get updated. We can't call
335 // UpdateView(aView) because the area to be repainted might be
336 // outside aView's clipped bounds. This isn't the greatest way
337 // to achieve this, perhaps, but it works.
338 widget
->Show(PR_FALSE
);
339 widget
->Show(PR_TRUE
);
343 // Don't recurse if the view haLs a widget, because we adjusted the view's
344 // widget position, and its child widgets are relative to its positon
345 nsPoint widgetToViewOrigin
= aWidgetToParentViewOrigin
346 + aView
->GetPosition();
348 for (nsView
* kid
= aView
->GetFirstChild(); kid
; kid
= kid
->GetNextSibling())
350 AdjustChildWidgets(kid
, widgetToViewOrigin
, aP2A
, aInvalidate
);
356 NS_IMETHODIMP
nsScrollPortView::SetScrolledView(nsIView
*aScrolledView
)
358 NS_ASSERTION(GetFirstChild() == nsnull
|| GetFirstChild()->GetNextSibling() == nsnull
,
359 "Error scroll port has too many children");
361 // if there is already a child so remove it
362 if (GetFirstChild() != nsnull
)
364 mViewManager
->RemoveChild(GetFirstChild());
367 return mViewManager
->InsertChild(this, aScrolledView
, 0);
370 NS_IMETHODIMP
nsScrollPortView::GetScrolledView(nsIView
*&aScrolledView
) const
372 aScrolledView
= GetScrolledView();
376 NS_IMETHODIMP
nsScrollPortView::GetScrollPosition(nscoord
&aX
, nscoord
&aY
) const
384 NS_IMETHODIMP
nsScrollPortView::SetScrollProperties(PRUint32 aProperties
)
386 mScrollProperties
= aProperties
;
390 NS_IMETHODIMP
nsScrollPortView::GetScrollProperties(PRUint32
*aProperties
)
392 *aProperties
= mScrollProperties
;
396 NS_IMETHODIMP
nsScrollPortView::SetLineHeight(nscoord aHeight
)
398 mLineHeight
= aHeight
;
402 NS_IMETHODIMP
nsScrollPortView::GetLineHeight(nscoord
*aHeight
)
404 *aHeight
= mLineHeight
;
408 NS_IMETHODIMP
nsScrollPortView::ScrollByLines(PRInt32 aNumLinesX
, PRInt32 aNumLinesY
)
410 nscoord dx
= mLineHeight
*aNumLinesX
;
411 nscoord dy
= mLineHeight
*aNumLinesY
;
413 return ScrollTo(mOffsetX
+ dx
, mOffsetY
+ dy
, NS_VMREFRESH_SMOOTHSCROLL
);
416 NS_IMETHODIMP
nsScrollPortView::GetPageScrollDistances(nsSize
*aDistances
)
421 // The page increment is the size of the page, minus the smaller of
422 // 10% of the size or 2 lines.
423 aDistances
->width
= size
.width
- PR_MIN(size
.width
/ 10, 2 * mLineHeight
);
424 aDistances
->height
= size
.height
- PR_MIN(size
.height
/ 10, 2 * mLineHeight
);
429 NS_IMETHODIMP
nsScrollPortView::ScrollByPages(PRInt32 aNumPagesX
, PRInt32 aNumPagesY
)
432 GetPageScrollDistances(&delta
);
434 // put in the number of pages.
435 delta
.width
*= aNumPagesX
;
436 delta
.height
*= aNumPagesY
;
438 return ScrollTo(mOffsetX
+ delta
.width
, mOffsetY
+ delta
.height
,
439 NS_VMREFRESH_SMOOTHSCROLL
);
442 NS_IMETHODIMP
nsScrollPortView::ScrollByWhole(PRBool aTop
)
448 nsView
* scrolledView
= GetScrolledView();
449 scrolledView
->GetDimensions(scrolledSize
);
450 newPos
= scrolledSize
.height
;
453 ScrollTo(mOffsetX
, newPos
, 0);
458 NS_IMETHODIMP
nsScrollPortView::ScrollByPixels(PRInt32 aNumPixelsX
,
461 nsCOMPtr
<nsIDeviceContext
> dev
;
462 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
463 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
465 nscoord dx
= NSIntPixelsToAppUnits(aNumPixelsX
, p2a
);
466 nscoord dy
= NSIntPixelsToAppUnits(aNumPixelsY
, p2a
);
468 return ScrollTo(mOffsetX
+ dx
, mOffsetY
+ dy
, 0);
471 NS_IMETHODIMP
nsScrollPortView::CanScroll(PRBool aHorizontal
,
475 nscoord offset
= aHorizontal
? mOffsetX
: mOffsetY
;
477 nsView
* scrolledView
= GetScrolledView();
480 return NS_ERROR_FAILURE
;
484 scrolledView
->GetDimensions(scrolledRect
);
486 // Can scroll to Top or to Left?
488 aResult
= offset
> (aHorizontal
? scrolledRect
.x
: scrolledRect
.y
);
493 GetDimensions(portSize
);
495 nsCOMPtr
<nsIDeviceContext
> dev
;
496 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
497 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
501 max
= scrolledRect
.XMost() - portSize
.width
;
503 nscoord maxPx
= NSAppUnitsToIntPixels(max
, p2a
);
504 max
= NSIntPixelsToAppUnits(maxPx
, p2a
);
506 max
= scrolledRect
.YMost() - portSize
.height
;
508 nscoord maxPx
= NSAppUnitsToIntPixels(max
, p2a
);
509 max
= NSIntPixelsToAppUnits(maxPx
, p2a
);
512 // Can scroll to Bottom or to Right?
513 aResult
= (offset
< max
) ? PR_TRUE
: PR_FALSE
;
518 void nsScrollPortView::Scroll(nsView
*aScrolledView
, nsPoint aTwipsDelta
, nsPoint aPixDelta
,
521 if (aTwipsDelta
.x
!= 0 || aTwipsDelta
.y
!= 0)
523 /* If we should invalidate our wrapped view, we should do so at this
526 if (aScrolledView
->NeedsInvalidateFrameOnScroll())
527 GetViewManager()->GetViewObserver()->InvalidateFrameForView(aScrolledView
);
529 nsIWidget
*scrollWidget
= GetWidget();
530 nsRegion updateRegion
;
531 PRBool canBitBlit
= scrollWidget
&&
532 ((mScrollProperties
& NS_SCROLL_PROPERTY_ALWAYS_BLIT
) ||
533 mViewManager
->CanScrollWithBitBlt(aScrolledView
, aTwipsDelta
, &updateRegion
));
536 // We're going to bit-blit. Let the viewmanager know so it can
537 // adjust dirty regions appropriately.
538 mViewManager
->WillBitBlit(this, aTwipsDelta
);
543 NS_ASSERTION(!canBitBlit
, "Someone screwed up");
544 nsPoint offsetToWidget
;
545 GetNearestWidget(&offsetToWidget
);
546 // We're moving the child widgets because we are scrolling. But
547 // the child widgets may stick outside our bounds, so their area
548 // may include area that's not supposed to be scrolled. We need
549 // to invalidate to ensure that any such area is properly
550 // repainted back to the right rendering.
551 AdjustChildWidgets(aScrolledView
, offsetToWidget
, aP2A
, PR_TRUE
);
552 // If we don't have a scroll widget then we must just update.
553 // We should call this after fixing up the widget positions to be
554 // consistent with the view hierarchy.
555 mViewManager
->UpdateView(this, NS_VMREFRESH_DEFERRED
);
556 } else if (!canBitBlit
) {
557 // We can't blit for some reason.
558 // Just update the view and adjust widgets
559 // Recall that our widget's origin is at our bounds' top-left
560 nsRect
bounds(GetBounds());
561 nsPoint
topLeft(bounds
.x
, bounds
.y
);
562 AdjustChildWidgets(aScrolledView
,
563 GetPosition() - topLeft
, aP2A
, PR_FALSE
);
564 // We should call this after fixing up the widget positions to be
565 // consistent with the view hierarchy.
566 mViewManager
->UpdateView(this, NS_VMREFRESH_DEFERRED
);
567 } else { // if we can blit and have a scrollwidget then scroll.
568 nsRect
* toScrollPtr
= nsnull
;
572 if (!updateRegion
.IsEmpty()) {
573 nsRegion regionToScroll
;
574 regionToScroll
.Sub(nsRect(nsPoint(0,0), GetBounds().Size()),
576 nsRegionRectIterator
iter(regionToScroll
);
577 nsRect
biggestRect(0,0,0,0);
579 for (r
= iter
.Next(); r
; r
= iter
.Next()) {
580 if (r
->width
*r
->height
> biggestRect
.width
*biggestRect
.height
) {
584 toScrollPtr
= &toScroll
;
585 biggestRect
.ScaleRoundIn(1.0/aP2A
);
586 toScroll
= biggestRect
;
588 regionToScroll
.Sub(regionToScroll
, biggestRect
);
589 updateRegion
.Or(updateRegion
, regionToScroll
);
593 // Scroll the contents of the widget by the specified amount, and scroll
595 scrollWidget
->Scroll(aPixDelta
.x
, aPixDelta
.y
, toScrollPtr
);
596 mViewManager
->UpdateViewAfterScroll(this, updateRegion
);
601 NS_IMETHODIMP
nsScrollPortView::ScrollToImpl(nscoord aX
, nscoord aY
, PRUint32 aUpdateFlags
)
603 PRInt32 dxPx
= 0, dyPx
= 0;
606 nsCOMPtr
<nsIDeviceContext
> dev
;
607 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
608 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
610 // Update the scrolled view's position
611 nsresult rv
= ClampScrollValues(aX
, aY
, this);
616 PRInt32 xPixels
= NSAppUnitsToIntPixels(aX
, p2a
);
617 PRInt32 yPixels
= NSAppUnitsToIntPixels(aY
, p2a
);
619 aX
= NSIntPixelsToAppUnits(xPixels
, p2a
);
620 aY
= NSIntPixelsToAppUnits(yPixels
, p2a
);
622 // do nothing if the we aren't scrolling.
623 // this needs to be rechecked because of the clamping and
625 if (aX
== mOffsetX
&& aY
== mOffsetY
) {
629 // figure out the diff by comparing old pos to new
630 dxPx
= NSAppUnitsToIntPixels(mOffsetX
, p2a
) - xPixels
;
631 dyPx
= NSAppUnitsToIntPixels(mOffsetY
, p2a
) - yPixels
;
633 // notify the listeners.
634 PRUint32 listenerCount
;
635 const nsIID
& kScrollPositionListenerIID
= NS_GET_IID(nsIScrollPositionListener
);
636 nsIScrollPositionListener
* listener
;
637 if (nsnull
!= mListeners
) {
638 if (NS_SUCCEEDED(mListeners
->Count(&listenerCount
))) {
639 for (PRUint32 i
= 0; i
< listenerCount
; i
++) {
640 if (NS_SUCCEEDED(mListeners
->QueryElementAt(i
, kScrollPositionListenerIID
, (void**)&listener
))) {
641 listener
->ScrollPositionWillChange(this, aX
, aY
);
642 NS_RELEASE(listener
);
648 nsView
* scrolledView
= GetScrolledView();
649 if (!scrolledView
) return NS_ERROR_FAILURE
;
651 // move the scrolled view to the new location
652 // Note that child widgets may be scrolled by the native widget scrolling,
653 // so don't update their positions
654 scrolledView
->SetPositionIgnoringChildWidgets(-aX
, -aY
);
656 // notify the listeners.
657 if (nsnull
!= mListeners
) {
658 if (NS_SUCCEEDED(mListeners
->Count(&listenerCount
))) {
659 for (PRUint32 i
= 0; i
< listenerCount
; i
++) {
660 if (NS_SUCCEEDED(mListeners
->QueryElementAt(i
, kScrollPositionListenerIID
, (void**)&listener
))) {
661 listener
->ViewPositionDidChange(this);
662 NS_RELEASE(listener
);
668 nsPoint
twipsDelta(aX
- mOffsetX
, aY
- mOffsetY
);
670 // store the new position
674 Scroll(scrolledView
, twipsDelta
, nsPoint(dxPx
, dyPx
), p2a
);
676 mViewManager
->SynthesizeMouseMove(PR_TRUE
);
678 // notify the listeners.
679 if (nsnull
!= mListeners
) {
680 if (NS_SUCCEEDED(mListeners
->Count(&listenerCount
))) {
681 for (PRUint32 i
= 0; i
< listenerCount
; i
++) {
682 if (NS_SUCCEEDED(mListeners
->QueryElementAt(i
, kScrollPositionListenerIID
, (void**)&listener
))) {
683 listener
->ScrollPositionDidChange(this, aX
, aY
);
684 NS_RELEASE(listener
);
693 /************************
695 * smooth scrolling methods
697 ***********************/
699 PRBool
nsScrollPortView::IsSmoothScrollingEnabled() {
700 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
703 nsresult rv
= prefs
->GetBoolPref(SMOOTH_SCROLL_PREF_NAME
, &enabled
);
704 if (NS_SUCCEEDED(rv
)) {
712 * Callback function from timer used in nsScrollPortView::DoSmoothScroll
713 * this cleans up the target coordinates and incrementally calls
714 * nsScrollPortView::ScrollTo
717 nsScrollPortView::SmoothScrollAnimationCallback (nsITimer
*aTimer
, void* anInstance
)
719 nsScrollPortView
* self
= static_cast<nsScrollPortView
*>(anInstance
);
721 self
->IncrementalScroll();
726 * manages data members and calls to ScrollTo from the (static) SmoothScrollAnimationCallback method
729 nsScrollPortView::IncrementalScroll()
731 if (!mSmoothScroll
) {
735 if (mSmoothScroll
->mFrameIndex
< SMOOTH_SCROLL_FRAMES
) {
736 ScrollToImpl(mOffsetX
+ mSmoothScroll
->mVelocities
[mSmoothScroll
->mFrameIndex
*2],
737 mOffsetY
+ mSmoothScroll
->mVelocities
[mSmoothScroll
->mFrameIndex
*2 + 1],
739 mSmoothScroll
->mFrameIndex
++;
741 delete mSmoothScroll
;
742 mSmoothScroll
= nsnull
;