diff --git a/mozilla/layout/base/nsCaret.cpp b/mozilla/layout/base/nsCaret.cpp index bb9dcd0470b..93c76d34da8 100644 --- a/mozilla/layout/base/nsCaret.cpp +++ b/mozilla/layout/base/nsCaret.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Pierre Phaneuf + * Mats Palmgren * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -95,9 +96,9 @@ nsCaret::nsCaret() , mDrawn(PR_FALSE) , mReadOnly(PR_FALSE) , mShowDuringSelection(PR_FALSE) -, mLastCaretFrame(nsnull) , mLastCaretView(nsnull) , mLastContentOffset(0) +, mLastHint(nsIFrameSelection::HINTLEFT) #ifdef IBMBIDI , mKeyboardRTL(PR_FALSE) #endif @@ -200,7 +201,7 @@ NS_IMETHODIMP nsCaret::Terminate() mDomSelectionWeak = nsnull; mPresShell = nsnull; - mLastCaretFrame = nsnull; + mLastContent = nsnull; mLastCaretView = nsnull; #ifdef IBMBIDI @@ -377,23 +378,6 @@ NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType, nsI return NS_OK; } -//----------------------------------------------------------------------------- -NS_IMETHODIMP nsCaret::ClearFrameRefs(nsIFrame* aFrame) -{ - EraseCaret(); // make sure that the caret is erased completely - - if (mLastCaretFrame == aFrame) - { - mLastCaretFrame = nsnull; // frames are not refcounted. - mLastCaretView = nsnull; - mLastContentOffset = 0; - } - - mDrawn = PR_FALSE; // assume that the view has been cleared, and ensure - // that we don't try to use the frame. - return NS_OK; -} - NS_IMETHODIMP nsCaret::EraseCaret() { if (mDrawn) @@ -412,11 +396,8 @@ NS_IMETHODIMP nsCaret::DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset) NS_ENSURE_ARG(aNode); // XXX we need to do more work here to get the correct hint. - if (!SetupDrawingFrameAndOffset(aNode, aOffset, nsIFrameSelection::HINTLEFT)) - return NS_ERROR_FAILURE; - - GetCaretRectAndInvert(); - return NS_OK; + return DrawAtPositionWithHint(aNode, aOffset, nsIFrameSelection::HINTLEFT) ? + NS_OK : NS_ERROR_FAILURE; } @@ -513,15 +494,14 @@ nsresult nsCaret::StopBlinking() return NS_OK; } - -//----------------------------------------------------------------------------- -// Get the nsIFrame and the content offset for the current caret position. -// Returns PR_TRUE if we should go ahead and draw, PR_FALSE otherwise. -// -PRBool nsCaret::SetupDrawingFrameAndOffset(nsIDOMNode* aNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint) +PRBool +nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode, + PRInt32 aOffset, + nsIFrameSelection::HINT aFrameHint) { nsCOMPtr contentNode = do_QueryInterface(aNode); - if (!contentNode) return PR_FALSE; + if (!contentNode) + return PR_FALSE; //get frame selection and find out what frame to use... nsCOMPtr presShell = do_QueryReferent(mPresShell); @@ -708,13 +688,15 @@ PRBool nsCaret::SetupDrawingFrameAndOffset(nsIDOMNode* aNode, PRInt32 aOffset, n return PR_FALSE; } - // mark the frame, so we get notified on deletion. - // frames are never unmarked, which means that we'll touch every frame we visit. - // this is not ideal. - theFrame->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE); + if (!mDrawn) + { + // save stuff so we can erase the caret later + mLastContent = contentNode; + mLastContentOffset = aOffset; + mLastHint = aFrameHint; + } - mLastCaretFrame = theFrame; - mLastContentOffset = theFrameOffset; + GetCaretRectAndInvert(theFrame, theFrameOffset); return PR_TRUE; } @@ -872,7 +854,10 @@ void nsCaret::DrawCaret() if (!MustDrawCaret()) return; - // if we are drawing, not erasing, then set up the frame etc. + nsCOMPtr node; + PRInt32 offset; + nsIFrameSelection::HINT hint; + if (!mDrawn) { nsCOMPtr domSelection = do_QueryReferent(mDomSelectionWeak); @@ -886,38 +871,49 @@ void nsCaret::DrawCaret() PRBool hintRight; privateSelection->GetInterlinePosition(&hintRight);//translate hint. - nsIFrameSelection::HINT hint = (hintRight) ? nsIFrameSelection::HINTRIGHT : nsIFrameSelection::HINTLEFT; + hint = hintRight ? nsIFrameSelection::HINTRIGHT : nsIFrameSelection::HINTLEFT; // get the node and offset, which is where we want the caret to draw - nsCOMPtr focusNode; - domSelection->GetFocusNode(getter_AddRefs(focusNode)); - if (!focusNode) + domSelection->GetFocusNode(getter_AddRefs(node)); + if (!node) return; - PRInt32 contentOffset; - if (NS_FAILED(domSelection->GetFocusOffset(&contentOffset))) - return; - - if (!SetupDrawingFrameAndOffset(focusNode, contentOffset, hint)) + if (NS_FAILED(domSelection->GetFocusOffset(&offset))) return; } + else + { + if (!mLastContent) + { + mDrawn = PR_FALSE; + return; + } + if (!mLastContent->IsInDoc()) + { + mLastContent = nsnull; + mDrawn = PR_FALSE; + return; + } + node = do_QueryInterface(mLastContent); + offset = mLastContentOffset; + hint = mLastHint; + } - GetCaretRectAndInvert(); + DrawAtPositionWithHint(node, offset, hint); } -void nsCaret::GetCaretRectAndInvert() +void nsCaret::GetCaretRectAndInvert(nsIFrame* aFrame, PRInt32 aFrameOffset) { - NS_ASSERTION(mLastCaretFrame != nsnull, "Should have a frame here"); - - nsRect frameRect = mLastCaretFrame->GetRect(); - + NS_ASSERTION(aFrame, "Should have a frame here"); + + nsRect frameRect = aFrame->GetRect(); frameRect.x = 0; // the origin is accounted for in GetViewForRendering() frameRect.y = 0; nsPoint viewOffset(0, 0); nsRect clipRect; nsIView *drawingView; - GetViewForRendering(mLastCaretFrame, eRenderingViewCoordinates, viewOffset, clipRect, &drawingView, nsnull); + GetViewForRendering(aFrame, eRenderingViewCoordinates, viewOffset, clipRect, &drawingView, nsnull); if (!drawingView) return; @@ -954,8 +950,8 @@ void nsCaret::GetCaretRectAndInvert() // after we've got an RC. if (frameRect.height == 0) { - const nsStyleFont* fontStyle = mLastCaretFrame->GetStyleFont(); - const nsStyleVisibility* vis = mLastCaretFrame->GetStyleVisibility(); + const nsStyleFont* fontStyle = aFrame->GetStyleFont(); + const nsStyleVisibility* vis = aFrame->GetStyleVisibility(); mRendContext->SetFont(fontStyle->mFont, vis->mLangGroup); nsCOMPtr fm; @@ -982,7 +978,7 @@ void nsCaret::GetCaretRectAndInvert() nsCOMPtr privateSelection = do_QueryInterface(domSelection); // if cache in selection is available, apply it, else refresh it - privateSelection->GetCachedFrameOffset(mLastCaretFrame,mLastContentOffset, framePos); + privateSelection->GetCachedFrameOffset(aFrame, aFrameOffset, framePos); caretRect += framePos; diff --git a/mozilla/layout/base/nsCaret.h b/mozilla/layout/base/nsCaret.h index c8f766a75f1..ff5b97dcc9a 100644 --- a/mozilla/layout/base/nsCaret.h +++ b/mozilla/layout/base/nsCaret.h @@ -1,4 +1,3 @@ - /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** @@ -74,7 +73,6 @@ class nsCaret : public nsICaret, NS_IMETHOD SetCaretVisible(PRBool intMakeVisible); NS_IMETHOD SetCaretReadOnly(PRBool inMakeReadonly); NS_IMETHOD GetCaretCoordinates(EViewCoordinates aRelativeToType, nsISelection *inDOMSel, nsRect* outCoordinates, PRBool* outIsCollapsed, nsIView **outView); - NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame); NS_IMETHOD EraseCaret(); NS_IMETHOD SetVisibilityDuringSelection(PRBool aVisibility); @@ -94,10 +92,10 @@ class nsCaret : public nsICaret, nsresult StopBlinking(); void GetViewForRendering(nsIFrame *caretFrame, EViewCoordinates coordType, nsPoint &viewOffset, nsRect& outClipRect, nsIView **outRenderingView, nsIView **outRelativeView); - PRBool SetupDrawingFrameAndOffset(nsIDOMNode* aNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint); + PRBool DrawAtPositionWithHint(nsIDOMNode* aNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint); PRBool MustDrawCaret(); void DrawCaret(); - void GetCaretRectAndInvert(); + void GetCaretRectAndInvert(nsIFrame* aFrame, PRInt32 aFrameOffset); void ToggleDrawnStatus() { mDrawn = !mDrawn; } protected: @@ -119,9 +117,11 @@ protected: PRPackedBool mShowDuringSelection; // show when text is selected nsRect mCaretRect; // the last caret rect - nsIFrame* mLastCaretFrame; // store the frame the caret was last drawn in. nsIView* mLastCaretView; // last view that we used for drawing. Cached so we can tell when we need to make a new RC - PRInt32 mLastContentOffset; + nsCOMPtr mLastContent; // store the content the caret was last requested to be drawn in (by DrawAtPosition()/DrawCaret()), + // note that this can be different than where it was actually drawn (anon
in text control) + PRInt32 mLastContentOffset; // the offset for the last request + nsIFrameSelection::HINT mLastHint; // the hint associated with the last request #ifdef IBMBIDI nsRect mHookRect; // directional hook on the caret nsCOMPtr mBidiKeyboard; // Bidi keyboard object to set and query keyboard language diff --git a/mozilla/layout/base/nsICaret.h b/mozilla/layout/base/nsICaret.h index 1fd3f8976b2..3071a8f566a 100644 --- a/mozilla/layout/base/nsICaret.h +++ b/mozilla/layout/base/nsICaret.h @@ -53,8 +53,10 @@ class nsISelection; class nsIDOMNode; // IID for the nsICaret interface -#define NS_ICARET_IID \ -{ 0x43d789e0, 0x21b7, 0x4fb4, { 0xb6, 0xfc, 0x4a, 0x41, 0x49, 0x3e, 0x40, 0xf0 } } +// c2ba7b60-ccbf-4f2b-8bf7-07493bbf3377 +#define NS_ICARET_IID \ +{ 0xc2ba7b60, 0xccbf, 0x4f2b, \ + { 0x8b, 0xf7, 0x07, 0x49, 0x3b, 0xbf, 0x33, 0x77 } } class nsICaret: public nsISupports { @@ -99,11 +101,6 @@ public: */ NS_IMETHOD GetCaretCoordinates(EViewCoordinates aRelativeToType, nsISelection *aDOMSel, nsRect *outCoordinates, PRBool *outIsCollapsed, nsIView **outView) = 0; - /** ClearFrameRefs - * The caret stores a reference to the frame that the caret was last drawn in. - * This is called to tell the caret that that frame is going away. - */ - NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame) = 0; /** Erase Caret * this will erase the caret if its drawn and reset drawn status */ diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 39e9ba2d958..b149604c292 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -3874,10 +3874,6 @@ PresShell::ClearFrameRefs(nsIFrame* aFrame) { mPresContext->EventStateManager()->ClearFrameRefs(aFrame); - if (mCaret) { - mCaret->ClearFrameRefs(aFrame); - } - if (aFrame == mCurrentEventFrame) { mCurrentEventContent = aFrame->GetContent(); mCurrentEventFrame = nsnull;