/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsScrollingView.h" #include "nsIWidget.h" #include "nsUnitConversion.h" #include "nsIPresContext.h" #include "nsIScrollbar.h" #include "nsIDeviceContext.h" #include "nsGUIEvent.h" #include "nsWidgetsCID.h" #include "nsViewsCID.h" #include "nsIScrollableView.h" #include "nsIFrame.h" #include "nsILookAndFeel.h" #include "nsISupportsArray.h" #include "nsIScrollPositionListener.h" #include "nsIRegion.h" #include "nsViewManager.h" static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID); static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); static NS_DEFINE_IID(kIClipViewIID, NS_ICLIPVIEW_IID); class ScrollBarView : public nsView { public: ScrollBarView(nsScrollingView *aScrollingView); ~ScrollBarView(); nsEventStatus HandleEvent(nsViewManager* aVM, nsGUIEvent *aEvent, PRBool aCaptured); // Do not set the visibility of the ScrollbarView using SetVisibility. Instead it // must be marked as visible or hidden using SetEnabled. // The nsScrollingView::UpdateComponentVisibility looks at both the enabled flag and the // scrolling views visibility to determine if the ScrollBarView is visible or hidden and calls // SetVisibility. KMM void SetEnabled(PRBool aEnabled); PRBool GetEnabled(); public: nsScrollingView *mScrollingView; protected: PRBool mEnabled; }; static inline PRBool ViewIsShowing(ScrollBarView *aView) { return(aView->GetEnabled()); } ScrollBarView::ScrollBarView(nsScrollingView *aScrollingView) { mScrollingView = aScrollingView; mEnabled = PR_FALSE; } ScrollBarView::~ScrollBarView() { } nsEventStatus ScrollBarView::HandleEvent(nsViewManager* aVM, nsGUIEvent *aEvent, PRBool aCaptured) { switch (aEvent->message) { case NS_SCROLLBAR_POS: case NS_SCROLLBAR_PAGE_NEXT: case NS_SCROLLBAR_PAGE_PREV: case NS_SCROLLBAR_LINE_NEXT: case NS_SCROLLBAR_LINE_PREV: NS_ASSERTION((nsnull != mScrollingView), "HandleEvent() called after the ScrollingView has been destroyed."); if (nsnull != mScrollingView) mScrollingView->HandleScrollEvent(aEvent, 0); return nsEventStatus_eConsumeNoDefault; default: break; } return nsEventStatus_eIgnore; } void ScrollBarView::SetEnabled(PRBool aEnabled) { mEnabled = aEnabled; } PRBool ScrollBarView::GetEnabled() { return(mEnabled); } class CornerView : public nsView { public: CornerView(); ~CornerView(); NS_IMETHOD ShowQuality(PRBool aShow); NS_IMETHOD SetQuality(nsContentQuality aQuality); NS_IMETHOD Paint(nsIRenderingContext& rc, const nsRect& rect, PRUint32 aPaintFlags, PRBool &Result); NS_IMETHOD Paint(nsIRenderingContext& rc, const nsIRegion& region, PRUint32 aPaintFlags, PRBool &aResult); void Show(PRBool aShow, PRBool aRethink); PRBool mShowQuality; nsContentQuality mQuality; PRBool mShow; nsILookAndFeel *mLookAndFeel; }; CornerView::CornerView() { mShowQuality = PR_FALSE; mQuality = nsContentQuality_kGood; mShow = PR_FALSE; mLookAndFeel = nsnull; } CornerView::~CornerView() { NS_IF_RELEASE(mLookAndFeel); } NS_IMETHODIMP CornerView::ShowQuality(PRBool aShow) { if (mShowQuality != aShow) { mShowQuality = aShow; if (mShow == PR_FALSE) { if (mShowQuality == PR_FALSE) mViewManager->SetViewVisibility(this, nsViewVisibility_kHide); else mViewManager->SetViewVisibility(this, nsViewVisibility_kShow); nsIScrollableView *par; if (NS_OK == mParent->QueryInterface(NS_GET_IID(nsIScrollableView), (void **)&par)) { par->ComputeScrollOffsets(PR_TRUE); } } mViewManager->UpdateView(this, NS_VMREFRESH_IMMEDIATE); } return NS_OK; } NS_IMETHODIMP CornerView::SetQuality(nsContentQuality aQuality) { if (mQuality != aQuality) { mQuality = aQuality; if (mVis == nsViewVisibility_kShow) mViewManager->UpdateView(this, NS_VMREFRESH_IMMEDIATE); } return NS_OK; } void CornerView::Show(PRBool aShow, PRBool aRethink) { if (mShow != aShow) { mShow = aShow; if (mShow == PR_TRUE) mViewManager->SetViewVisibility(this, nsViewVisibility_kShow); else if (mShowQuality == PR_FALSE) mViewManager->SetViewVisibility(this, nsViewVisibility_kHide); if (PR_TRUE == aRethink) { nsIScrollableView *par; if (NS_OK == mParent->QueryInterface(NS_GET_IID(nsIScrollableView), (void **)&par)) { par->ComputeScrollOffsets(PR_TRUE); } } } } #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif NS_IMETHODIMP CornerView::Paint(nsIRenderingContext& rc, const nsRect& rect, PRUint32 aPaintFlags, PRBool &aResult) { if (mVis == nsViewVisibility_kShow) { nsRect brect; nscolor bgcolor; GetBounds(brect); brect.x = brect.y = 0; if (nsnull == mLookAndFeel) { nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, NS_GET_IID(nsILookAndFeel), (void **)&mLookAndFeel); } if (nsnull != mLookAndFeel) mLookAndFeel->GetColor(nsILookAndFeel::eColor_WidgetBackground, bgcolor); else bgcolor = NS_RGB(192, 192, 192); rc.SetColor(bgcolor); rc.FillRect(brect); if (PR_TRUE == mShowQuality) { nscolor tcolor, bcolor; //display quality indicator rc.Translate(brect.x, brect.y); rc.SetColor(NS_RGB(0, 0, 0)); rc.FillEllipse(NSToCoordFloor(brect.width * 0.15f), NSToCoordFloor(brect.height * 0.15f), NSToCoordRound(brect.width * 0.7f), // XXX should use NSToCoordCeil ?? NSToCoordRound(brect.height * 0.7f)); // XXX should use NSToCoordCeil ?? if (mQuality == nsContentQuality_kGood) rc.SetColor(NS_RGB(0, 255, 0)); else if (mQuality == nsContentQuality_kFair) rc.SetColor(NS_RGB(255, 176, 0)); else if (mQuality == nsContentQuality_kPoor) rc.SetColor(NS_RGB(255, 0, 0)); else rc.SetColor(NS_RGB(0, 0, 255)); //hey, notice that these numbers don't add up... that's because //something funny happens on windows when the *right* numbers are //used. MMP rc.FillEllipse(NSToCoordRound(brect.width * 0.23f), // XXX should use NSToCoordCeil ?? NSToCoordRound(brect.height * 0.23f), // XXX should use NSToCoordCeil ?? nscoord(brect.width * 0.46f), nscoord(brect.height * 0.46f)); rc.GetColor(bcolor); tcolor = bcolor; //this is inefficient, but compact... tcolor = NS_RGB((int)min(NS_GET_R(bcolor) + 40, 255), (int)min(NS_GET_G(bcolor) + 40, 255), (int)min(NS_GET_B(bcolor) + 40, 255)); rc.SetColor(tcolor); rc.FillEllipse(NSToCoordRound(brect.width * 0.34f), // XXX should use NSToCoordCeil ?? NSToCoordRound(brect.height * 0.34f), // XXX should use NSToCoordCeil ?? nscoord(brect.width * 0.28f), nscoord(brect.height * 0.28f)); tcolor = NS_RGB((int)min(NS_GET_R(bcolor) + 120, 255), (int)min(NS_GET_G(bcolor) + 120, 255), (int)min(NS_GET_B(bcolor) + 120, 255)); rc.SetColor(tcolor); rc.FillEllipse(NSToCoordRound(brect.width * 0.32f), // XXX should use NSToCoordCeil ?? NSToCoordRound(brect.height * 0.32f), // XXX should use NSToCoordCeil ?? nscoord(brect.width * 0.17f), nscoord(brect.height * 0.17f)); } } aResult = PR_TRUE; return NS_OK; } NS_IMETHODIMP CornerView::Paint(nsIRenderingContext& rc, const nsIRegion& region, PRUint32 aPaintFlags, PRBool &aResult) { // Corner View Paint is overridden to get rid of compiler warnings caused // by overloading Paint then overriding Paint. return nsView::Paint(rc, region, aPaintFlags, aResult); } class ClipView : public nsView, public nsIClipView { public: ClipView(); ~ClipView(); NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); NS_IMETHOD_(nsrefcnt) AddRef(void); NS_IMETHOD_(nsrefcnt) Release(void); }; ClipView::ClipView() { } ClipView::~ClipView() { } nsresult ClipView::QueryInterface(const nsIID& aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(NS_GET_IID(nsIClipView))) { *aInstancePtr = (void*)(nsIClipView*)this; return NS_OK; } return nsView::QueryInterface(aIID, aInstancePtr); } nsrefcnt ClipView::AddRef() { NS_WARNING("not supported for views"); return 1; } nsrefcnt ClipView::Release() { NS_WARNING("not supported for views"); return 1; } nsScrollingView::nsScrollingView() : mInsets(0, 0, 0, 0) { mSizeX = mSizeY = 0; mOffsetX = mOffsetY = 0; mClipView = nsnull; mVScrollBarView = nsnull; mHScrollBarView = nsnull; mCornerView = nsnull; mScrollPref = nsScrollPreference_kAuto; mLineHeight = 240; mListeners = nsnull; } nsScrollingView::~nsScrollingView() { if (nsnull != mVScrollBarView) { // Clear the back-pointer from the scrollbar... ((ScrollBarView*)mVScrollBarView)->mScrollingView = nsnull; } if (nsnull != mHScrollBarView) { // Clear the back-pointer from the scrollbar... ((ScrollBarView*)mHScrollBarView)->mScrollingView = nsnull; } mClipView = nsnull; mCornerView = nsnull; if (mScrollingTimer) { mScrollingTimer->Cancel(); } if (nsnull != mListeners) { mListeners->Clear(); NS_RELEASE(mListeners); } if (nsnull != mViewManager) { nsIScrollableView* scrollingView; mViewManager->GetRootScrollableView(&scrollingView); if ((nsnull != scrollingView) && (this == scrollingView)) { mViewManager->SetRootScrollableView(nsnull); } } } nsresult nsScrollingView::QueryInterface(const nsIID& aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } *aInstancePtr = nsnull; if (aIID.Equals(NS_GET_IID(nsIScrollableView))) { *aInstancePtr = (void*)(nsIScrollableView*)this; return NS_OK; } return nsView::QueryInterface(aIID, aInstancePtr); } nsrefcnt nsScrollingView::AddRef() { NS_WARNING("not supported for views"); return 1; } nsrefcnt nsScrollingView::Release() { NS_WARNING("not supported for views"); return 1; } NS_IMETHODIMP nsScrollingView::Init(nsIViewManager* aManager, const nsRect &aBounds, const nsIView *aParent, nsViewVisibility aVisibilityFlag) { nsIDeviceContext *dx = nsnull; aManager->GetDeviceContext(dx); if (dx) { float t2d, d2a; dx->GetTwipsToDevUnits(t2d); dx->GetDevUnitsToAppUnits(d2a); mLineHeight = NSToCoordRound(240.0f * t2d * d2a); NS_RELEASE(dx); } return nsView::Init(aManager, aBounds, aParent, aVisibilityFlag); } void nsScrollingView::SetDimensions(const nsRect& aRect, PRBool aPaint) { nsIDeviceContext *dx; mViewManager->GetDeviceContext(dx); float scrollWidth, scrollHeight; dx->GetScrollBarDimensions(scrollWidth, scrollHeight); nscoord showHorz = 0, showVert = 0; nsRect clipRect; // Set our bounds and size our widget if we have one nsView::SetDimensions(aRect, aPaint); #if 0 //this will fix the size of the thumb when we resize the root window, //but unfortunately it will also cause scrollbar flashing. so long as //all resize operations happen through the viewmanager, this is not //an issue. we'll see. MMP ComputeScrollOffsets(); #endif NS_ASSERTION(aRect.x == 0 && aRect.y == 0, "ScrollingView has contents sticking above or to left"); // Determine how much space is actually taken up by the scrollbars if (mHScrollBarView && ViewIsShowing((ScrollBarView *)mHScrollBarView)) showHorz = NSToCoordRound(scrollHeight); if (mVScrollBarView && ViewIsShowing((ScrollBarView *)mVScrollBarView)) showVert = NSToCoordRound(scrollWidth); // Compute the clip view rect clipRect.SetRect(0, 0, PR_MAX((aRect.width - showVert), mInsets.left+mInsets.right), PR_MAX((aRect.height - showHorz), mInsets.top+mInsets.bottom)); clipRect.Deflate(mInsets); // Size and position the clip view if (nsnull != mClipView) { mClipView->SetPosition(clipRect.x, clipRect.y); clipRect.x = clipRect.y = 0; mClipView->SetDimensions(clipRect, aPaint); UpdateScrollControls(aPaint); } NS_RELEASE(dx); } void nsScrollingView::SetPosition(nscoord aX, nscoord aY) { // If we have a widget then there's no need to adjust child widgets, // because they're relative to our window if (nsnull != mWindow) { nsView::SetPosition(aX, aY); } else { nsIDeviceContext *dx; nsIWidget *thiswin; GetWidget(thiswin); float t2p; if (nsnull == thiswin) GetOffsetFromWidget(nsnull, nsnull, thiswin); if (nsnull != thiswin) thiswin->BeginResizingChildren(); nsView::SetPosition(aX, aY); mViewManager->GetDeviceContext(dx); dx->GetAppUnitsToDevUnits(t2p); nsView* scrolledView = GetScrolledView(); if (scrolledView) { // Adjust the positions of the scrollbars and clip view's widget AdjustChildWidgets(this, this, 0, 0, t2p); } if (nsnull != thiswin) { thiswin->EndResizingChildren(); NS_RELEASE(thiswin); } NS_RELEASE(dx); } } nsresult nsScrollingView::SetComponentVisibility(nsView* aView, nsViewVisibility aViewVisibility) { nsresult rv = NS_OK; if (nsnull != aView) { // Only set visibility if it's not currently set. nsViewVisibility componentVisibility; aView->GetVisibility(componentVisibility); if (aViewVisibility != componentVisibility) { rv = aView->SetVisibility(aViewVisibility); } } return rv; } // Set the visibility of the scrolling view's components (ClipView, CornerView, ScrollBarView's) nsresult nsScrollingView::UpdateComponentVisibility(nsViewVisibility aScrollingViewVisibility) { nsresult rv = NS_OK; if (nsViewVisibility_kHide == aScrollingViewVisibility) { // Hide Clip View rv = SetComponentVisibility(mClipView, nsViewVisibility_kHide); // Hide horizontal scrollbar if (NS_SUCCEEDED(rv)) { rv = SetComponentVisibility(mHScrollBarView, nsViewVisibility_kHide); } // Hide vertical scrollbar if (NS_SUCCEEDED(rv)) { rv = SetComponentVisibility(mVScrollBarView, nsViewVisibility_kHide); } // Hide the corner view if (NS_SUCCEEDED(rv)) { rv = SetComponentVisibility(mCornerView, nsViewVisibility_kHide); } } else if (nsViewVisibility_kShow == aScrollingViewVisibility) { // Show clip view if if the scrolling view is visible rv = SetComponentVisibility(mClipView, nsViewVisibility_kShow); PRBool horizEnabled = PR_FALSE; PRBool vertEnabled = PR_FALSE; // Show horizontal scrollbar if it is enabled otherwise hide it if ((NS_SUCCEEDED(rv)) && (nsnull != mHScrollBarView)) { horizEnabled = ((ScrollBarView *)mHScrollBarView)->GetEnabled(); rv = SetComponentVisibility(mHScrollBarView, horizEnabled ? nsViewVisibility_kShow : nsViewVisibility_kHide); } // Show vertical scrollbar view if it is enabled otherwise hide it if ((NS_SUCCEEDED(rv)) && (nsnull != mVScrollBarView)) { vertEnabled = ((ScrollBarView *)mVScrollBarView)->GetEnabled(); rv = SetComponentVisibility(mVScrollBarView, vertEnabled ? nsViewVisibility_kShow : nsViewVisibility_kHide); } // Show the corner view if both the horizontal and vertical scrollbars are enabled otherwise hide it if (NS_SUCCEEDED(rv)) { rv = SetComponentVisibility(mCornerView, (horizEnabled && vertEnabled) ? nsViewVisibility_kShow : nsViewVisibility_kHide); } } return rv; } NS_IMETHODIMP nsScrollingView::SetVisibility(nsViewVisibility aVisibility) { nsresult rv = UpdateComponentVisibility(aVisibility); if (NS_SUCCEEDED(rv)) { rv = nsView::SetVisibility(aVisibility); } return rv; } NS_IMETHODIMP nsScrollingView::GetClipView(const nsIView** aClipView) const { NS_PRECONDITION(aClipView, "null pointer"); *aClipView = mClipView; return NS_OK; } NS_IMETHODIMP nsScrollingView::AddScrollPositionListener(nsIScrollPositionListener* aListener) { if (nsnull == mListeners) { nsresult rv = NS_NewISupportsArray(&mListeners); if (NS_FAILED(rv)) return rv; } return mListeners->AppendElement(aListener); } NS_IMETHODIMP nsScrollingView::RemoveScrollPositionListener(nsIScrollPositionListener* aListener) { if (nsnull != mListeners) { return mListeners->RemoveElement(aListener); } return NS_ERROR_FAILURE; } void nsScrollingView::HandleScrollEvent(nsGUIEvent *aEvent, PRUint32 aEventFlags) { nsIView *scview = nsView::GetViewFor(aEvent->widget); nsIDeviceContext *px; float t2p, p2t; nscoord dx = 0, dy = 0; // in device units nsSize clipSize; mViewManager->GetDeviceContext(px); px->GetAppUnitsToDevUnits(t2p); px->GetDevUnitsToAppUnits(p2t); NS_RELEASE(px); // Get the size of the clip view mClipView->GetDimensions(clipSize); nscoord offsetX = mOffsetX; nscoord offsetY = mOffsetY; // Is it a vertical scroll event or a horizontal scroll event? if ((nsnull != mVScrollBarView) && (scview == mVScrollBarView)) { nscoord oldOffsetY = offsetY; nscoord newPos; // The new scrollbar position is in app units newPos = ((nsScrollbarEvent *)aEvent)->position; // Don't allow a scroll below the bottom of the scrolled view if ((newPos + clipSize.height) > mSizeY) newPos = mSizeY - clipSize.height; // Snap the new scrollbar position to the nearest pixel. This ensures that // as we scroll the view a pixel at a time the scrollbar position // is at the same pixel as the top edge of the scrolled view offsetY = NSIntPixelsToTwips(NSTwipsToIntPixels(newPos, t2p), p2t); // Compute the delta in device units. We need device units when scrolling // the window dy = NSTwipsToIntPixels((oldOffsetY - offsetY), t2p); if (dy != 0) { // Update the scrollbar position passed in with the scrollbar event. // This value will be used to update the scrollbar thumb, and we want // to make sure the scrollbar thumb is in sync with the offset we came // up with here. ((nsScrollbarEvent *)aEvent)->position = offsetY; } } else if ((nsnull != mHScrollBarView) && (scview == mHScrollBarView)) { nscoord oldOffsetX = offsetX; nscoord newPos; // The new scrollbar position is in app units newPos = ((nsScrollbarEvent *)aEvent)->position; // Don't allow a scroll beyond the width of the scrolled view if ((newPos + clipSize.width) > mSizeX) newPos = mSizeX - clipSize.width; // Snap the new scrollbar position to the nearest pixel. This ensures that // as we scroll the view a pixel at a time the scrollbar position // is at the same pixel as the left edge of the scrolled view offsetX = NSIntPixelsToTwips(NSTwipsToIntPixels(newPos, t2p), p2t); // Compute the delta in device units. We need device units when scrolling // the window dx = NSTwipsToIntPixels((oldOffsetX - offsetX), t2p); if (dx != 0) { // Update the scrollbar position passed in with the scrollbar event. // This value will be used to update the scrollbar thumb, and we want // to make sure the scrollbar thumb is in sync with the offset we came // up with here. ((nsScrollbarEvent *)aEvent)->position = offsetX; } } NotifyScrollPositionWillChange(offsetX, offsetY); mOffsetX = offsetX; mOffsetY = offsetY; // Position the scrolled view nsView *scrolledView = GetScrolledView(); if(scrolledView) { scrolledView->SetPosition(-mOffsetX, -mOffsetY); Scroll(scrolledView, dx, dy, t2p, 0); NotifyScrollPositionDidChange(offsetX, offsetY); } } NS_IMETHODIMP nsScrollingView::Notify(nsITimer * aTimer) { nscoord xoff, yoff; // First do the scrolling of the view xoff = mOffsetX; yoff = mOffsetY; nscoord newPos = yoff + mScrollingDelta; if (newPos < 0) newPos = 0; ScrollTo(0, newPos, 0); // Now fake a mouse event so the frames can process the selection event nsRect rect; nsGUIEvent event; nsEventStatus retval; event.message = NS_MOUSE_MOVE; GetBounds(rect); event.point.x = rect.x; event.point.y = (mScrollingDelta > 0) ? (rect.height - rect.y - 1) : 135; //printf("timer %d %d\n", event.point.x, event.point.y); nsIViewObserver *obs; if (NS_OK == mViewManager->GetViewObserver(obs)) { PRBool handled; obs->HandleEvent((nsIView *)this, &event, &retval, PR_TRUE, handled); NS_RELEASE(obs); } nsresult rv; mScrollingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); if (NS_SUCCEEDED(rv)) mScrollingTimer->InitWithCallback(this, 25, nsITimer::TYPE_ONE_SHOT); return NS_OK; } NS_IMETHODIMP nsScrollingView::CreateScrollControls(nsNativeWidget aNative) { nsIDeviceContext *dx; mViewManager->GetDeviceContext(dx); nsresult rv = NS_ERROR_FAILURE; // XXX Have the all widgets siblings. For the time being this is needed // for 'fixed' elements... nsWidgetInitData initData; initData.clipChildren = PR_TRUE; initData.clipSiblings = PR_TRUE; // Create a clip view mClipView = new ClipView; if (nsnull != mClipView) { // The clip view needs a widget to clip any of the scrolled view's // child views with widgets. Note that the clip view has an opacity // of 0.0f (completely transparent) // XXX The clip widget should be created on demand only... rv = mClipView->Init(mViewManager, mDimBounds, this); rv = mViewManager->InsertChild(this, mClipView, mZIndex); rv = mViewManager->SetViewOpacity(mClipView, 0.0f); rv = mClipView->CreateWidget(kWidgetCID, &initData, mWindow ? nsnull : aNative); } // Create a view for a corner cover mCornerView = new CornerView; if (nsnull != mCornerView) { nsRect trect; float sbWidth, sbHeight; dx->GetScrollBarDimensions(sbWidth, sbHeight); trect.width = NSToCoordRound(sbWidth); trect.x = mDimBounds.width - trect.width; trect.height = NSToCoordRound(sbHeight); trect.y = mDimBounds.height - trect.height; rv = mCornerView->Init(mViewManager, trect, this, nsViewVisibility_kHide); mViewManager->InsertChild(this, mCornerView, mZIndex); mCornerView->CreateWidget(kWidgetCID, &initData, mWindow ? nsnull : aNative); } // Create a view for a vertical scrollbar mVScrollBarView = new ScrollBarView(this); if (nsnull != mVScrollBarView) { nsRect trect; float sbWidth, sbHeight; dx->GetScrollBarDimensions(sbWidth, sbHeight); trect.width = NSToCoordRound(sbWidth); trect.x = mDimBounds.width - trect.width; trect.height -= NSToCoordRound(sbHeight); trect.y = 0; static NS_DEFINE_IID(kCScrollbarIID, NS_VERTSCROLLBAR_CID); rv = mVScrollBarView->Init(mViewManager, trect, this); rv = mViewManager->InsertChild(this, mVScrollBarView, mZIndex); rv = mVScrollBarView->CreateWidget(kCScrollbarIID, &initData, mWindow ? nsnull : aNative, PR_FALSE); nsIView *scrolledView; GetScrolledView(scrolledView); #ifdef LOSER // MOUSE WHEEL TRACKER CODE // XXX This code is to be reviewed by michealp // It gets the Window for the view and the gets the widget // for the vertical ScrollbarView and sets it into the window // this is need for platforms where the window receives // scrollbar message that need to be sent to the vertical scrollbar // For example, the Mouse Wheel Tracker on MS-Windows // Find Parent view with window and remember the window nsIWidget * win = nsnull; nsView * view = this; view->GetWidget(win); while (win == nsnull) { nsView * parent = view->GetParent(); if (nsnull == parent) { break; } parent->GetWidget(win); view = parent; } // Set scrollbar widget into window if (nsnull != win) { nsIWidget * scrollbar; mVScrollBarView->GetWidget(scrollbar); if (nsnull != scrollbar) { win->SetVerticalScrollbar(scrollbar); NS_RELEASE(scrollbar); } NS_RELEASE(win); } // XXX done with the code that needs to be reviewed #endif } // Create a view for a horizontal scrollbar mHScrollBarView = new ScrollBarView(this); if (nsnull != mHScrollBarView) { nsRect trect; float sbWidth, sbHeight; dx->GetScrollBarDimensions(sbWidth, sbHeight); trect.height = NSToCoordRound(sbHeight); trect.y = mDimBounds.height - trect.height; trect.width -= NSToCoordRound(sbWidth); trect.x = 0; static NS_DEFINE_IID(kCHScrollbarIID, NS_HORZSCROLLBAR_CID); rv = mHScrollBarView->Init(mViewManager, trect, this); rv = mViewManager->InsertChild(this, mHScrollBarView, mZIndex); rv = mHScrollBarView->CreateWidget(kCHScrollbarIID, &initData, mWindow ? nsnull : aNative, PR_FALSE); } NS_RELEASE(dx); return rv; } NS_IMETHODIMP nsScrollingView::SetWidget(nsIWidget *aWidget) { if (nsnull != aWidget) { NS_ASSERTION(PR_FALSE, "please don't try and set a widget here"); return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP nsScrollingView::SetZIndex(PRBool aAuto, PRInt32 aZIndex, PRBool aTopMost) { nsView::SetZIndex(aAuto, aZIndex, aTopMost); // inform all views that the z-index has changed. // XXX why are we doing this? they're all a child of this view, so they // shouldn't need to be re-z-indexed. if (mClipView) mViewManager->SetViewZIndex(mClipView, aAuto, aZIndex, aTopMost); if (mCornerView) mViewManager->SetViewZIndex(mCornerView, aAuto, aZIndex, aTopMost); if (mVScrollBarView) mViewManager->SetViewZIndex(mVScrollBarView, aAuto, aZIndex, aTopMost); if (mHScrollBarView) mViewManager->SetViewZIndex(mHScrollBarView, aAuto, aZIndex, aTopMost); return NS_OK; } NS_IMETHODIMP nsScrollingView::ComputeScrollOffsets(PRBool aAdjustWidgets) { nsView *scrolledView = GetScrolledView(); nsIScrollbar *scrollv = nsnull, *scrollh = nsnull; PRBool hasVertical = PR_TRUE, hasHorizontal = PR_FALSE; nsIWidget *win; if (nsnull != scrolledView) { nscoord dx = 0, dy = 0; nsIDeviceContext *px; nsSize hSize; nsSize vSize; PRUint32 oldsizey = mSizeY, oldsizex = mSizeX; nscoord offx, offy; float scale; nsRect controlRect(0, 0, mDimBounds.width, mDimBounds.height); controlRect.Deflate(mInsets); mViewManager->GetDeviceContext(px); px->GetAppUnitsToDevUnits(scale); nsSize sz; scrolledView->GetDimensions(sz); mSizeX = sz.width; mSizeY = sz.height; if (nsnull != mHScrollBarView) { mHScrollBarView->GetDimensions(hSize); mHScrollBarView->GetWidget(win); if (NS_OK == win->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollh)) { if (((mSizeX > controlRect.width) && (mScrollPref != nsScrollPreference_kNeverScroll)) || (mScrollPref == nsScrollPreference_kAlwaysScroll) || (mScrollPref == nsScrollPreference_kAlwaysScrollHorizontal)) { hasHorizontal = PR_TRUE; } NS_RELEASE(scrollh); } NS_RELEASE(win); } if (nsnull != mVScrollBarView) { mVScrollBarView->GetDimensions(vSize); offy = mOffsetY; mVScrollBarView->GetWidget(win); if (NS_OK == win->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollv)) { if ((mSizeY > (controlRect.height - (hasHorizontal ? hSize.height : 0)))) { // if we are scrollable if (mScrollPref != nsScrollPreference_kNeverScroll) { //we need to be able to scroll ((ScrollBarView *)mVScrollBarView)->SetEnabled(PR_TRUE); win->Enable(PR_TRUE); //now update the scroller position for the new size PRUint32 oldpos = 0; float p2t; PRInt32 availheight; scrollv->GetPosition(oldpos); px->GetDevUnitsToAppUnits(p2t); availheight = controlRect.height - (hasHorizontal ? hSize.height : 0); // XXX Check for 0 initial size. This is really indicative // of a problem. if (0 == oldsizey) mOffsetY = 0; else { mOffsetY = NSIntPixelsToTwips(NSTwipsToIntPixels(nscoord(oldpos), scale), p2t); if ((mSizeY - mOffsetY) < availheight) { mOffsetY = mSizeY - availheight; if (mOffsetY < 0) mOffsetY = 0; } } dy = NSTwipsToIntPixels((offy - mOffsetY), scale); scrollv->SetParameters(mSizeY, availheight, mOffsetY, mLineHeight); } } else { // The scrolled view is entirely visible vertically. Either hide the // vertical scrollbar or disable it mOffsetY = 0; dy = NSTwipsToIntPixels(offy, scale); scrollv->SetPosition(0); // make sure thumb is at the top scrollv->SetParameters(0, 0, 0, 0); // make thumb full-size if (mScrollPref == nsScrollPreference_kAlwaysScroll || mScrollPref == nsScrollPreference_kAlwaysScrollVertical) { ((ScrollBarView *)mVScrollBarView)->SetEnabled(PR_TRUE); win->Enable(PR_FALSE); } else { ((ScrollBarView *)mVScrollBarView)->SetEnabled(PR_FALSE); win->Enable(PR_TRUE); hasVertical = PR_FALSE; } } NS_RELEASE(scrollv); } NS_RELEASE(win); } if (nsnull != mHScrollBarView) { offx = mOffsetX; mHScrollBarView->GetWidget(win); if (NS_OK == win->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollh)) { if ((mSizeX > (controlRect.width - (hasVertical ? vSize.width : 0)))) { if (mScrollPref != nsScrollPreference_kNeverScroll) { //we need to be able to scroll ((ScrollBarView *)mHScrollBarView)->SetEnabled(PR_TRUE); win->Enable(PR_TRUE); //now update the scroller position for the new size PRUint32 oldpos = 0; float p2t; PRInt32 availwidth; scrollh->GetPosition(oldpos); px->GetDevUnitsToAppUnits(p2t); availwidth = controlRect.width - (hasVertical ? vSize.width : 0); // XXX Check for 0 initial size. This is really indicative // of a problem. if (0 == oldsizex) mOffsetX = 0; else { mOffsetX = NSIntPixelsToTwips(NSTwipsToIntPixels(nscoord(oldpos), scale), p2t); if ((mSizeX - mOffsetX) < availwidth) { mOffsetX = mSizeX - availwidth; if (mOffsetX < 0) mOffsetX = 0; } } dx = NSTwipsToIntPixels((offx - mOffsetX), scale); scrollh->SetParameters(mSizeX, availwidth, mOffsetX, mLineHeight); } } else { // The scrolled view is entirely visible horizontally. Either hide the // horizontal scrollbar or disable it mOffsetX = 0; dx = NSTwipsToIntPixels(offx, scale); scrollh->SetPosition(0); // make sure thumb is all the way to the left if (mScrollPref == nsScrollPreference_kAlwaysScroll || mScrollPref == nsScrollPreference_kAlwaysScrollHorizontal) { ((ScrollBarView *)mHScrollBarView)->SetEnabled(PR_TRUE); win->Enable(PR_FALSE); } else { ((ScrollBarView *)mHScrollBarView)->SetEnabled(PR_FALSE); win->Enable(PR_TRUE); } } NS_RELEASE(scrollh); } NS_RELEASE(win); } // Adjust the size of the clip view to account for scrollbars that are // showing if (mHScrollBarView && ViewIsShowing((ScrollBarView *)mHScrollBarView)) { controlRect.height -= hSize.height; controlRect.height = PR_MAX(controlRect.height, 0); } if (mVScrollBarView && ViewIsShowing((ScrollBarView *)mVScrollBarView)) { controlRect.width -= vSize.width; controlRect.width = PR_MAX(controlRect.width, 0); } nsRect r(0, 0, controlRect.width, controlRect.height); mClipView->SetDimensions(r, PR_FALSE); // Position the scrolled view scrolledView->SetPosition(-mOffsetX, -mOffsetY); if (mCornerView) { if (mHScrollBarView && ViewIsShowing((ScrollBarView *)mHScrollBarView) && mVScrollBarView && ViewIsShowing((ScrollBarView *)mVScrollBarView)) ((CornerView *)mCornerView)->Show(PR_TRUE, PR_FALSE); else ((CornerView *)mCornerView)->Show(PR_FALSE, PR_FALSE); } if ((dx != 0) || (dy != 0) && aAdjustWidgets) AdjustChildWidgets(this, scrolledView, 0, 0, scale); NS_RELEASE(px); } else { // There's no scrolled view so hide the scrollbars and corner view if (nsnull != mHScrollBarView) { ((ScrollBarView *)mHScrollBarView)->SetEnabled(PR_FALSE); mHScrollBarView->GetWidget(win); if (NS_OK == win->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollh)) { scrollh->SetParameters(0, 0, 0, 0); NS_RELEASE(scrollh); } NS_RELEASE(win); } if (nsnull != mVScrollBarView) { ((ScrollBarView *)mVScrollBarView)->SetEnabled(PR_FALSE); mVScrollBarView->GetWidget(win); if (NS_OK == win->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollv)) { scrollv->SetParameters(0, 0, 0, 0); NS_RELEASE(scrollv); } NS_RELEASE(win); } if (nsnull != mCornerView) ((CornerView *)mCornerView)->Show(PR_FALSE, PR_FALSE); mOffsetX = mOffsetY = 0; mSizeX = mSizeY = 0; } UpdateScrollControls(PR_TRUE); return NS_OK; } NS_IMETHODIMP nsScrollingView::GetContainerSize(nscoord *aWidth, nscoord *aHeight) const { *aWidth = mSizeX; *aHeight = mSizeY; return NS_OK; } NS_IMETHODIMP nsScrollingView::ShowQuality(PRBool aShow) { ((CornerView *)mCornerView)->ShowQuality(aShow); return NS_OK; } NS_IMETHODIMP nsScrollingView::GetShowQuality(PRBool &aShow) const { aShow = ((CornerView *)mCornerView)->mShowQuality; return NS_OK; } NS_IMETHODIMP nsScrollingView::SetQuality(nsContentQuality aQuality) { ((CornerView *)mCornerView)->SetQuality(aQuality); return NS_OK; } NS_IMETHODIMP nsScrollingView::SetScrollPreference(nsScrollPreference aPref) { mScrollPref = aPref; ComputeScrollOffsets(PR_TRUE); return NS_OK; } NS_IMETHODIMP nsScrollingView::GetScrollPreference(nsScrollPreference &aScrollPreference) const { aScrollPreference = mScrollPref; return NS_OK; } // XXX doesn't smooth scroll NS_IMETHODIMP nsScrollingView::ScrollTo(nscoord aX, nscoord aY, PRUint32 aUpdateFlags) { nsIDeviceContext *dev; float t2p; float p2t; nsSize clipSize; nsIWidget *widget; PRInt32 dx = 0, dy = 0; mViewManager->GetDeviceContext(dev); dev->GetAppUnitsToDevUnits(t2p); dev->GetDevUnitsToAppUnits(p2t); NS_RELEASE(dev); mClipView->GetDimensions(clipSize); // Clamp aX if ((aX + clipSize.width) > mSizeX) aX = mSizeX - clipSize.width; if (aX < 0) aX = 0; // Clamp aY if ((aY + clipSize.height) > mSizeY) aY = mSizeY - clipSize.height; if (aY < 0) aY = 0; aX = NSIntPixelsToTwips(NSTwipsToIntPixels(aX, t2p), p2t); aY = NSIntPixelsToTwips(NSTwipsToIntPixels(aY, t2p), p2t); // do nothing if the we aren't scrolling. if (aX == mOffsetX && aY == mOffsetY) return NS_OK; mVScrollBarView->GetWidget(widget); if (nsnull != widget) { nsIScrollbar* scrollv = nsnull; if (NS_OK == widget->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollv)) { // Move the scrollbar's thumb PRUint32 oldpos = mOffsetY; scrollv->SetPosition(aY); dy = NSTwipsToIntPixels((oldpos - aY), t2p); NS_RELEASE(scrollv); } NS_RELEASE(widget); } mHScrollBarView->GetWidget(widget); if (nsnull != widget) { nsIScrollbar* scrollh = nsnull; if (NS_OK == widget->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollh)) { // Move the scrollbar's thumb PRUint32 oldpos = mOffsetX; scrollh->SetPosition(aX); dx = NSTwipsToIntPixels((oldpos - aX), t2p); NS_RELEASE(scrollh); } NS_RELEASE(widget); } // Update the scrolled view's position nsView* scrolledView = GetScrolledView(); NotifyScrollPositionWillChange(aX, aY); if (nsnull != scrolledView) { scrolledView->SetPosition(-aX, -aY); mOffsetX = aX; mOffsetY = aY; } Scroll(scrolledView, dx, dy, t2p, 0); NotifyScrollPositionDidChange(aX, aY); return NS_OK; } NS_IMETHODIMP nsScrollingView::SetControlInsets(const nsMargin &aInsets) { mInsets = aInsets; return NS_OK; } NS_IMETHODIMP nsScrollingView::GetControlInsets(nsMargin &aInsets) const { aInsets = mInsets; return NS_OK; } NS_IMETHODIMP nsScrollingView::GetScrollbarVisibility(PRBool *aVerticalVisible, PRBool *aHorizontalVisible) const { *aVerticalVisible = mVScrollBarView && ViewIsShowing((ScrollBarView *)mVScrollBarView); *aHorizontalVisible = mHScrollBarView && ViewIsShowing((ScrollBarView *)mHScrollBarView); return NS_OK; } void nsScrollingView::AdjustChildWidgets(nsScrollingView *aScrolling, nsView *aView, nscoord aDx, nscoord aDy, float scale) { nscoord offx, offy; PRBool isscroll = PR_FALSE; if (aScrolling == aView) { nsIWidget *widget; aScrolling->GetOffsetFromWidget(&aDx, &aDy, widget); NS_IF_RELEASE(widget); } aView->GetPosition(&offx, &offy); aDx += offx; aDy += offy; nsView* kid; for (kid = aView->GetFirstChild(); kid != nsnull; kid = kid->GetNextSibling()) { nsIWidget *win; kid->GetWidget(win); if (nsnull != win) { nsRect bounds; #if 0 win->BeginResizingChildren(); #endif kid->GetBounds(bounds); if (!isscroll || (isscroll && (kid != ((nsScrollingView *)aView)->mVScrollBarView) && (kid != ((nsScrollingView *)aView)->mHScrollBarView))) win->Move(NSTwipsToIntPixels((bounds.x + aDx), scale), NSTwipsToIntPixels((bounds.y + aDy), scale)); else win->Move(NSTwipsToIntPixels((bounds.x + aDx + offx), scale), NSTwipsToIntPixels((bounds.y + aDy + offy), scale)); } // Don't recurse if the view has a widget, because we adjusted the view's // widget position, and its child widgets are relative to its positon if (nsnull == win) AdjustChildWidgets(aScrolling, kid, aDx, aDy, scale); if (nsnull != win) { #if 0 win->EndResizingChildren(); #endif NS_RELEASE(win); } } } void nsScrollingView::UpdateScrollControls(PRBool aPaint) { nsRect clipRect; nsSize cornerSize = nsSize(0, 0); nsSize visCornerSize = nsSize(0, 0); nsPoint cornerPos = nsPoint(0, 0); PRBool vertVis = PR_FALSE; PRBool horzVis = PR_FALSE; if (nsnull != mClipView) { mClipView->GetBounds(clipRect); if (nsnull != mVScrollBarView) vertVis = ((ScrollBarView *)mVScrollBarView)->GetEnabled(); if (nsnull != mHScrollBarView) horzVis = ((ScrollBarView *)mHScrollBarView)->GetEnabled(); if (nsnull != mCornerView) { mCornerView->GetDimensions(cornerSize); // If both the vertical and horizontal scrollbars are enabled, so is the corner view. if (vertVis && horzVis) visCornerSize = cornerSize; if (PR_TRUE == vertVis) visCornerSize.width = 0; if (PR_TRUE == horzVis) visCornerSize.height = 0; } // Size and position the vertical scrollbar if (nsnull != mVScrollBarView) { nsSize vertSize; mVScrollBarView->GetDimensions(vertSize); mVScrollBarView->SetPosition(clipRect.XMost(), clipRect.y); nsRect r(0, 0, vertSize.width, clipRect.height - visCornerSize.height); mVScrollBarView->SetDimensions(r, aPaint); if (vertVis == nsViewVisibility_kShow) cornerPos.x = clipRect.XMost(); else cornerPos.x = clipRect.XMost() - cornerSize.width; } // Size and position the horizontal scrollbar if (nsnull != mHScrollBarView) { nsSize horzSize; mHScrollBarView->GetDimensions(horzSize); mHScrollBarView->SetPosition(clipRect.x, clipRect.YMost()); nsRect r(0, 0, clipRect.width - visCornerSize.width, horzSize.height); mHScrollBarView->SetDimensions(r, aPaint); if (horzVis == nsViewVisibility_kShow) cornerPos.y = clipRect.YMost(); else cornerPos.y = clipRect.YMost() - cornerSize.height; } // Position the corner view if (nsnull != mCornerView) mCornerView->SetPosition(cornerPos.x, cornerPos.y); } // Update the visibility of all of the ScrollingView's components nsViewVisibility scrollingViewVisibility; GetVisibility(scrollingViewVisibility); UpdateComponentVisibility(scrollingViewVisibility); } NS_IMETHODIMP nsScrollingView::SetScrolledView(nsIView *aScrolledView) { return mViewManager->InsertChild(mClipView, aScrolledView, 0); } nsView* nsScrollingView::GetScrolledView() const { if (nsnull != mClipView) { return mClipView->GetFirstChild(); } else { return nsnull; } } NS_IMETHODIMP nsScrollingView::GetScrolledView(nsIView *&aScrolledView) const { aScrolledView = GetScrolledView(); return NS_OK; } NS_IMETHODIMP nsScrollingView::GetScrollPosition(nscoord &aX, nscoord &aY) const { aX = mOffsetX; aY = mOffsetY; return NS_OK; } NS_IMETHODIMP nsScrollingView::SetScrollProperties(PRUint32 aProperties) { mScrollProperties = aProperties; return NS_OK; } NS_IMETHODIMP nsScrollingView::GetScrollProperties(PRUint32 *aProperties) { *aProperties = mScrollProperties; return NS_OK; } NS_IMETHODIMP nsScrollingView::SetLineHeight(nscoord aHeight) { mLineHeight = aHeight; return NS_OK; } NS_IMETHODIMP nsScrollingView::GetLineHeight(nscoord *aHeight) { *aHeight = mLineHeight; return NS_OK; } NS_IMETHODIMP nsScrollingView::ScrollByLines(PRInt32 aNumLinesX, PRInt32 aNumLinesY) { nsCOMPtr widget; nscoord newPosX = 0, newPosY = 0; if (aNumLinesX != 0) { if (mHScrollBarView->GetWidget(*getter_AddRefs(widget)) == NS_OK) { nsCOMPtr scrollh( do_QueryInterface(widget) ); if (scrollh) { PRUint32 oldPos = 0; PRUint32 lineInc; scrollh->GetPosition(oldPos); scrollh->GetLineIncrement(lineInc); newPosX = oldPos + lineInc * aNumLinesX; } } } if (aNumLinesY != 0) { if (mVScrollBarView->GetWidget(*getter_AddRefs(widget)) == NS_OK) { nsCOMPtr scrollv( do_QueryInterface(widget) ); if (scrollv) { PRUint32 oldPos = 0; PRUint32 lineInc; scrollv->GetPosition(oldPos); scrollv->GetLineIncrement(lineInc); newPosY = oldPos + lineInc * aNumLinesY; } } } nsSize clipSize; mClipView->GetDimensions(clipSize); //sanity check values if (newPosX > (mSizeX - clipSize.height)) newPosX = mSizeX - clipSize.height; else if (newPosX < 0) newPosX = 0; if (newPosY > (mSizeY - clipSize.height)) newPosY = mSizeY - clipSize.height; else if (newPosY < 0) newPosY = 0; ScrollTo(newPosX, newPosY, 0); return NS_OK; } NS_IMETHODIMP nsScrollingView::ScrollByPages(PRInt32 aNumPages) { nsIWidget* widget = nsnull; if (mVScrollBarView->GetWidget(widget) == NS_OK) { nsIScrollbar* scrollv = nsnull; if (widget->QueryInterface(NS_GET_IID(nsIScrollbar), (void **)&scrollv) == NS_OK) { PRUint32 oldPos = 0; nsSize clipSize; nscoord newPos = 0; scrollv->GetPosition(oldPos); NS_RELEASE(scrollv); mClipView->GetDimensions(clipSize); newPos = oldPos + clipSize.height * aNumPages; if (newPos > (mSizeY - clipSize.height)) newPos = mSizeY - clipSize.height; if (newPos < 0) newPos = 0; ScrollTo(0, newPos, 0); } NS_RELEASE(widget); } return NS_OK; } NS_IMETHODIMP nsScrollingView::ScrollByWhole(PRBool aTop) { nscoord newPos = 0; if (aTop) { newPos = 0; } else { nsSize clipSize; mClipView->GetDimensions(clipSize); newPos = mSizeY - clipSize.height; } ScrollTo(0, newPos, 0); return NS_OK; } PRBool nsScrollingView::CannotBitBlt(nsView* aScrolledView) { PRUint32 scrolledViewFlags = aScrolledView->GetViewFlags(); return (mScrollProperties & NS_SCROLL_PROPERTY_NEVER_BLIT) || (scrolledViewFlags & NS_VIEW_FLAG_DONT_BITBLT) || (!(mScrollProperties & NS_SCROLL_PROPERTY_ALWAYS_BLIT) && !mViewManager->CanScrollWithBitBlt(aScrolledView)); } void nsScrollingView::Scroll(nsView *aScrolledView, PRInt32 aDx, PRInt32 aDy, float scale, PRUint32 aUpdateFlags) { if ((aDx != 0) || (aDy != 0)) { // Since we keep track of the dirty region as absolute screen coordintes, // we need to offset it by the amount we scrolled. nsCOMPtr dirtyRegion; GetDirtyRegion(*getter_AddRefs(dirtyRegion)); dirtyRegion->Offset(aDx, aDy); nsIWidget *clipWidget; mClipView->GetWidget(clipWidget); if ((nsnull == clipWidget) || CannotBitBlt(aScrolledView)) { // XXX Repainting is really slow. The widget's Scroll() member function // needs an argument that specifies whether child widgets are scrolled, // and we need to be able to specify the rect to be scrolled... mViewManager->UpdateView(mClipView, 0); AdjustChildWidgets(this, aScrolledView, 0, 0, scale); } else { // Scroll the contents of the widget by the specfied amount, and scroll // the child widgets clipWidget->Scroll(aDx, aDy, nsnull); mViewManager->UpdateViewAfterScroll(this, aDx, aDy); } NS_IF_RELEASE(clipWidget); } } nsresult nsScrollingView::NotifyScrollPositionWillChange(nscoord aX, nscoord aY) { nsresult result; if (!mListeners) return NS_OK; PRUint32 listenerCount; result = mListeners->Count(&listenerCount); if (NS_FAILED(result) || listenerCount < 1) return result; const nsIID& kScrollPositionListenerIID = NS_GET_IID(nsIScrollPositionListener); nsIScrollPositionListener* listener; for (PRUint32 i = 0; i < listenerCount; i++) { result = mListeners->QueryElementAt(i, kScrollPositionListenerIID, (void**)&listener); if (NS_FAILED(result)) return result; if (!listener) return NS_ERROR_NULL_POINTER; listener->ScrollPositionWillChange(this, aX, aY); NS_RELEASE(listener); } return result; } nsresult nsScrollingView::NotifyScrollPositionDidChange(nscoord aX, nscoord aY) { nsresult result; if (!mListeners) return NS_OK; PRUint32 listenerCount; result = mListeners->Count(&listenerCount); if (NS_FAILED(result) || listenerCount < 1) return result; const nsIID& kScrollPositionListenerIID = NS_GET_IID(nsIScrollPositionListener); nsIScrollPositionListener* listener; for (PRUint32 i = 0; i < listenerCount; i++) { result = mListeners->QueryElementAt(i, kScrollPositionListenerIID, (void**)&listener); if (NS_FAILED(result)) return result; if (!listener) return NS_ERROR_NULL_POINTER; listener->ScrollPositionDidChange(this, aX, aY); NS_RELEASE(listener); } return result; }