Bug 1048752. Part 19: Create nsCaret::GetPaintGeometry to call during painting. r=tn

This is the start of the changes to caret-drawing proper.

The idea is to combine GetCaretFrame and GetCaretRect into a method
GetPaintGeometry which looks like GetGeometry but returns values
needed for painting (i.e. including bidi decorations, and returning
a null frame if we're not supposed to paint due to specific caret
state, e.g. in the "off" phase of the blink cycle).

Mostly a straightforward refactoring but there are a few interesting changes:
-- nsDisplayCaret stores its bounds instead of getting them from nsCaret on
demand. Eventually those bounds will not be stored in nsCaret at all.
-- nsDisplayCaret::GetBounds returns true for aSnap. nsCaret draws snapped
rects, so why not.
-- I removed "if (caretRect.Intersects(aDirtyRect))" in EnterPresShell.
As far as I can tell, this check is incorrect because it doesn't take
transforms into account. Since there's at most one drawn caret per window,
hence we do this at most once per paint, I don't think there's any real
performance advantage to having this check.

--HG--
extra : rebase_source : c98d3a5994478b482d19cc2e2ac83ab51bd17e00
This commit is contained in:
Robert O'Callahan 2014-08-06 17:19:28 +12:00
parent 1b1473f94c
commit 27a3fe0069
6 changed files with 34 additions and 32 deletions

View File

@ -476,6 +476,13 @@ nsIFrame * nsCaret::GetCaretFrame(int32_t *aOffset)
return frame;
}
nsIFrame*
nsCaret::GetPaintGeometry(nsRect* aRect)
{
aRect->UnionRect(mCaretRect, GetHookRect());
return GetCaretFrame();
}
void nsCaret::UpdateCaretPosition()
{
// We'll recalculate anyway if we're not drawn right now.

View File

@ -113,17 +113,14 @@ class nsCaret : public nsISelectionListener
* @param aOffset is result of the caret offset in the content.
*/
nsIFrame* GetCaretFrame(int32_t *aOffset = nullptr);
/** GetCaretRect
* Get the current caret rect. Only call this when GetCaretFrame returns
* non-null.
* This rect includes any extra decorations for bidi.
/**
* Returns a frame to paint in, and the bounds of the painted caret
* relative to that frame.
* The rectangle includes bidi decorations.
* Returns null if the caret should not be drawn (including if it's blinked
* off).
*/
nsRect GetCaretRect()
{
nsRect r;
r.UnionRect(mCaretRect, GetHookRect());
return r;
}
nsIFrame* GetPaintGeometry(nsRect* aRect);
/**
* A simple wrapper around GetGeometry. Does not take any caret state into
* account other than the current selection.

View File

@ -942,19 +942,10 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
return;
nsRefPtr<nsCaret> caret = state->mPresShell->GetCaret();
state->mCaretFrame = caret->GetCaretFrame();
NS_ASSERTION(state->mCaretFrame == caret->GetCaretFrame(),
"GetCaretFrame() is unstable");
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
if (state->mCaretFrame) {
// Check if the dirty rect intersects with the caret's dirty rect.
nsRect caretRect =
caret->GetCaretRect() + state->mCaretFrame->GetOffsetTo(aReferenceFrame);
if (caretRect.Intersects(aDirtyRect)) {
// Okay, our rects intersect, let's mark the frame and all of its ancestors.
mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
MarkFrameForDisplay(state->mCaretFrame, nullptr);
}
mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
MarkFrameForDisplay(state->mCaretFrame, nullptr);
}
}
@ -2743,10 +2734,10 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
}
nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder,
nsIFrame* aCaretFrame,
nsCaret *aCaret)
nsIFrame* aCaretFrame)
: nsDisplayItem(aBuilder, aCaretFrame)
, mCaret(aCaret)
, mCaret(aBuilder->GetCaret())
, mBounds(aBuilder->GetCaretRect() + ToReferenceFrame())
{
MOZ_COUNT_CTOR(nsDisplayCaret);
}
@ -2761,9 +2752,9 @@ nsDisplayCaret::~nsDisplayCaret()
nsRect
nsDisplayCaret::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
{
*aSnap = false;
*aSnap = true;
// The caret returns a rect in the coordinates of mFrame.
return mCaret->GetCaretRect() + ToReferenceFrame();
return mBounds;
}
void

View File

@ -353,6 +353,12 @@ public:
nsIFrame* GetCaretFrame() {
return CurrentPresShellState()->mCaretFrame;
}
/**
* Get the rectangle we're supposed to draw the caret into.
*/
const nsRect& GetCaretRect() {
return CurrentPresShellState()->mCaretRect;
}
/**
* Get the caret associated with the current presshell.
*/
@ -703,6 +709,7 @@ private:
struct PresShellState {
nsIPresShell* mPresShell;
nsIFrame* mCaretFrame;
nsRect mCaretRect;
nsRect mPrevDirtyRect;
uint32_t mFirstFrameMarkedForDisplay;
bool mIsBackgroundOnly;
@ -1951,8 +1958,7 @@ protected:
class nsDisplayCaret : public nsDisplayItem {
public:
nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame,
nsCaret *aCaret);
nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayCaret();
#endif
@ -1962,6 +1968,7 @@ public:
NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET)
protected:
nsRefPtr<nsCaret> mCaret;
nsRect mBounds;
};
/**

View File

@ -1553,8 +1553,7 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
if (!IsVisibleForPainting(aBuilder))
return;
aList->AppendNewToTop(
new (aBuilder) nsDisplayCaret(aBuilder, this, aBuilder->GetCaret()));
aList->AppendNewToTop(new (aBuilder) nsDisplayCaret(aBuilder, this));
}
nscolor

View File

@ -3640,7 +3640,8 @@ SVGTextFrame::PaintSVG(nsRenderingContext* aContext,
gfxMatrix currentMatrix = gfx->CurrentMatrix();
nsRefPtr<nsCaret> caret = presContext->PresShell()->GetCaret();
nsIFrame* caretFrame = caret->GetCaretFrame();
nsRect caretRect;
nsIFrame* caretFrame = caret->GetPaintGeometry(&caretRect);
TextRenderedRunIterator it(this, TextRenderedRunIterator::eVisibleFrames);
TextRenderedRun run = it.Current();