diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 033f5bec4c07..db13fb8b7c4b 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -1209,7 +1209,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, } // disable selection mousedown state on activation - shell->FrameSelection()->SetMouseDownState(PR_FALSE); + nsCOMPtr frameSelection = shell->FrameSelection(); + frameSelection->SetMouseDownState(PR_FALSE); } } } @@ -1713,7 +1714,8 @@ nsEventStateManager::FireContextClick() // stop selection tracking, we're in control now if (mCurrentTarget) { - nsFrameSelection* frameSel = mCurrentTarget->GetFrameSelection(); + nsCOMPtr frameSel = + mCurrentTarget->GetFrameSelection(); if (frameSel && frameSel->GetMouseDownState()) { // note that this can cause selection changed events to fire if we're in @@ -1849,7 +1851,7 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext, // don't interfere! if (mCurrentTarget) { - nsFrameSelection* frameSel = mCurrentTarget->GetFrameSelection(); + nsCOMPtr frameSel = mCurrentTarget->GetFrameSelection(); if (frameSel && frameSel->GetMouseDownState()) { StopTrackingDragGesture(); return; @@ -2386,7 +2388,8 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, viewMan->GrabMouseEvents(nsnull, result); } } - shell->FrameSelection()->SetMouseDownState(PR_FALSE); + nsCOMPtr frameSelection = shell->FrameSelection(); + frameSelection->SetMouseDownState(PR_FALSE); } } break; @@ -4945,7 +4948,7 @@ nsEventStateManager::GetDocSelectionLocation(nsIContent **aStartContent, nsIPresShell *shell; shell = mPresContext->GetPresShell(); - nsFrameSelection *frameSelection = nsnull; + nsCOMPtr frameSelection; if (shell) frameSelection = shell->FrameSelection(); @@ -5296,7 +5299,8 @@ nsEventStateManager::MoveCaretToFocus() nsCOMPtr rangeDoc(do_QueryInterface(mDocument)); if (rangeDoc) { - nsCOMPtr domSelection = shell->FrameSelection()-> + nsCOMPtr frameSelection = shell->FrameSelection(); + nsCOMPtr domSelection = frameSelection-> GetSelection(nsISelectionController::SELECTION_NORMAL); if (domSelection) { nsCOMPtr currentFocusNode(do_QueryInterface(mCurrentFocus)); @@ -5355,7 +5359,7 @@ nsEventStateManager::SetContentCaretVisible(nsIPresShell* aPresShell, nsCOMPtr caret; aPresShell->GetCaret(getter_AddRefs(caret)); - nsFrameSelection* frameSelection = nsnull; + nsCOMPtr frameSelection; if (aFocusedContent) { nsIFrame *focusFrame = aPresShell->GetPrimaryFrameFor(aFocusedContent); @@ -5363,7 +5367,7 @@ nsEventStateManager::SetContentCaretVisible(nsIPresShell* aPresShell, frameSelection = focusFrame->GetFrameSelection(); } - nsFrameSelection *docFrameSelection = aPresShell->FrameSelection(); + nsCOMPtr docFrameSelection = aPresShell->FrameSelection(); if (docFrameSelection && caret && (frameSelection == docFrameSelection || !aFocusedContent)) { diff --git a/layout/base/nsCaret.cpp b/layout/base/nsCaret.cpp index 32651e23e5a3..f802dfe08462 100644 --- a/layout/base/nsCaret.cpp +++ b/layout/base/nsCaret.cpp @@ -299,7 +299,7 @@ NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType, nsIFrame* theFrame = nsnull; PRInt32 theFrameOffset = 0; - nsFrameSelection* frameSelection = GetFrameSelection(); + nsCOMPtr frameSelection = GetFrameSelection(); if (!frameSelection) return NS_ERROR_FAILURE; PRUint8 bidiLevel = frameSelection->GetCaretBidiLevel(); @@ -379,7 +379,7 @@ NS_IMETHODIMP nsCaret::DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset) NS_ENSURE_ARG(aNode); PRUint8 bidiLevel; - nsFrameSelection* frameSelection = GetFrameSelection(); + nsCOMPtr frameSelection = GetFrameSelection(); if (!frameSelection) return NS_ERROR_FAILURE; bidiLevel = frameSelection->GetCaretBidiLevel(); @@ -591,7 +591,7 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode, // If there has been a reflow, set the caret Bidi level to the level of the current frame if (aBidiLevel & BIDI_LEVEL_UNDEFINED) { - nsFrameSelection* frameSelection = GetFrameSelection(); + nsCOMPtr frameSelection = GetFrameSelection(); if (!frameSelection) return PR_FALSE; frameSelection->SetCaretBidiLevel(NS_GET_EMBEDDING_LEVEL(theFrame)); @@ -687,7 +687,7 @@ nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode, if (!presShell) return NS_ERROR_FAILURE; - nsFrameSelection* frameSelection = GetFrameSelection(); + nsCOMPtr frameSelection = GetFrameSelection(); if (!frameSelection) return NS_ERROR_FAILURE; @@ -1009,7 +1009,7 @@ void nsCaret::DrawCaret(PRBool aInvalidate) if (NS_FAILED(domSelection->GetFocusOffset(&offset))) return; - nsFrameSelection* frameSelection = GetFrameSelection(); + nsCOMPtr frameSelection = GetFrameSelection(); if (!frameSelection) return; bidiLevel = frameSelection->GetCaretBidiLevel(); @@ -1203,12 +1203,14 @@ void nsCaret::CaretBlinkCallback(nsITimer *aTimer, void *aClosure) //----------------------------------------------------------------------------- -nsFrameSelection* nsCaret::GetFrameSelection() { +already_AddRefed +nsCaret::GetFrameSelection() +{ nsCOMPtr privateSelection(do_QueryReferent(mDomSelectionWeak)); if (!privateSelection) return nsnull; - nsCOMPtr frameSelection; - privateSelection->GetFrameSelection(getter_AddRefs(frameSelection)); + nsFrameSelection* frameSelection = nsnull; + privateSelection->GetFrameSelection(&frameSelection); return frameSelection; } diff --git a/layout/base/nsCaret.h b/layout/base/nsCaret.h index 582d848a2da3..8907165baff4 100644 --- a/layout/base/nsCaret.h +++ b/layout/base/nsCaret.h @@ -155,7 +155,7 @@ class nsCaret : public nsICaret, } void ToggleDrawnStatus() { mDrawn = !mDrawn; } - nsFrameSelection* GetFrameSelection(); + already_AddRefed GetFrameSelection(); protected: diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index dc7e1468d738..1771672e5080 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -102,10 +102,10 @@ class gfxContext; typedef short SelectionType; typedef PRUint32 nsFrameState; -// 4BE324F2-FB22-47CD-A653-19C70EE55E3F +// ff2bdd39-75ed-4392-92b8-8b650c4db574 #define NS_IPRESSHELL_IID \ -{ 0x4BE324F2, 0xFB22, 0x47CD, \ - { 0xA6, 0x53, 0x19, 0xC7, 0x0E, 0xE5, 0x5E, 0x3F } } +{ 0xff2bdd39, 0x75ed, 0x4392, \ + { 0x92, 0xb8, 0x8b, 0x65, 0x0c, 0x4d, 0xb5, 0x74 } } // Constants for ScrollContentIntoView() function #define NS_PRESSHELL_SCROLL_TOP 0 @@ -252,7 +252,13 @@ public: * You cannot go back and forth anymore with QI between nsIDOM sel and * nsIFrame sel. */ - nsFrameSelection* FrameSelection() { return mSelection; } + already_AddRefed FrameSelection(); + + /** + * ConstFrameSelection returns an object which methods are safe to use for + * example in nsIFrame code. + */ + const nsFrameSelection* ConstFrameSelection() { return mSelection; } // Make shell be a document observer. If called after Destroy() has // been called on the shell, this will be ignored. diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 60a0c27dad6b..ce8cd92140cd 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1352,6 +1352,13 @@ nsIPresShell::RemoveWeakFrame(nsWeakFrame* aWeakFrame) } } +already_AddRefed +nsIPresShell::FrameSelection() +{ + NS_IF_ADDREF(mSelection); + return mSelection; +} + //---------------------------------------------------------------------- nsresult @@ -1412,7 +1419,10 @@ PresShell::~PresShell() NS_IF_RELEASE(mPresContext); NS_IF_RELEASE(mDocument); - NS_IF_RELEASE(mSelection); + if (mSelection) { + mSelection->DisconnectFromPresShell(); + NS_RELEASE(mSelection); + } } /** diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index 097a95d29450..9fde84f44177 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -2716,9 +2716,10 @@ nsTextControlFrame::SetValue(const nsAString& aValue) selPriv->StartBatchChanges(); } + nsCOMPtr kungFuDeathGrip = mSelCon; mSelCon->SelectAll(); nsCOMPtr plaintextEditor = do_QueryInterface(editor); - if (!plaintextEditor) { + if (!plaintextEditor || !weakFrame.IsAlive()) { NS_WARNING("Somehow not a plaintext editor?"); if (pushed) { JSContext* cx; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 45f67f0c10e3..3f1502ccd987 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -816,7 +816,7 @@ nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder, if (!(displaySelection & aContentType)) return NS_OK; - nsFrameSelection* frameSelection = GetFrameSelection(); + const nsFrameSelection* frameSelection = GetConstFrameSelection(); PRInt16 selectionValue = frameSelection->GetDisplaySelection(); if (selectionValue <= nsISelectionController::SELECTION_HIDDEN) @@ -1516,7 +1516,7 @@ nsFrame::HandleEvent(nsPresContext* aPresContext, } NS_IMETHODIMP -nsFrame::GetDataForTableSelection(nsFrameSelection *aFrameSelection, +nsFrame::GetDataForTableSelection(const nsFrameSelection *aFrameSelection, nsIPresShell *aPresShell, nsMouseEvent *aMouseEvent, nsIContent **aParentContent, PRInt32 *aContentOffset, PRInt32 *aTarget) { @@ -1775,11 +1775,11 @@ nsFrame::HandlePress(nsPresContext* aPresContext, // XXX This is screwy; it really should use the selection frame, not the // event frame - nsFrameSelection* frameselection; + const nsFrameSelection* frameselection = nsnull; if (useFrameSelection) - frameselection = GetFrameSelection(); + frameselection = GetConstFrameSelection(); else - frameselection = shell->FrameSelection(); + frameselection = shell->ConstFrameSelection(); if (frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF) return NS_OK;//nothing to do we cannot affect selection from here @@ -1790,11 +1790,13 @@ nsFrame::HandlePress(nsPresContext* aPresContext, if (me->isControl) return NS_OK;//short ciruit. hard coded for mac due to time restraints. #endif - + nsCOMPtr fc = const_cast(frameselection); if (me->clickCount >1 ) { - frameselection->SetMouseDownState(PR_TRUE); - frameselection->SetMouseDoubleDown(PR_TRUE); + // These methods aren't const but can't actually delete anything, + // so no need for nsWeakFrame. + fc->SetMouseDownState(PR_TRUE); + fc->SetMouseDoubleDown(PR_TRUE); return HandleMultiplePress(aPresContext, aEvent, aEventStatus); } @@ -1811,11 +1813,11 @@ nsFrame::HandlePress(nsPresContext* aPresContext, rv = GetDataForTableSelection(frameselection, shell, me, getter_AddRefs(parentContent), &contentOffset, &target); if (NS_SUCCEEDED(rv) && parentContent) { - frameselection->SetMouseDownState(PR_TRUE); - return frameselection->HandleTableSelection(parentContent, contentOffset, target, me); + fc->SetMouseDownState(PR_TRUE); + return fc->HandleTableSelection(parentContent, contentOffset, target, me); } - frameselection->SetDelayedCaretData(0); + fc->SetDelayedCaretData(0); // Check if any part of this frame is selected, and if the // user clicked inside the selected region. If so, we delay @@ -1852,8 +1854,8 @@ nsFrame::HandlePress(nsPresContext* aPresContext, offsets.EndOffset() <= curDetail->mEnd) { delete details; - frameselection->SetMouseDownState(PR_FALSE); - frameselection->SetDelayedCaretData(me); + fc->SetMouseDownState(PR_FALSE); + fc->SetDelayedCaretData(me); return NS_OK; } @@ -1864,7 +1866,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext, } } - frameselection->SetMouseDownState(PR_TRUE); + fc->SetMouseDownState(PR_TRUE); #ifdef XP_MACOSX PRBool control = me->isMeta; @@ -1872,15 +1874,17 @@ nsFrame::HandlePress(nsPresContext* aPresContext, PRBool control = me->isControl; #endif - rv = frameselection->HandleClick(offsets.content, offsets.StartOffset(), - offsets.EndOffset(), me->isShift, control, - offsets.associateWithNext); + // Do not touch any nsFrame members after this point without adding + // weakFrame checks. + rv = fc->HandleClick(offsets.content, offsets.StartOffset(), + offsets.EndOffset(), me->isShift, control, + offsets.associateWithNext); if (NS_FAILED(rv)) return rv; if (offsets.offset != offsets.secondaryOffset) - frameselection->MaintainSelection(); + fc->MaintainSelection(); if (isEditor && !me->isShift && (offsets.EndOffset() - offsets.StartOffset()) == 1) @@ -1890,7 +1894,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext, // -moz-user-select: all or a non-text node without children). // Therefore, disable selection extension during mouse moves. // XXX This is a bit hacky; shouldn't editor be able to deal with this? - frameselection->SetMouseDownState(PR_FALSE); + fc->SetMouseDownState(PR_FALSE); } return rv; @@ -1945,7 +1949,9 @@ nsFrame::HandleMultiplePress(nsPresContext* aPresContext, nsIFrame* theFrame; PRInt32 offset; // Maybe make this a static helper? - theFrame = PresContext()->GetPresShell()->FrameSelection()-> + const nsFrameSelection* frameSelection = + PresContext()->GetPresShell()->ConstFrameSelection(); + theFrame = frameSelection-> GetFrameForNodeOffset(offsets.content, offsets.offset, nsFrameSelection::HINT(offsets.associateWithNext), &offset); @@ -3972,7 +3978,17 @@ nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionControl return CallQueryInterface(aPresContext->GetPresShell(), aSelCon); } -nsFrameSelection* nsIFrame::GetFrameSelection() +already_AddRefed +nsIFrame::GetFrameSelection() +{ + nsFrameSelection* fs = + const_cast(GetConstFrameSelection()); + NS_IF_ADDREF(fs); + return fs; +} + +const nsFrameSelection* +nsIFrame::GetConstFrameSelection() { nsIFrame *frame = this; while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) { @@ -3983,7 +3999,7 @@ nsFrameSelection* nsIFrame::GetFrameSelection() frame = frame->GetParent(); } - return PresContext()->PresShell()->FrameSelection(); + return PresContext()->PresShell()->ConstFrameSelection(); } #ifdef NS_DEBUG diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index fba3c81e29af..1e5c41faeb3e 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -579,7 +579,7 @@ protected: // of the enclosing cell or table (if not inside a cell) // aTarget tells us what table element to select (currently only cell and table supported) // (enums for this are defined in nsIFrame.h) - NS_IMETHOD GetDataForTableSelection(nsFrameSelection *aFrameSelection, + NS_IMETHOD GetDataForTableSelection(const nsFrameSelection *aFrameSelection, nsIPresShell *aPresShell, nsMouseEvent *aMouseEvent, nsIContent **aParentContent, PRInt32 *aContentOffset, PRInt32 *aTarget); diff --git a/layout/generic/nsFrameSelection.h b/layout/generic/nsFrameSelection.h index 919d677f2496..4d9cf759330a 100644 --- a/layout/generic/nsFrameSelection.h +++ b/layout/generic/nsFrameSelection.h @@ -48,10 +48,10 @@ #include "nsGUIEvent.h" // IID for the nsFrameSelection interface -// 6c2c1a4c-47ec-42be-a790-00417bf4c241 +// d78edc5a-28d0-48f0-8abb-1597b1591556 #define NS_FRAME_SELECTION_IID \ -{ 0x6c2c1a4c, 0x47ec, 0x42be, \ - { 0xa7, 0x90, 0x00, 0x41, 0x7b, 0xf4, 0xc2, 0x41 } } +{ 0xd78edc5a, 0x28d0, 0x48f0, \ + { 0x8a, 0xbb, 0x15, 0x97, 0xb1, 0x59, 0x15, 0x56 } } #ifdef IBMBIDI // Constant for Set/Get CaretBidiLevel #define BIDI_LEVEL_UNDEFINED 0x80 @@ -194,6 +194,12 @@ struct nsPrevNextBidiLevels class nsTypedSelection; class nsIScrollableView; +/** + * Methods which are marked with *unsafe* should be handled with special care. + * They may cause nsFrameSelection to be deleted, if strong pointer isn't used, + * or they may cause other objects to be deleted. + */ + class nsFrameSelection : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAME_SELECTION_IID) @@ -221,7 +227,7 @@ public: /** * GetScrollableView returns the current scroll view. */ - nsIScrollableView* GetScrollableView() + nsIScrollableView* GetScrollableView() const { return mScrollableViewProvider ? mScrollableViewProvider->GetScrollableView() @@ -241,6 +247,7 @@ public: * @param aHint will tell the selection which direction geometrically to actually show the caret on. * 1 = end of this line 0 = beginning of this line */ + /*unsafe*/ nsresult HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, PRUint32 aContentEndOffset, @@ -253,6 +260,7 @@ public: * @param aFrame is the parent of all frames to use when searching for the closest frame to the point. * @param aPoint is relative to aFrame */ + /*unsafe*/ void HandleDrag(nsIFrame *aFrame, nsPoint aPoint); /** HandleTableSelection will set selection to a table, cell, etc @@ -267,6 +275,7 @@ public: * TABLESELECTION_ALLCELLS We should select all cells (content points to any cell in table) * @param aMouseEvent passed in so we can get where event occurred and what keys are pressed */ + /*unsafe*/ nsresult HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRInt32 aTarget, @@ -299,31 +308,32 @@ public: SelectionDetails* LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset, PRInt32 aContentLength, - PRBool aSlowCheck); + PRBool aSlowCheck) const; /** SetMouseDownState(PRBool); * sets the mouse state to aState for resons of drag state. * @param aState is the new state of mousedown */ + /*unsafe*/ void SetMouseDownState(PRBool aState); /** GetMouseDownState(PRBool *); * gets the mouse state to aState for resons of drag state. * @param aState will hold the state of mousedown */ - PRBool GetMouseDownState() { return mMouseDownState; } + PRBool GetMouseDownState() const { return mMouseDownState; } /** if we are in table cell selection mode. aka ctrl click in table cell */ - PRBool GetTableCellSelection() { return mSelectingTableCellMode != 0; } - void ClearTableCellSelection(){ mSelectingTableCellMode = 0; } + PRBool GetTableCellSelection() const { return mSelectingTableCellMode != 0; } + void ClearTableCellSelection() { mSelectingTableCellMode = 0; } /** GetSelection * no query interface for selection. must use this method now. * @param aSelectionType enum value defined in nsISelection for the seleciton you want. */ - nsISelection* GetSelection(SelectionType aType); + nsISelection* GetSelection(SelectionType aType) const; /** * ScrollSelectionIntoView scrolls a region of the selection, @@ -336,13 +346,13 @@ public: */ nsresult ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, - PRBool aIsSynchronous); + PRBool aIsSynchronous) const; /** RepaintSelection repaints the selected frames that are inside the selection * specified by aSelectionType. * @param aSelectionType enum value defined in nsISelection for the seleciton you want. */ - nsresult RepaintSelection(SelectionType aType); + nsresult RepaintSelection(SelectionType aType) const; /** GetFrameForNodeOffset given a node and its child offset, return the nsIFrame and * the offset into that frame. @@ -353,7 +363,7 @@ public: nsIFrame* GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, - PRInt32 *aReturnOffset); + PRInt32 *aReturnOffset) const; /** * Scrolling then moving caret placement code in common to text areas and @@ -367,12 +377,13 @@ public: * @param aExtend if PR_TRUE, extend selection to the new point * @param aScrollableView the view that needs the scrolling */ + /*unsafe*/ void CommonPageMove(PRBool aForward, PRBool aExtend, nsIScrollableView *aScrollableView); void SetHint(HINT aHintRight) { mHint = aHintRight; } - HINT GetHint() { return mHint; } + HINT GetHint() const { return mHint; } #ifdef IBMBIDI /** SetCaretBidiLevel sets the caret bidi level @@ -383,7 +394,7 @@ public: /** GetCaretBidiLevel gets the caret bidi level * This method is virtual since it gets called from outside of layout. */ - virtual PRUint8 GetCaretBidiLevel(); + virtual PRUint8 GetCaretBidiLevel() const; /** UndefineCaretBidiLevel sets the caret bidi level to "undefined" * This method is virtual since it gets called from outside of layout. */ @@ -395,6 +406,7 @@ public: * @param aForward move forward in document. * @param aExtend continue selection */ + /*unsafe*/ nsresult CharacterMove(PRBool aForward, PRBool aExtend); /** WordMove will generally be called from the nsiselectioncontroller implementations. @@ -402,12 +414,14 @@ public: * @param aForward move forward in document. * @param aExtend continue selection */ + /*unsafe*/ nsresult WordMove(PRBool aForward, PRBool aExtend); /** WordExtendForDelete extends the selection backward or forward (logically) to the * next word boundary, so that the selected word can be deleted. * @param aForward select forward in document. */ + /*unsafe*/ nsresult WordExtendForDelete(PRBool aForward); /** LineMove will generally be called from the nsiselectioncontroller implementations. @@ -415,6 +429,7 @@ public: * @param aForward move forward in document. * @param aExtend continue selection */ + /*unsafe*/ nsresult LineMove(PRBool aForward, PRBool aExtend); /** IntraLineMove will generally be called from the nsiselectioncontroller implementations. @@ -422,17 +437,19 @@ public: * @param aForward move forward in document. * @param aExtend continue selection */ + /*unsafe*/ nsresult IntraLineMove(PRBool aForward, PRBool aExtend); /** Select All will generally be called from the nsiselectioncontroller implementations. * it will select the whole doc */ + /*unsafe*/ nsresult SelectAll(); /** Sets/Gets The display selection enum. */ void SetDisplaySelection(PRInt16 aState) { mDisplaySelection = aState; } - PRInt16 GetDisplaySelection() { return mDisplaySelection; } + PRInt16 GetDisplaySelection() const { return mDisplaySelection; } /** This method can be used to store the data received during a MouseDown * event so that we can place the caret during the MouseUp event. @@ -455,9 +472,10 @@ public: * in an browser page, we must stop at this node else we reach into the * parent page, which is very bad! */ - nsIContent* GetLimiter() { return mLimiter; } + nsIContent* GetLimiter() const { return mLimiter; } - nsIContent* GetAncestorLimiter() { return mAncestorLimiter; } + nsIContent* GetAncestorLimiter() const { return mAncestorLimiter; } + /*unsafe*/ void SetAncestorLimiter(nsIContent *aLimiter); /** This will tell the frame selection that a double click has been pressed @@ -469,7 +487,7 @@ public: /** This will return whether the double down flag was set. * @return whether the double down flag was set */ - PRBool GetMouseDoubleDown() { return mMouseDoubleDownState; } + PRBool GetMouseDoubleDown() const { return mMouseDoubleDownState; } /** GetPrevNextBidiLevels will return the frames and associated Bidi levels of the characters * logically before and after a (collapsed) selection. @@ -489,7 +507,7 @@ public: */ virtual nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent *aNode, PRUint32 aContentOffset, - PRBool aJumpLines); + PRBool aJumpLines) const; /** GetFrameFromLevel will scan in a given direction * until it finds a frame with a Bidi level less than or equal to a given level. @@ -503,7 +521,7 @@ public: nsresult GetFrameFromLevel(nsIFrame *aFrameIn, nsDirection aDirection, PRUint8 aBidiLevel, - nsIFrame **aFrameOut); + nsIFrame **aFrameOut) const; /** * MaintainSelection will track the current selection as being "sticky". @@ -521,10 +539,12 @@ public: void StartBatchChanges(); void EndBatchChanges(); + /*unsafe*/ nsresult DeleteFromDocument(); - nsIPresShell *GetShell() {return mShell;} + nsIPresShell *GetShell()const { return mShell; } + void DisconnectFromPresShell() { mShell = nsnull; } private: nsresult TakeFocus(nsIContent *aNewFocus, PRUint32 aContentOffset, @@ -541,7 +561,7 @@ private: nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent *aNode, PRUint32 aContentOffset, HINT aHint, - PRBool aJumpLines); + PRBool aJumpLines) const; #ifdef VISUALSELECTION NS_IMETHOD VisualSelectFrames(nsIFrame* aCurrentFrame, nsPeekOffsetStruct aPos); @@ -591,18 +611,20 @@ private: nsresult GetRootForContentSubtree(nsIContent *aContent, nsIContent **aParent); nsresult ConstrainFrameAndPointToAnchorSubtree(nsIFrame *aFrame, nsPoint& aPoint, nsIFrame **aRetFrame, nsPoint& aRetPoint); - PRUint32 GetBatching(){return mBatching;} - PRBool GetNotifyFrames(){return mNotifyFrames;} + PRUint32 GetBatching() const {return mBatching; } + PRBool GetNotifyFrames() const { return mNotifyFrames; } void SetDirty(PRBool aDirty=PR_TRUE){if (mBatching) mChangesDuringBatching = aDirty;} + // nsFrameSelection may get deleted when calling this, + // so remember to use nsCOMPtr when needed. nsresult NotifySelectionListeners(SelectionType aType); // add parameters to say collapsed etc? nsTypedSelection *mDomSelections[nsISelectionController::NUM_SELECTIONTYPES]; // Table selection support. // Interfaces that let us get info based on cellmap locations - nsITableLayout* GetTableLayout(nsIContent *aTableContent); - nsITableCellLayout* GetCellLayout(nsIContent *aCellContent); + nsITableLayout* GetTableLayout(nsIContent *aTableContent) const; + nsITableCellLayout* GetCellLayout(nsIContent *aCellContent) const; nsresult SelectBlockOfCells(nsIContent *aStartNode, nsIContent *aEndNode); nsresult SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget); @@ -610,10 +632,13 @@ private: nsresult GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange); nsresult GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange); - nsresult GetFirstCellNodeInRange(nsIDOMRange *aRange, nsIDOMNode **aCellNode); + nsresult GetFirstCellNodeInRange(nsIDOMRange *aRange, + nsIDOMNode **aCellNode) const; // aTableNode may be null if table isn't needed to be returned - PRBool IsInSameTable(nsIContent *aContent1, nsIContent *aContent2, nsIContent **aTableNode); - nsresult GetParentTable(nsIContent *aCellNode, nsIContent **aTableNode); + PRBool IsInSameTable(nsIContent *aContent1, nsIContent *aContent2, + nsIContent **aTableNode) const; + nsresult GetParentTable(nsIContent *aCellNode, + nsIContent **aTableNode) const; nsresult SelectCellElement(nsIDOMElement* aCellElement); nsresult CreateAndAddRange(nsIDOMNode *aParentNode, PRInt32 aOffset); nsresult ClearNormalSelection(); diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index c1def8688349..4100ca9e08e1 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -104,10 +104,10 @@ struct nsMargin; typedef class nsIFrame nsIBox; // IID for the nsIFrame interface -// 39681dd7-5db6-4e38-b84c-5d9a163c987a +// 95f75c0a-de85-437a-a195-0304df3f62ce #define NS_IFRAME_IID \ -{ 0x39681dd7, 0x5db6, 0x4e38, \ - { 0xb8, 0x4c, 0x5d, 0x9a, 0x16, 0x3c, 0x98, 0x7a } } +{ 0x95f75c0a, 0xde85, 0x437a, \ + { 0xa1, 0x95, 0x03, 0x04, 0xdf, 0x3f, 0x62, 0xce } } /** * Indication of how the frame can be split. This is used when doing runaround @@ -1726,9 +1726,15 @@ public: NS_IMETHOD GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon) = 0; /** - * Call to get nsFrameSelection for this frame; does not addref + * Call to get nsFrameSelection for this frame. */ - nsFrameSelection* GetFrameSelection(); + already_AddRefed GetFrameSelection(); + + /** + * GetConstFrameSelection returns an object which methods are safe to use for + * example in nsIFrame code. + */ + const nsFrameSelection* GetConstFrameSelection(); /** EndSelection related calls */ diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index 0d721386bda4..ac3f5865b15b 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -112,10 +112,6 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID); #include "nsIBidiKeyboard.h" #endif // IBMBIDI -#define STATUS_CHECK_RETURN_MACRO() {if (!mShell) return NS_ERROR_FAILURE;} - - - //#define DEBUG_TABLE 1 static NS_DEFINE_IID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); @@ -188,6 +184,13 @@ struct RangeData PRInt32 mEndIndex; // index into mRangeEndings of this item }; +// Note, the ownership of nsTypedSelection depends on which way the object is +// created. When nsFrameSelection has created nsTypedSelection, +// addreffing/releasing nsTypedSelection object is aggregated to +// nsFrameSelection. Otherwise normal addref/release is used. +// This ensures that nsFrameSelection is never deleted before its +// nsTypedSelections. + class nsTypedSelection : public nsISelection2, public nsISelectionPrivate, public nsSupportsWeakReference @@ -279,8 +282,6 @@ public: nsresult NotifySelectionListeners(); - void DetachFromPresentation(); - private: friend class nsSelectionIterator; @@ -555,12 +556,14 @@ public: nsIView* captureView = capturingFrame->GetMouseCapturer(); - nsIFrame* viewFrame = static_cast(captureView->GetClientData()); - NS_ASSERTION(viewFrame, "View must have a client frame"); + nsWeakFrame viewFrame = static_cast(captureView->GetClientData()); + NS_ASSERTION(viewFrame.GetFrame(), "View must have a client frame"); mFrameSelection->HandleDrag(viewFrame, mPoint); - mSelection->DoAutoScrollView(mPresContext, captureView, mPoint, PR_TRUE); + mSelection->DoAutoScrollView(mPresContext, + viewFrame.IsAlive() ? captureView : nsnull, + mPoint, PR_TRUE); } return NS_OK; } @@ -824,7 +827,6 @@ nsFrameSelection::nsFrameSelection() mDomSelections[i] = new nsTypedSelection(this); if (!mDomSelections[i]) return; - NS_ADDREF(mDomSelections[i]); mDomSelections[i]->SetType(GetSelectionTypeFromIndex(i)); } mBatching = 0; @@ -869,8 +871,7 @@ nsFrameSelection::~nsFrameSelection() PRInt32 i; for (i = 0;iDetachFromPresentation(); - NS_RELEASE(mDomSelections[i]); + delete mDomSelections[i]; } } } @@ -1078,6 +1079,7 @@ nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(nsIFrame *aFrame, // find the closest frame aPoint. // + NS_ENSURE_STATE(mShell); *aRetFrame = mShell->GetPrimaryFrameFor(anchorRoot); if (! *aRetFrame) @@ -1109,7 +1111,7 @@ nsFrameSelection::SetCaretBidiLevel(PRUint8 aLevel) } PRUint8 -nsFrameSelection::GetCaretBidiLevel() +nsFrameSelection::GetCaretBidiLevel() const { return mCaretBidiLevel; } @@ -1218,20 +1220,15 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode, PRBool aContinueSelection, nsSelectionAmount aAmount) { - { - // Make sure that if our presshell gets Destroy() called when we - // flush we don't die. - nsRefPtr kungFuDeathGrip(this); + NS_ENSURE_STATE(mShell); + // Flush out layout, since we need it to be up to date to do caret + // positioning. + mShell->FlushPendingNotifications(Flush_Layout); - // Flush out layout, since we need it to be up to date to do caret - // positioning. - mShell->FlushPendingNotifications(Flush_Layout); - - if (!mShell) { - return NS_OK; - } + if (!mShell) { + return NS_OK; } - + nsPresContext *context = mShell->GetPresContext(); if (!context) return NS_ERROR_FAILURE; @@ -1945,7 +1942,7 @@ nsFrameSelection::VisualSelectFrames(nsIFrame* aCurrentFrame, nsPrevNextBidiLevels nsFrameSelection::GetPrevNextBidiLevels(nsIContent *aNode, PRUint32 aContentOffset, - PRBool aJumpLines) + PRBool aJumpLines) const { return GetPrevNextBidiLevels(aNode, aContentOffset, mHint, aJumpLines); } @@ -1954,7 +1951,7 @@ nsPrevNextBidiLevels nsFrameSelection::GetPrevNextBidiLevels(nsIContent *aNode, PRUint32 aContentOffset, HINT aHint, - PRBool aJumpLines) + PRBool aJumpLines) const { // Get the level of the frames on each side nsIFrame *currentFrame; @@ -2024,8 +2021,9 @@ nsresult nsFrameSelection::GetFrameFromLevel(nsIFrame *aFrameIn, nsDirection aDirection, PRUint8 aBidiLevel, - nsIFrame **aFrameOut) + nsIFrame **aFrameOut) const { + NS_ENSURE_STATE(mShell); PRUint8 foundLevel = 0; nsIFrame *foundFrame = aFrameIn; @@ -2268,7 +2266,7 @@ nsFrameSelection::HandleClick(nsIContent *aNewFocus, void nsFrameSelection::HandleDrag(nsIFrame *aFrame, nsPoint aPoint) { - if (!aFrame) + if (!aFrame || !mShell) return; nsresult result; @@ -2351,6 +2349,7 @@ nsFrameSelection::StartAutoScrollTimer(nsIView *aView, nsPoint aPoint, PRUint32 aDelay) { + NS_ENSURE_STATE(mShell); PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL); return mDomSelections[index]->StartAutoScrollTimer(mShell->GetPresContext(), aView, aPoint, aDelay); @@ -2376,7 +2375,7 @@ nsFrameSelection::TakeFocus(nsIContent *aNewFocus, if (!aNewFocus) return NS_ERROR_NULL_POINTER; - STATUS_CHECK_RETURN_MACRO(); + NS_ENSURE_STATE(mShell); if (!IsValidSelectionPoint(this,aNewFocus)) return NS_ERROR_FAILURE; @@ -2428,6 +2427,7 @@ nsFrameSelection::TakeFocus(nsIContent *aNewFocus, //if we are no longer inside same table ,cell then switch to table selection mode. // BUT only do this in an editor + NS_ENSURE_STATE(mShell); PRInt16 displaySelection; nsresult result = mShell->GetSelectionFlags(&displaySelection); if (NS_FAILED(result)) @@ -2502,8 +2502,10 @@ printf(" * TakeFocus - moving into new cell\n"); SelectionDetails* -nsFrameSelection::LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset, - PRInt32 aContentLength, PRBool aSlowCheck) +nsFrameSelection::LookUpSelection(nsIContent *aContent, + PRInt32 aContentOffset, + PRInt32 aContentLength, + PRBool aSlowCheck) const { if (!aContent || !mShell) return nsnull; @@ -2536,7 +2538,7 @@ nsFrameSelection::SetMouseDownState(PRBool aState) } nsISelection* -nsFrameSelection::GetSelection(SelectionType aType) +nsFrameSelection::GetSelection(SelectionType aType) const { PRInt8 index = GetIndexFromSelectionType(aType); if (index < 0) @@ -2548,7 +2550,7 @@ nsFrameSelection::GetSelection(SelectionType aType) nsresult nsFrameSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, - PRBool aIsSynchronous) + PRBool aIsSynchronous) const { PRInt8 index = GetIndexFromSelectionType(aType); if (index < 0) @@ -2562,13 +2564,14 @@ nsFrameSelection::ScrollSelectionIntoView(SelectionType aType, } nsresult -nsFrameSelection::RepaintSelection(SelectionType aType) +nsFrameSelection::RepaintSelection(SelectionType aType) const { PRInt8 index = GetIndexFromSelectionType(aType); if (index < 0) return NS_ERROR_INVALID_ARG; if (!mDomSelections[index]) return NS_ERROR_NULL_POINTER; + NS_ENSURE_STATE(mShell); return mDomSelections[index]->Repaint(mShell->GetPresContext()); } @@ -2576,9 +2579,9 @@ nsIFrame* nsFrameSelection::GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, - PRInt32 *aReturnOffset) + PRInt32 *aReturnOffset) const { - if (!aNode || !aReturnOffset) + if (!aNode || !aReturnOffset || !mShell) return nsnull; if (aOffset < 0) @@ -2818,6 +2821,7 @@ nsFrameSelection::SelectAll() } else { + NS_ENSURE_STATE(mShell); nsIDocument *doc = mShell->GetDocument(); if (!doc) return NS_ERROR_FAILURE; @@ -2871,8 +2875,9 @@ static PRBool IsCell(nsIContent *aContent) } nsITableCellLayout* -nsFrameSelection::GetCellLayout(nsIContent *aCellContent) +nsFrameSelection::GetCellLayout(nsIContent *aCellContent) const { + NS_ENSURE_TRUE(mShell, nsnull); // Get frame for cell nsIFrame *cellFrame = mShell->GetPrimaryFrameFor(aCellContent); if (!cellFrame) @@ -2885,8 +2890,9 @@ nsFrameSelection::GetCellLayout(nsIContent *aCellContent) } nsITableLayout* -nsFrameSelection::GetTableLayout(nsIContent *aTableContent) +nsFrameSelection::GetTableLayout(nsIContent *aTableContent) const { + NS_ENSURE_TRUE(mShell, nsnull); // Get frame for table nsIFrame *tableFrame = mShell->GetPrimaryFrameFor(aTableContent); if (!tableFrame) @@ -3046,6 +3052,7 @@ printf("HandleTableSelection: Mouse down event\n"); // We have at least 1 other selected cell // Check if new cell is already selected + NS_ENSURE_STATE(mShell); nsIFrame *cellFrame = mShell->GetPrimaryFrameFor(childContent); if (!cellFrame) return NS_ERROR_NULL_POINTER; result = cellFrame->GetSelected(&isSelected); @@ -3253,10 +3260,8 @@ nsFrameSelection::SelectBlockOfCells(nsIContent *aStartCell, nsIContent *aEndCel result = GetCellIndexes(aEndCell, endRowIndex, endColIndex); if(NS_FAILED(result)) return result; - // Get TableLayout interface to access cell data based on cellmap location - // frames are not ref counted, so don't use an nsCOMPtr - nsITableLayout *tableLayoutObject = GetTableLayout(table); - if (!tableLayoutObject) return NS_ERROR_FAILURE; + // Check that |table| is a table. + if (!GetTableLayout(table)) return NS_ERROR_FAILURE; PRInt32 curRowIndex, curColIndex; @@ -3311,6 +3316,11 @@ printf("SelectBlockOfCells -- range is null\n"); PRInt32 col = startColIndex; while(PR_TRUE) { + // Get TableLayout interface to access cell data based on cellmap location + // frames are not ref counted, so don't use an nsCOMPtr + nsITableLayout *tableLayoutObject = GetTableLayout(table); + if (!tableLayoutObject) return NS_ERROR_FAILURE; + result = tableLayoutObject->GetCellDataAt(row, col, *getter_AddRefs(cellElement), curRowIndex, curColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan, isSelected); @@ -3462,7 +3472,7 @@ nsFrameSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget) nsresult nsFrameSelection::GetFirstCellNodeInRange(nsIDOMRange *aRange, - nsIDOMNode **aCellNode) + nsIDOMNode **aCellNode) const { if (!aRange || !aCellNode) return NS_ERROR_NULL_POINTER; @@ -3602,7 +3612,7 @@ nsFrameSelection::GetCellIndexes(nsIContent *aCell, PRBool nsFrameSelection::IsInSameTable(nsIContent *aContent1, nsIContent *aContent2, - nsIContent **aTable) + nsIContent **aTable) const { if (!aContent1 || !aContent2) return PR_FALSE; @@ -3631,7 +3641,7 @@ nsFrameSelection::IsInSameTable(nsIContent *aContent1, } nsresult -nsFrameSelection::GetParentTable(nsIContent *aCell, nsIContent **aTable) +nsFrameSelection::GetParentTable(nsIContent *aCell, nsIContent **aTable) const { if (!aCell || !aTable) { return NS_ERROR_NULL_POINTER; @@ -3992,10 +4002,6 @@ nsTypedSelection::nsTypedSelection() nsTypedSelection::~nsTypedSelection() { - DetachFromPresentation(); -} - -void nsTypedSelection::DetachFromPresentation() { setAnchorFocusRange(-1); if (mAutoScrollTimer) { @@ -4025,9 +4031,36 @@ NS_INTERFACE_MAP_BEGIN(nsTypedSelection) NS_INTERFACE_MAP_END -NS_IMPL_ADDREF(nsTypedSelection) -NS_IMPL_RELEASE(nsTypedSelection) +NS_IMETHODIMP_(nsrefcnt) +nsTypedSelection::AddRef() +{ + if (mFrameSelection) { + return mFrameSelection->AddRef(); + } + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + NS_ASSERT_OWNINGTHREAD(nsTypedSelection); + ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsTypedSelection", sizeof(*this)); + return mRefCnt; +} +NS_IMETHODIMP_(nsrefcnt) +nsTypedSelection::Release() +{ + if (mFrameSelection) { + return mFrameSelection->Release(); + } + NS_PRECONDITION(0 != mRefCnt, "dup release"); + NS_ASSERT_OWNINGTHREAD(nsTypedSelection); + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsTypedSelection"); + if (mRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + NS_DELETEXPCOM(this); + return 0; + } + return mRefCnt; +} NS_IMETHODIMP nsTypedSelection::SetPresShell(nsIPresShell *aPresShell) diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index f963ffb808fa..2b2d6b306017 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -3485,10 +3485,11 @@ GetGeneratedContentOwner(nsIFrame* aFrame, PRBool* aIsBefore) SelectionDetails* nsTextFrame::GetSelectionDetails() { + const nsFrameSelection* frameSelection = GetConstFrameSelection(); if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) { SelectionDetails* details = - GetFrameSelection()->LookUpSelection(mContent, GetContentOffset(), - GetContentLength(), PR_FALSE); + frameSelection->LookUpSelection(mContent, GetContentOffset(), + GetContentLength(), PR_FALSE); SelectionDetails* sd; for (sd = details; sd; sd = sd->mNext) { sd->mStart += mContentOffset; @@ -3505,7 +3506,7 @@ nsTextFrame::GetSelectionDetails() return nsnull; SelectionDetails* details = - GetFrameSelection()->LookUpSelection(owner->GetContent(), + frameSelection->LookUpSelection(owner->GetContent(), isBefore ? 0 : owner->GetContent()->GetChildCount(), 0, PR_FALSE); SelectionDetails* sd; for (sd = details; sd; sd = sd->mNext) { diff --git a/layout/mathml/base/src/nsMathMLmoFrame.cpp b/layout/mathml/base/src/nsMathMLmoFrame.cpp index c9a65ec47cab..8bc82a5f8eba 100644 --- a/layout/mathml/base/src/nsMathMLmoFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmoFrame.cpp @@ -98,8 +98,9 @@ nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame) if (!isSelected) return PR_FALSE; - SelectionDetails* details = aFrame->GetFrameSelection()-> - LookUpSelection(aFrame->GetContent(), 0, 1, PR_TRUE); + const nsFrameSelection* frameSelection = aFrame->GetConstFrameSelection(); + SelectionDetails* details = + frameSelection->LookUpSelection(aFrame->GetContent(), 0, 1, PR_TRUE); if (!details) return PR_FALSE; diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index c7fa63fa6882..3fe466d3169e 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -296,7 +296,8 @@ nsTableCellFrame::DecorateForSelection(nsIRenderingContext& aRenderingContext, nsPresContext* presContext = PresContext(); displaySelection = DisplaySelection(presContext); if (displaySelection) { - nsFrameSelection *frameSelection = presContext->PresShell()->FrameSelection(); + nsCOMPtr frameSelection = + presContext->PresShell()->FrameSelection(); if (frameSelection->GetTableCellSelection()) { nscolor bordercolor; @@ -492,7 +493,9 @@ nsTableCellFrame::SetSelected(nsPresContext* aPresContext, // only this frame is considered nsFrame::SetSelected(aPresContext, aRange, aSelected, aSpread); - if (aPresContext->PresShell()->FrameSelection()->GetTableCellSelection()) { + nsCOMPtr frameSelection = + aPresContext->PresShell()->FrameSelection(); + if (frameSelection->GetTableCellSelection()) { // Selection can affect content, border and outline Invalidate(GetOverflowRect(), PR_FALSE); }