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 (mScrollTimer
) mScrollTimer
->Cancel();
72 nsCOMPtr
<nsITimer
> mScrollTimer
;
73 PRInt32 mVelocities
[SMOOTH_SCROLL_FRAMES
*2];
75 PRPackedBool mIsSmoothScroll
;
78 nsScrollPortView::nsScrollPortView(nsViewManager
* aViewManager
)
79 : nsView(aViewManager
)
81 mOffsetX
= mOffsetY
= 0;
82 mDestinationX
= mDestinationY
= 0;
83 nsCOMPtr
<nsIDeviceContext
> dev
;
84 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
85 mLineHeight
= dev
->AppUnitsPerInch() / 6; // 12 pt
88 mAsyncScroll
= 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
);
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
== mDestinationX
&& aDestinationY
== mDestinationY
) {
248 // kill any in-progress smooth scroll
250 mAsyncScroll
= nsnull
;
254 mDestinationX
= aDestinationX
;
255 mDestinationY
= aDestinationY
;
256 ClampScrollValues(mDestinationX
, mDestinationY
, this);
258 if (!(aUpdateFlags
& (NS_VMREFRESH_DEFERRED
| NS_VMREFRESH_SMOOTHSCROLL
))) {
259 // Asynchronous scrolling is not allowed, so we'll kill any existing
260 // async-scrolling process and do an instant scroll
262 mAsyncScroll
= nsnull
;
263 return ScrollToImpl(mDestinationX
, mDestinationY
);
266 PRInt32 currentVelocityX
= 0;
267 PRInt32 currentVelocityY
= 0;
268 PRBool isSmoothScroll
= (aUpdateFlags
& NS_VMREFRESH_SMOOTHSCROLL
) &&
269 IsSmoothScrollingEnabled();
272 if (mAsyncScroll
->mIsSmoothScroll
) {
273 currentVelocityX
= mAsyncScroll
->mVelocities
[mAsyncScroll
->mFrameIndex
*2];
274 currentVelocityY
= mAsyncScroll
->mVelocities
[mAsyncScroll
->mFrameIndex
*2 + 1];
277 mAsyncScroll
= new AsyncScroll
;
279 mAsyncScroll
->mScrollTimer
= do_CreateInstance("@mozilla.org/timer;1");
280 if (!mAsyncScroll
->mScrollTimer
) {
282 mAsyncScroll
= nsnull
;
286 // some allocation failed. Scroll the normal way.
287 return ScrollToImpl(mDestinationX
, mDestinationY
);
289 if (isSmoothScroll
) {
290 mAsyncScroll
->mScrollTimer
->InitWithFuncCallback(
291 AsyncScrollCallback
, this, SMOOTH_SCROLL_MSECS_PER_FRAME
,
292 nsITimer::TYPE_REPEATING_PRECISE
);
294 mAsyncScroll
->mScrollTimer
->InitWithFuncCallback(
295 AsyncScrollCallback
, this, 0, nsITimer::TYPE_ONE_SHOT
);
299 mAsyncScroll
->mFrameIndex
= 0;
300 mAsyncScroll
->mIsSmoothScroll
= isSmoothScroll
;
302 if (isSmoothScroll
) {
303 nsCOMPtr
<nsIDeviceContext
> dev
;
304 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
305 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
307 // compute velocity vectors
308 ComputeVelocities(currentVelocityX
, mOffsetX
, mDestinationX
,
309 mAsyncScroll
->mVelocities
, p2a
);
310 ComputeVelocities(currentVelocityY
, mOffsetY
, mDestinationY
,
311 mAsyncScroll
->mVelocities
+ 1, p2a
);
317 static void AdjustChildWidgets(nsView
*aView
,
318 nsPoint aWidgetToParentViewOrigin
, PRInt32 aP2A
, PRBool aInvalidate
)
320 if (aView
->HasWidget()) {
321 nsIWidget
* widget
= aView
->GetWidget();
323 widget
->GetWindowType(type
);
324 if (type
!= eWindowType_popup
) {
325 nsRect bounds
= aView
->GetBounds();
326 nsPoint widgetOrigin
= aWidgetToParentViewOrigin
327 + nsPoint(bounds
.x
, bounds
.y
);
328 widget
->Move(NSAppUnitsToIntPixels(widgetOrigin
.x
, aP2A
),
329 NSAppUnitsToIntPixels(widgetOrigin
.y
, aP2A
));
331 // Force the widget and everything in it to repaint. We can't
332 // just use Invalidate because the widget might have child
333 // widgets and they wouldn't get updated. We can't call
334 // UpdateView(aView) because the area to be repainted might be
335 // outside aView's clipped bounds. This isn't the greatest way
336 // to achieve this, perhaps, but it works.
337 widget
->Show(PR_FALSE
);
338 widget
->Show(PR_TRUE
);
342 // Don't recurse if the view haLs a widget, because we adjusted the view's
343 // widget position, and its child widgets are relative to its positon
344 nsPoint widgetToViewOrigin
= aWidgetToParentViewOrigin
345 + aView
->GetPosition();
347 for (nsView
* kid
= aView
->GetFirstChild(); kid
; kid
= kid
->GetNextSibling())
349 AdjustChildWidgets(kid
, widgetToViewOrigin
, aP2A
, aInvalidate
);
355 NS_IMETHODIMP
nsScrollPortView::SetScrolledView(nsIView
*aScrolledView
)
357 NS_ASSERTION(GetFirstChild() == nsnull
|| GetFirstChild()->GetNextSibling() == nsnull
,
358 "Error scroll port has too many children");
360 // if there is already a child so remove it
361 if (GetFirstChild() != nsnull
)
363 mViewManager
->RemoveChild(GetFirstChild());
366 return mViewManager
->InsertChild(this, aScrolledView
, 0);
369 NS_IMETHODIMP
nsScrollPortView::GetScrolledView(nsIView
*&aScrolledView
) const
371 aScrolledView
= GetScrolledView();
375 NS_IMETHODIMP
nsScrollPortView::GetScrollPosition(nscoord
&aX
, nscoord
&aY
) const
383 NS_IMETHODIMP
nsScrollPortView::SetScrollProperties(PRUint32 aProperties
)
385 mScrollProperties
= aProperties
;
389 NS_IMETHODIMP
nsScrollPortView::GetScrollProperties(PRUint32
*aProperties
)
391 *aProperties
= mScrollProperties
;
395 NS_IMETHODIMP
nsScrollPortView::SetLineHeight(nscoord aHeight
)
397 mLineHeight
= aHeight
;
401 NS_IMETHODIMP
nsScrollPortView::GetLineHeight(nscoord
*aHeight
)
403 *aHeight
= mLineHeight
;
407 NS_IMETHODIMP
nsScrollPortView::ScrollByLines(PRInt32 aNumLinesX
, PRInt32 aNumLinesY
,
408 PRUint32 aUpdateFlags
)
410 nscoord dx
= mLineHeight
*aNumLinesX
;
411 nscoord dy
= mLineHeight
*aNumLinesY
;
413 return ScrollTo(mDestinationX
+ dx
, mDestinationY
+ dy
, aUpdateFlags
);
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
,
430 PRUint32 aUpdateFlags
)
433 GetPageScrollDistances(&delta
);
435 // put in the number of pages.
436 delta
.width
*= aNumPagesX
;
437 delta
.height
*= aNumPagesY
;
439 return ScrollTo(mDestinationX
+ delta
.width
, mDestinationY
+ delta
.height
,
443 NS_IMETHODIMP
nsScrollPortView::ScrollByWhole(PRBool aTop
,
444 PRUint32 aUpdateFlags
)
450 nsView
* scrolledView
= GetScrolledView();
451 scrolledView
->GetDimensions(scrolledSize
);
452 newPos
= scrolledSize
.height
;
455 ScrollTo(mDestinationX
, newPos
, aUpdateFlags
);
460 NS_IMETHODIMP
nsScrollPortView::ScrollByPixels(PRInt32 aNumPixelsX
,
462 PRUint32 aUpdateFlags
)
464 nsCOMPtr
<nsIDeviceContext
> dev
;
465 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
466 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
468 nscoord dx
= NSIntPixelsToAppUnits(aNumPixelsX
, p2a
);
469 nscoord dy
= NSIntPixelsToAppUnits(aNumPixelsY
, p2a
);
471 return ScrollTo(mDestinationX
+ dx
, mDestinationY
+ dy
, aUpdateFlags
);
474 NS_IMETHODIMP
nsScrollPortView::CanScroll(PRBool aHorizontal
,
478 nscoord offset
= aHorizontal
? mOffsetX
: mOffsetY
;
480 nsView
* scrolledView
= GetScrolledView();
483 return NS_ERROR_FAILURE
;
487 scrolledView
->GetDimensions(scrolledRect
);
489 // Can scroll to Top or to Left?
491 aResult
= offset
> (aHorizontal
? scrolledRect
.x
: scrolledRect
.y
);
496 GetDimensions(portSize
);
498 nsCOMPtr
<nsIDeviceContext
> dev
;
499 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
500 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
504 max
= scrolledRect
.XMost() - portSize
.width
;
506 nscoord maxPx
= NSAppUnitsToIntPixels(max
, p2a
);
507 max
= NSIntPixelsToAppUnits(maxPx
, p2a
);
509 max
= scrolledRect
.YMost() - portSize
.height
;
511 nscoord maxPx
= NSAppUnitsToIntPixels(max
, p2a
);
512 max
= NSIntPixelsToAppUnits(maxPx
, p2a
);
515 // Can scroll to Bottom or to Right?
516 aResult
= (offset
< max
) ? PR_TRUE
: PR_FALSE
;
521 void nsScrollPortView::Scroll(nsView
*aScrolledView
, nsPoint aTwipsDelta
, nsPoint aPixDelta
,
524 if (aTwipsDelta
.x
!= 0 || aTwipsDelta
.y
!= 0)
526 /* If we should invalidate our wrapped view, we should do so at this
529 if (aScrolledView
->NeedsInvalidateFrameOnScroll())
530 GetViewManager()->GetViewObserver()->InvalidateFrameForView(aScrolledView
);
532 nsIWidget
*scrollWidget
= GetWidget();
533 nsRegion updateRegion
;
534 PRBool canBitBlit
= scrollWidget
&&
535 ((mScrollProperties
& NS_SCROLL_PROPERTY_ALWAYS_BLIT
) ||
536 mViewManager
->CanScrollWithBitBlt(aScrolledView
, aTwipsDelta
, &updateRegion
));
539 // We're going to bit-blit. Let the viewmanager know so it can
540 // adjust dirty regions appropriately.
541 mViewManager
->WillBitBlit(this, aTwipsDelta
);
546 NS_ASSERTION(!canBitBlit
, "Someone screwed up");
547 nsPoint offsetToWidget
;
548 GetNearestWidget(&offsetToWidget
);
549 // We're moving the child widgets because we are scrolling. But
550 // the child widgets may stick outside our bounds, so their area
551 // may include area that's not supposed to be scrolled. We need
552 // to invalidate to ensure that any such area is properly
553 // repainted back to the right rendering.
554 AdjustChildWidgets(aScrolledView
, offsetToWidget
, aP2A
, PR_TRUE
);
555 // If we don't have a scroll widget then we must just update.
556 // We should call this after fixing up the widget positions to be
557 // consistent with the view hierarchy.
558 mViewManager
->UpdateView(this, NS_VMREFRESH_DEFERRED
);
559 } else if (!canBitBlit
) {
560 // We can't blit for some reason.
561 // Just update the view and adjust widgets
562 // Recall that our widget's origin is at our bounds' top-left
563 nsRect
bounds(GetBounds());
564 nsPoint
topLeft(bounds
.x
, bounds
.y
);
565 AdjustChildWidgets(aScrolledView
,
566 GetPosition() - topLeft
, aP2A
, PR_FALSE
);
567 // We should call this after fixing up the widget positions to be
568 // consistent with the view hierarchy.
569 mViewManager
->UpdateView(this, NS_VMREFRESH_DEFERRED
);
570 } else { // if we can blit and have a scrollwidget then scroll.
571 nsRect
* toScrollPtr
= nsnull
;
575 if (!updateRegion
.IsEmpty()) {
576 nsRegion regionToScroll
;
577 regionToScroll
.Sub(nsRect(nsPoint(0,0), GetBounds().Size()),
579 nsRegionRectIterator
iter(regionToScroll
);
580 nsRect
biggestRect(0,0,0,0);
582 for (r
= iter
.Next(); r
; r
= iter
.Next()) {
583 if (r
->width
*r
->height
> biggestRect
.width
*biggestRect
.height
) {
587 toScrollPtr
= &toScroll
;
588 biggestRect
.ScaleRoundIn(1.0/aP2A
);
589 toScroll
= biggestRect
;
591 regionToScroll
.Sub(regionToScroll
, biggestRect
);
592 updateRegion
.Or(updateRegion
, regionToScroll
);
596 // Scroll the contents of the widget by the specified amount, and scroll
598 scrollWidget
->Scroll(aPixDelta
.x
, aPixDelta
.y
, toScrollPtr
);
599 mViewManager
->UpdateViewAfterScroll(this, updateRegion
);
604 NS_IMETHODIMP
nsScrollPortView::ScrollToImpl(nscoord aX
, nscoord aY
)
606 PRInt32 dxPx
= 0, dyPx
= 0;
609 nsCOMPtr
<nsIDeviceContext
> dev
;
610 mViewManager
->GetDeviceContext(*getter_AddRefs(dev
));
611 PRInt32 p2a
= dev
->AppUnitsPerDevPixel();
613 // Update the scrolled view's position
614 nsresult rv
= ClampScrollValues(aX
, aY
, this);
619 PRInt32 xPixels
= NSAppUnitsToIntPixels(aX
, p2a
);
620 PRInt32 yPixels
= NSAppUnitsToIntPixels(aY
, p2a
);
622 aX
= NSIntPixelsToAppUnits(xPixels
, p2a
);
623 aY
= NSIntPixelsToAppUnits(yPixels
, p2a
);
625 // do nothing if the we aren't scrolling.
626 // this needs to be rechecked because of the clamping and
628 if (aX
== mOffsetX
&& aY
== mOffsetY
) {
632 // figure out the diff by comparing old pos to new
633 dxPx
= NSAppUnitsToIntPixels(mOffsetX
, p2a
) - xPixels
;
634 dyPx
= NSAppUnitsToIntPixels(mOffsetY
, p2a
) - yPixels
;
636 // notify the listeners.
637 PRUint32 listenerCount
;
638 const nsIID
& kScrollPositionListenerIID
= NS_GET_IID(nsIScrollPositionListener
);
639 nsIScrollPositionListener
* listener
;
640 if (nsnull
!= mListeners
) {
641 if (NS_SUCCEEDED(mListeners
->Count(&listenerCount
))) {
642 for (PRUint32 i
= 0; i
< listenerCount
; i
++) {
643 if (NS_SUCCEEDED(mListeners
->QueryElementAt(i
, kScrollPositionListenerIID
, (void**)&listener
))) {
644 listener
->ScrollPositionWillChange(this, aX
, aY
);
645 NS_RELEASE(listener
);
651 nsView
* scrolledView
= GetScrolledView();
652 if (!scrolledView
) return NS_ERROR_FAILURE
;
654 // move the scrolled view to the new location
655 // Note that child widgets may be scrolled by the native widget scrolling,
656 // so don't update their positions
657 scrolledView
->SetPositionIgnoringChildWidgets(-aX
, -aY
);
659 // notify the listeners.
660 if (nsnull
!= mListeners
) {
661 if (NS_SUCCEEDED(mListeners
->Count(&listenerCount
))) {
662 for (PRUint32 i
= 0; i
< listenerCount
; i
++) {
663 if (NS_SUCCEEDED(mListeners
->QueryElementAt(i
, kScrollPositionListenerIID
, (void**)&listener
))) {
664 listener
->ViewPositionDidChange(this);
665 NS_RELEASE(listener
);
671 nsPoint
twipsDelta(aX
- mOffsetX
, aY
- mOffsetY
);
673 // store the new position
677 Scroll(scrolledView
, twipsDelta
, nsPoint(dxPx
, dyPx
), p2a
);
679 mViewManager
->SynthesizeMouseMove(PR_TRUE
);
681 // notify the listeners.
682 if (nsnull
!= mListeners
) {
683 if (NS_SUCCEEDED(mListeners
->Count(&listenerCount
))) {
684 for (PRUint32 i
= 0; i
< listenerCount
; i
++) {
685 if (NS_SUCCEEDED(mListeners
->QueryElementAt(i
, kScrollPositionListenerIID
, (void**)&listener
))) {
686 listener
->ScrollPositionDidChange(this, aX
, aY
);
687 NS_RELEASE(listener
);
696 PRBool
nsScrollPortView::IsSmoothScrollingEnabled() {
697 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
700 nsresult rv
= prefs
->GetBoolPref(SMOOTH_SCROLL_PREF_NAME
, &enabled
);
701 if (NS_SUCCEEDED(rv
)) {
709 * Callback function from timer used in nsScrollPortView::ScrollTo
712 nsScrollPortView::AsyncScrollCallback(nsITimer
*aTimer
, void* anInstance
)
714 nsScrollPortView
* self
= static_cast<nsScrollPortView
*>(anInstance
);
716 self
->IncrementalScroll();
721 * manages data members and calls to ScrollTo from the (static) AsyncScrollCallback method
724 nsScrollPortView::IncrementalScroll()
729 if (mAsyncScroll
->mIsSmoothScroll
) {
730 if (mAsyncScroll
->mFrameIndex
< SMOOTH_SCROLL_FRAMES
) {
731 ScrollToImpl(mOffsetX
+ mAsyncScroll
->mVelocities
[mAsyncScroll
->mFrameIndex
*2],
732 mOffsetY
+ mAsyncScroll
->mVelocities
[mAsyncScroll
->mFrameIndex
*2 + 1]);
733 mAsyncScroll
->mFrameIndex
++;
737 ScrollToImpl(mDestinationX
, mDestinationY
);
740 mAsyncScroll
= nsnull
;