Bug 898871 - Add more nsWeakFrame checks around scroll operations. r=roc

This commit is contained in:
Mats Palmgren 2013-08-08 22:04:59 +00:00
parent b0c3d1c587
commit a030bc32af
9 changed files with 232 additions and 28 deletions

View File

@ -643,7 +643,11 @@ nsListControlFrame::SingleSelection(int32_t aClickedIndex, bool aDoToggle)
wasChanged = SetOptionsSelectedFromFrame(aClickedIndex, aClickedIndex,
true, true);
}
nsWeakFrame weakFrame(this);
ScrollToIndex(aClickedIndex);
if (!weakFrame.IsAlive()) {
return wasChanged;
}
#ifdef ACCESSIBILITY
bool isCurrentOptionChanged = mEndSelectionIndex != aClickedIndex;
@ -775,7 +779,11 @@ nsListControlFrame::PerformSelection(int32_t aClickedIndex,
// Clear only if control was not pressed
wasChanged = ExtendedSelection(startIndex, endIndex, !aIsControl);
nsWeakFrame weakFrame(this);
ScrollToIndex(aClickedIndex);
if (!weakFrame.IsAlive()) {
return wasChanged;
}
if (mStartSelectionIndex == kNothingSelected) {
mStartSelectionIndex = aClickedIndex;
@ -792,12 +800,12 @@ nsListControlFrame::PerformSelection(int32_t aClickedIndex,
}
#endif
} else if (aIsControl) {
wasChanged = SingleSelection(aClickedIndex, true);
wasChanged = SingleSelection(aClickedIndex, true); // might destroy us
} else {
wasChanged = SingleSelection(aClickedIndex, false);
wasChanged = SingleSelection(aClickedIndex, false); // might destroy us
}
} else {
wasChanged = SingleSelection(aClickedIndex, false);
wasChanged = SingleSelection(aClickedIndex, false); // might destroy us
}
return wasChanged;
@ -817,7 +825,7 @@ nsListControlFrame::HandleListSelection(nsIDOMEvent* aEvent,
mouseEvent->GetCtrlKey(&isControl);
#endif
mouseEvent->GetShiftKey(&isShift);
return PerformSelection(aClickedIndex, isShift, isControl);
return PerformSelection(aClickedIndex, isShift, isControl); // might destroy us
}
//---------------------------------------------------------
@ -1018,7 +1026,11 @@ nsListControlFrame::ResetList(bool aAllowScrolling)
NS_ASSERTION(selectElement, "No select element!");
if (selectElement) {
selectElement->GetSelectedIndex(&indexToSelect);
nsWeakFrame weakFrame(this);
ScrollToIndex(indexToSelect);
if (!weakFrame.IsAlive()) {
return;
}
}
}
@ -1290,12 +1302,13 @@ nsListControlFrame::ComboboxFinish(int32_t aIndex)
gLastKeyTime = 0;
if (mComboboxFrame) {
PerformSelection(aIndex, false, false);
nsWeakFrame weakFrame(this);
PerformSelection(aIndex, false, false); // might destroy us
if (!weakFrame.IsAlive() || !mComboboxFrame) {
return;
}
int32_t displayIndex = mComboboxFrame->GetIndexOfDisplayArea();
nsWeakFrame weakFrame(this);
if (displayIndex != aIndex) {
mComboboxFrame->RedisplaySelectedText(); // might destroy us
}
@ -1336,7 +1349,11 @@ nsListControlFrame::OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex)
mComboboxFrame->UpdateRecentIndex(NS_SKIP_NOTIFY_INDEX);
}
nsWeakFrame weakFrame(this);
ScrollToIndex(aNewIndex);
if (!weakFrame.IsAlive()) {
return NS_OK;
}
mStartSelectionIndex = aNewIndex;
mEndSelectionIndex = aNewIndex;
InvalidateFocus();
@ -1398,7 +1415,11 @@ nsListControlFrame::AboutToDropDown()
mLastDropdownBackstopColor);
if (mIsAllContentHere && mIsAllFramesHere && mHasBeenInitialized) {
nsWeakFrame weakFrame(this);
ScrollToIndex(GetSelectedIndex());
if (!weakFrame.IsAlive()) {
return;
}
#ifdef ACCESSIBILITY
FireMenuItemActiveEvent(); // Inform assistive tech what got focus
#endif
@ -1785,7 +1806,13 @@ nsListControlFrame::MouseDown(nsIDOMEvent* aMouseEvent)
// Handle Like List
mButtonDown = true;
CaptureMouseEvents(true);
mChangesSinceDragStart = HandleListSelection(aMouseEvent, selectedIndex);
nsWeakFrame weakFrame(this);
bool change =
HandleListSelection(aMouseEvent, selectedIndex); // might destroy us
if (!weakFrame.IsAlive()) {
return NS_OK;
}
mChangesSinceDragStart = change;
} else {
// NOTE: the combo box is responsible for dropping it down
if (mComboboxFrame) {
@ -1827,12 +1854,12 @@ nsListControlFrame::MouseMove(nsIDOMEvent* aMouseEvent)
if (mComboboxFrame->IsDroppedDown()) {
int32_t selectedIndex;
if (NS_SUCCEEDED(GetIndexFromDOMEvent(aMouseEvent, selectedIndex))) {
PerformSelection(selectedIndex, false, false);
PerformSelection(selectedIndex, false, false); // might destroy us
}
}
} else {// XXX - temporary until we get drag events
if (mButtonDown) {
return DragMove(aMouseEvent);
return DragMove(aMouseEvent); // might destroy us
}
}
return NS_OK;
@ -1860,9 +1887,13 @@ nsListControlFrame::DragMove(nsIDOMEvent* aMouseEvent)
#else
mouseEvent->GetCtrlKey(&isControl);
#endif
nsWeakFrame weakFrame(this);
// Turn SHIFT on when you are dragging, unless control is on.
bool wasChanged = PerformSelection(selectedIndex,
!isControl, isControl);
if (!weakFrame.IsAlive()) {
return NS_OK;
}
mChangesSinceDragStart = mChangesSinceDragStart || wasChanged;
}
}
@ -2283,6 +2314,7 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
uint32_t numOptions = options->Length();
nsWeakFrame weakFrame(this);
for (uint32_t i = 0; i < numOptions; ++i) {
uint32_t index = (i + startIndex) % numOptions;
nsRefPtr<dom::HTMLOptionElement> optionElement =
@ -2300,7 +2332,11 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
continue;
}
if (!PerformSelection(index, keyEvent->IsShift(), isControlOrMeta)) {
bool wasChanged = PerformSelection(index, keyEvent->IsShift(), isControlOrMeta);
if (!weakFrame.IsAlive()) {
return NS_OK;
}
if (!wasChanged) {
break;
}
@ -2327,12 +2363,16 @@ nsListControlFrame::PostHandleKeyEvent(int32_t aNewIndex,
// If you hold control, but not shift, no key will actually do anything
// except space.
nsWeakFrame weakFrame(this);
bool wasChanged = false;
if (aIsControlOrMeta && !aIsShift && aCharCode != ' ') {
mStartSelectionIndex = aNewIndex;
mEndSelectionIndex = aNewIndex;
InvalidateFocus();
ScrollToIndex(aNewIndex);
if (!weakFrame.IsAlive()) {
return;
}
#ifdef ACCESSIBILITY
FireMenuItemActiveEvent();
@ -2342,7 +2382,7 @@ nsListControlFrame::PostHandleKeyEvent(int32_t aNewIndex,
} else {
wasChanged = PerformSelection(aNewIndex, aIsShift, aIsControlOrMeta);
}
if (wasChanged) {
if (wasChanged && weakFrame.IsAlive()) {
// dispatch event, update combobox, etc.
UpdateSelection();
}

View File

@ -133,19 +133,19 @@ public:
virtual void AboutToDropDown() MOZ_OVERRIDE;
/**
* @note This method might destroy |this|.
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void AboutToRollup() MOZ_OVERRIDE;
/**
* Dispatch a DOM onchange event synchroniously.
* @note This method might destroy |this|.
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void FireOnChange() MOZ_OVERRIDE;
/**
* Makes aIndex the selected option of a combobox list.
* @note This method might destroy |this|.
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ComboboxFinish(int32_t aIndex) MOZ_OVERRIDE;
virtual void OnContentReset() MOZ_OVERRIDE;
@ -162,13 +162,16 @@ public:
NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) MOZ_OVERRIDE;
NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE;
// mouse event listeners (both )
nsresult MouseDown(nsIDOMEvent* aMouseEvent); // might destroy |this|
nsresult MouseUp(nsIDOMEvent* aMouseEvent); // might destroy |this|
/**
* Mouse event listeners.
* @note These methods might destroy the frame, pres shell and other objects.
*/
nsresult MouseDown(nsIDOMEvent* aMouseEvent);
nsresult MouseUp(nsIDOMEvent* aMouseEvent);
nsresult MouseMove(nsIDOMEvent* aMouseEvent);
nsresult DragMove(nsIDOMEvent* aMouseEvent);
nsresult KeyDown(nsIDOMEvent* aKeyEvent); // might destroy |this|
nsresult KeyPress(nsIDOMEvent* aKeyEvent); // might destroy |this|
nsresult KeyDown(nsIDOMEvent* aKeyEvent);
nsresult KeyPress(nsIDOMEvent* aKeyEvent);
/**
* Returns the options collection for mContent, if any.
@ -254,6 +257,7 @@ public:
protected:
/**
* Updates the selected text in a combobox and then calls FireOnChange().
* @note This method might destroy the frame, pres shell and other objects.
* Returns false if calling it destroyed |this|.
*/
bool UpdateSelection();
@ -268,12 +272,18 @@ protected:
/**
* Toggles (show/hide) the combobox dropdown menu.
* @note This method might destroy |this|.
* @note This method might destroy the frame, pres shell and other objects.
*/
void DropDownToggleKey(nsIDOMEvent* aKeyEvent);
nsresult IsOptionDisabled(int32_t anIndex, bool &aIsDisabled);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToFrame(mozilla::dom::HTMLOptionElement& aOptElement);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToIndex(int32_t anIndex);
/**
@ -342,11 +352,20 @@ protected:
bool aValue,
bool aClearAll);
bool ToggleOptionSelectedFromFrame(int32_t aIndex);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
bool SingleSelection(int32_t aClickedIndex, bool aDoToggle);
bool ExtendedSelection(int32_t aStartIndex, int32_t aEndIndex,
bool aClearAll);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
bool PerformSelection(int32_t aClickedIndex, bool aIsShift,
bool aIsControl);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
bool HandleListSelection(nsIDOMEvent * aDOMEvent, int32_t selectedIndex);
void InitSelectionRange(int32_t aClickedIndex);
void PostHandleKeyEvent(int32_t aNewIndex, uint32_t aCharCode,

View File

@ -1578,13 +1578,18 @@ nsGfxScrollFrameInner::AsyncScrollCallback(void* anInstance, mozilla::TimeStamp
nsRect intermediateRange =
nsRect(self->GetScrollPosition(), nsSize()).UnionEdges(range);
self->ScrollToImpl(destination, intermediateRange);
// 'self' might be destroyed here
return;
}
}
// Apply desired destination range since this is the last step of scrolling.
self->mAsyncScroll = nullptr;
nsWeakFrame weakFrame(self->mOuter);
self->ScrollToImpl(self->mDestination, range);
if (!weakFrame.IsAlive()) {
return;
}
// We are done scrolling, set our destination to wherever we actually ended
// up scrolling to.
self->mDestination = self->GetScrollPosition();
@ -1612,6 +1617,7 @@ nsGfxScrollFrameInner::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition)
range.height = 0;
}
ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
// 'this' might be destroyed here
}
void
@ -1621,6 +1627,7 @@ nsGfxScrollFrameInner::ScrollToCSSPixelsApproximate(const CSSPoint& aScrollPosit
nscoord halfRange = nsPresContext::CSSPixelsToAppUnits(1000);
nsRect range(pt.x - halfRange, pt.y - halfRange, 2*halfRange - 1, 2*halfRange - 1);
ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
// 'this' might be destroyed here
}
CSSIntPoint
@ -1648,7 +1655,11 @@ nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition,
// Asynchronous scrolling is not allowed, so we'll kill any existing
// async-scrolling process and do an instant scroll.
mAsyncScroll = nullptr;
nsWeakFrame weakFrame(mOuter);
ScrollToImpl(mDestination, range);
if (!weakFrame.IsAlive()) {
return;
}
// We are done scrolling, set our destination to wherever we actually ended
// up scrolling to.
mDestination = GetScrollPosition();
@ -1664,7 +1675,11 @@ nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition,
if (!mAsyncScroll->SetRefreshObserver(this)) {
mAsyncScroll = nullptr;
// Observer setup failed. Scroll the normal way.
nsWeakFrame weakFrame(mOuter);
ScrollToImpl(mDestination, range);
if (!weakFrame.IsAlive()) {
return;
}
// We are done scrolling, set our destination to wherever we actually
// ended up scrolling to.
mDestination = GetScrollPosition();
@ -2009,7 +2024,11 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
ScrollVisual(oldScrollFramePos);
ScheduleSyntheticMouseMove();
nsWeakFrame weakFrame(mOuter);
UpdateScrollbarPosition();
if (!weakFrame.IsAlive()) {
return;
}
PostScrollEvent();
// notify the listeners.
@ -2472,6 +2491,7 @@ nsGfxScrollFrameInner::ScrollBy(nsIntPoint aDelta,
AdjustForWholeDelta(aDelta.x, &pos.x);
AdjustForWholeDelta(aDelta.y, &pos.y);
ScrollTo(pos, aMode);
// 'this' might be destroyed here
if (aOverflow) {
*aOverflow = nsIntPoint(0, 0);
}
@ -2494,7 +2514,11 @@ nsGfxScrollFrameInner::ScrollBy(nsIntPoint aDelta,
rangeLowerY,
rangeUpperX - rangeLowerX,
rangeUpperY - rangeLowerY);
nsWeakFrame weakFrame(mOuter);
ScrollToWithOrigin(newPos, aMode, aOrigin, &range);
if (!weakFrame.IsAlive()) {
return;
}
if (aOverflow) {
nsPoint clampAmount = newPos - mDestination;
@ -2655,7 +2679,11 @@ nsGfxScrollFrameInner::ScrollToRestoredPosition()
// convert from logical to physical scroll position
scrollToPos.x = mScrollPort.x -
(mScrollPort.XMost() - scrollToPos.x - mScrolledFrame->GetRect().width);
nsWeakFrame weakFrame(mOuter);
ScrollTo(scrollToPos, nsIScrollableFrame::INSTANT);
if (!weakFrame.IsAlive()) {
return;
}
// Re-get the scroll position, it might not be exactly equal to
// mRestorePos due to rounding and clamping.
mLastPos = GetLogicalScrollPosition();
@ -2959,16 +2987,23 @@ nsGfxScrollFrameInner::Destroy()
void
nsGfxScrollFrameInner::UpdateScrollbarPosition()
{
nsWeakFrame weakFrame(mOuter);
mFrameIsUpdatingScrollbar = true;
nsPoint pt = GetScrollPosition();
if (mVScrollbarBox) {
SetCoordAttribute(mVScrollbarBox->GetContent(), nsGkAtoms::curpos,
pt.y - GetScrolledRect().y);
if (!weakFrame.IsAlive()) {
return;
}
}
if (mHScrollbarBox) {
SetCoordAttribute(mHScrollbarBox->GetContent(), nsGkAtoms::curpos,
pt.x - GetScrolledRect().x);
if (!weakFrame.IsAlive()) {
return;
}
}
mFrameIsUpdatingScrollbar = false;
@ -3024,11 +3059,16 @@ void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
// didn't actually move yet. We need to make sure other listeners
// see that the scroll position is not (yet) what they thought it
// was.
nsWeakFrame weakFrame(mOuter);
UpdateScrollbarPosition();
if (!weakFrame.IsAlive()) {
return;
}
}
ScrollToWithOrigin(dest,
isSmooth ? nsIScrollableFrame::SMOOTH : nsIScrollableFrame::INSTANT,
nsGkAtoms::scrollbars, &allowedRange);
// 'this' might be destroyed here
}
/* ============= Scroll events ========== */
@ -3600,7 +3640,8 @@ nsGfxScrollFrameInner::ReflowFinished()
mHScrollbarBox ? mHScrollbarBox->GetContent() : nullptr;
// Note, in some cases mOuter may get deleted while finishing reflow
// for scrollbars.
// for scrollbars. XXXmats is this still true now that we have a script
// blocker in this scope? (if not, remove the weak frame checks below).
if (vScroll || hScroll) {
nsWeakFrame weakFrame(mOuter);
nsPoint scrollPos = GetScrollPosition();
@ -3900,8 +3941,13 @@ nsGfxScrollFrameInner::SetCoordAttribute(nsIContent* aContent, nsIAtom* aAtom,
if (aContent->AttrValueIs(kNameSpaceID_None, aAtom, newValue, eCaseMatters))
return;
nsWeakFrame weakFrame(mOuter);
nsCOMPtr<nsIContent> kungFuDeathGrip = aContent;
aContent->SetAttr(kNameSpaceID_None, aAtom, newValue, true);
MOZ_ASSERT(ShellIsAlive(weakShell), "pres shell was destroyed by scrolling");
if (!weakFrame.IsAlive()) {
return;
}
if (mScrollbarActivity) {
nsRefPtr<ScrollbarActivity> scrollbarActivity(mScrollbarActivity);

View File

@ -88,8 +88,12 @@ public:
virtual bool ReflowFinished() MOZ_OVERRIDE;
virtual void ReflowCallbackCanceled() MOZ_OVERRIDE;
// This gets called when the 'curpos' attribute on one of the scrollbars changes
/**
* @note This method might destroy the frame, pres shell and other objects.
* Called when the 'curpos' attribute on one of the scrollbars changes.
*/
void CurPosAttributeChanged(nsIContent* aChild);
void PostScrollEvent();
void FireScrollEvent();
void PostScrolledAreaEvent();
@ -122,16 +126,29 @@ public:
nsGfxScrollFrameInner *mInner;
};
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void FinishReflowForScrollbar(nsIContent* aContent, nscoord aMinXY,
nscoord aMaxXY, nscoord aCurPosXY,
nscoord aPageIncrement,
nscoord aIncrement);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void SetScrollbarEnabled(nsIContent* aContent, nscoord aMaxPos);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void SetCoordAttribute(nsIContent* aContent, nsIAtom* aAtom, nscoord aSize);
nscoord GetCoordAttribute(nsIFrame* aFrame, nsIAtom* aAtom, nscoord aDefaultValue,
nscoord* aRangeStart, nscoord* aRangeLength);
// Update scrollbar curpos attributes to reflect current scroll position
/**
* @note This method might destroy the frame, pres shell and other objects.
* Update scrollbar curpos attributes to reflect current scroll position
*/
void UpdateScrollbarPosition();
nsRect GetScrollPortRect() const { return mScrollPort; }
@ -163,6 +180,7 @@ protected:
public:
static void AsyncScrollCallback(void* anInstance, mozilla::TimeStamp aTime);
/**
* @note This method might destroy the frame, pres shell and other objects.
* aRange is the range of allowable scroll positions around the desired
* aScrollPosition. Null means only aScrollPosition is allowed.
* This is a closed-ended range --- aRange.XMost()/aRange.YMost() are allowed.
@ -171,14 +189,31 @@ public:
const nsRect* aRange = nullptr) {
ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other, aRange);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition);
CSSIntPoint GetScrollPositionCSSPixels();
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToImpl(nsPoint aScrollPosition, const nsRect& aRange);
void ScrollVisual(nsPoint aOldScrolledFramePosition);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToRestoredPosition();
nsSize GetLineScrollAmount() const;
nsSize GetPageScrollAmount() const;
@ -360,6 +395,9 @@ public:
bool mHasBeenScrolled:1;
protected:
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToWithOrigin(nsPoint aScrollPosition,
nsIScrollableFrame::ScrollMode aMode,
nsIAtom *aOrigin, // nullptr indicates "other" origin
@ -522,23 +560,38 @@ public:
virtual nsSize GetPageScrollAmount() const MOZ_OVERRIDE {
return mInner.GetPageScrollAmount();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
const nsRect* aRange = nullptr) MOZ_OVERRIDE {
mInner.ScrollTo(aScrollPosition, aMode, aRange);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition) MOZ_OVERRIDE {
mInner.ScrollToCSSPixels(aScrollPosition);
}
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition) MOZ_OVERRIDE {
mInner.ScrollToCSSPixelsApproximate(aScrollPosition);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual CSSIntPoint GetScrollPositionCSSPixels() MOZ_OVERRIDE {
return mInner.GetScrollPositionCSSPixels();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr) MOZ_OVERRIDE {
mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToRestoredPosition() MOZ_OVERRIDE {
mInner.ScrollToRestoredPosition();
}
@ -548,6 +601,9 @@ public:
virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) MOZ_OVERRIDE {
mInner.RemoveScrollPositionListener(aListener);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void CurPosAttributeChanged(nsIContent* aChild) MOZ_OVERRIDE {
mInner.CurPosAttributeChanged(aChild);
}
@ -791,10 +847,16 @@ public:
virtual nsSize GetPageScrollAmount() const MOZ_OVERRIDE {
return mInner.GetPageScrollAmount();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
const nsRect* aRange = nullptr) MOZ_OVERRIDE {
mInner.ScrollTo(aScrollPosition, aMode, aRange);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition) MOZ_OVERRIDE {
mInner.ScrollToCSSPixels(aScrollPosition);
}
@ -804,10 +866,16 @@ public:
virtual CSSIntPoint GetScrollPositionCSSPixels() MOZ_OVERRIDE {
return mInner.GetScrollPositionCSSPixels();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr) MOZ_OVERRIDE {
mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToRestoredPosition() MOZ_OVERRIDE {
mInner.ScrollToRestoredPosition();
}
@ -817,6 +885,9 @@ public:
virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) MOZ_OVERRIDE {
mInner.RemoveScrollPositionListener(aListener);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void CurPosAttributeChanged(nsIContent* aChild) MOZ_OVERRIDE {
mInner.CurPosAttributeChanged(aChild);
}

View File

@ -154,6 +154,7 @@ public:
*/
enum ScrollMode { INSTANT, SMOOTH, NORMAL };
/**
* @note This method might destroy the frame, pres shell and other objects.
* Clamps aScrollPosition to GetScrollRange and sets the scroll position
* to that value.
* @param aRange If non-null, specifies area which contains aScrollPosition
@ -164,6 +165,7 @@ public:
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
const nsRect* aRange = nullptr) = 0;
/**
* @note This method might destroy the frame, pres shell and other objects.
* Scrolls to a particular position in integer CSS pixels.
* Keeps the exact current horizontal or vertical position if the current
* position, rounded to CSS pixels, matches aScrollPosition. If
@ -175,6 +177,7 @@ public:
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition) = 0;
/**
* @note This method might destroy the frame, pres shell and other objects.
* Scrolls to a particular position in float CSS pixels.
* This does not guarantee that GetScrollPositionCSSPixels equals
* aScrollPosition afterward. It tries to scroll as close to
@ -194,6 +197,7 @@ public:
*/
enum ScrollUnit { DEVICE_PIXELS, LINES, PAGES, WHOLE };
/**
* @note This method might destroy the frame, pres shell and other objects.
* Modifies the current scroll position by aDelta units given by aUnit,
* clamping it to GetScrollRange. If WHOLE is specified as the unit,
* content is scrolled all the way in the direction(s) given by aDelta.
@ -205,6 +209,7 @@ public:
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow = nullptr, nsIAtom *aOrigin = nullptr) = 0;
/**
* @note This method might destroy the frame, pres shell and other objects.
* This tells the scroll frame to try scrolling to the scroll
* position that was restored from the history. This must be called
* at least once after state has been restored. It is called by the

View File

@ -924,8 +924,12 @@ nsListBoxBodyFrame::VerticalScroll(int32_t aPosition)
nsPoint scrollPosition = scrollFrame->GetScrollPosition();
nsWeakFrame weakFrame(this);
scrollFrame->ScrollTo(nsPoint(scrollPosition.x, aPosition),
nsIScrollableFrame::INSTANT);
if (!weakFrame.IsAlive()) {
return;
}
mYPosition = aPosition;
}
@ -1358,7 +1362,11 @@ nsListBoxBodyFrame::OnContentRemoved(nsPresContext* aPresContext,
NS_PRECONDITION(mCurrentIndex > 0, "mCurrentIndex > 0");
--mCurrentIndex;
mYPosition = mCurrentIndex*mRowHeight;
nsWeakFrame weakChildFrame(aChildFrame);
VerticalScroll(mYPosition);
if (!weakChildFrame.IsAlive()) {
return;
}
}
} else if (mCurrentIndex > 0) {
// At this point, we know we have a scrollbar, and we need to know
@ -1382,7 +1390,11 @@ nsListBoxBodyFrame::OnContentRemoved(nsPresContext* aPresContext,
mRowsToPrepend = 1;
--mCurrentIndex;
mYPosition = mCurrentIndex*mRowHeight;
nsWeakFrame weakChildFrame(aChildFrame);
VerticalScroll(mYPosition);
if (!weakChildFrame.IsAlive()) {
return;
}
}
}
}

View File

@ -400,7 +400,11 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu, b
if (mIsOpenChanged) {
nsIScrollableFrame *scrollframe = do_QueryFrame(GetChildBox());
if (scrollframe) {
nsWeakFrame weakFrame(this);
scrollframe->ScrollTo(nsPoint(0,0), nsIScrollableFrame::INSTANT);
if (!weakFrame.IsAlive()) {
return;
}
}
}

View File

@ -96,6 +96,7 @@ nsScrollbarFrame::AttributeChanged(int32_t aNameSpaceID,
if (!scrollable)
return rv;
nsCOMPtr<nsIContent> kungFuDeathGrip(mContent);
scrollable->CurPosAttributeChanged(mContent);
return rv;
}

View File

@ -376,6 +376,7 @@ nsTreeBodyFrame::EnsureView()
// Scroll to the given row.
// XXX is this optimal if we haven't laid out yet?
ScrollToRow(rowIndex);
ENSURE_TRUE(weakFrame.IsAlive());
// Clear out the property info for the top row, but we always keep the
// view current.
@ -4134,9 +4135,12 @@ nsTreeBodyFrame::ScrollHorzInternal(const ScrollParts& aParts, int32_t aPosition
Invalidate();
// Update the column scroll view
nsWeakFrame weakFrame(this);
aParts.mColumnsScrollFrame->ScrollTo(nsPoint(mHorzPosition, 0),
nsIScrollableFrame::INSTANT);
if (!weakFrame.IsAlive()) {
return NS_ERROR_FAILURE;
}
// And fire off an event about it all
PostScrollEvent();
return NS_OK;
@ -4153,7 +4157,8 @@ nsTreeBodyFrame::ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aO
else if (aNewIndex < aOldIndex)
ScrollToRowInternal(parts, mTopRowIndex-1);
} else {
ScrollHorzInternal(parts, aNewIndex);
nsresult rv = ScrollHorzInternal(parts, aNewIndex);
if (NS_FAILED(rv)) return rv;
}
UpdateScrollbars(parts);
@ -4177,7 +4182,8 @@ nsTreeBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex
ScrollInternal(parts, newrow);
// Horizontal Scrollbar
} else if (parts.mHScrollbar == aScrollbar) {
ScrollHorzInternal(parts, aNewIndex);
nsresult rv = ScrollHorzInternal(parts, aNewIndex);
if (NS_FAILED(rv)) return rv;
}
UpdateScrollbars(parts);