From d1eab39b5c71b84b16a72839a89c44811f6a5c83 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Thu, 1 Apr 2010 11:35:48 +0900 Subject: [PATCH] Bug 554822 Caret should refer the actual text color instead of the value of CSS color property r=roc --- layout/base/nsCaret.cpp | 18 ++++++++---- layout/base/nsCaret.h | 4 ++- layout/generic/nsFrame.cpp | 7 +++++ layout/generic/nsIFrame.h | 7 +++++ layout/generic/nsTextFrame.h | 2 ++ layout/generic/nsTextFrameThebes.cpp | 42 ++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 7 deletions(-) diff --git a/layout/base/nsCaret.cpp b/layout/base/nsCaret.cpp index a40b20788f6..1bda957fbf8 100644 --- a/layout/base/nsCaret.cpp +++ b/layout/base/nsCaret.cpp @@ -497,7 +497,7 @@ nsresult nsCaret::DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset) return rv; } -nsIFrame * nsCaret::GetCaretFrame() +nsIFrame * nsCaret::GetCaretFrame(PRInt32 *aOffset) { // Return null if we're not drawn to prevent anybody from trying to draw us. if (!mDrawn) @@ -505,14 +505,17 @@ nsIFrame * nsCaret::GetCaretFrame() // Recompute the frame that we're supposed to draw in to guarantee that // we're not going to try to draw into a stale (dead) frame. - PRInt32 unused; + PRInt32 offset; nsIFrame *frame = nsnull; nsresult rv = GetCaretFrameForNodeOffset(mLastContent, mLastContentOffset, mLastHint, mLastBidiLevel, &frame, - &unused); + &offset); if (NS_FAILED(rv)) return nsnull; + if (aOffset) { + *aOffset = offset; + } return frame; } @@ -545,7 +548,10 @@ void nsCaret::PaintCaret(nsDisplayListBuilder *aBuilder, NS_ASSERTION(mDrawn, "The caret shouldn't be drawing"); const nsRect drawCaretRect = mCaretRect + aOffset; - nscolor cssColor = aForFrame->GetStyleColor()->mColor; + PRInt32 contentOffset; + nsIFrame* frame = GetCaretFrame(&contentOffset); + NS_ASSERTION(frame == aForFrame, "We're referring different frame"); + nscolor foregroundColor = aForFrame->GetCaretColorAt(contentOffset); // Only draw the native caret if the foreground color matches that of // -moz-fieldtext (the color of the text in a textbox). If it doesn't match @@ -559,7 +565,7 @@ void nsCaret::PaintCaret(nsDisplayListBuilder *aBuilder, nsILookAndFeel* lookAndFeel = presContext->LookAndFeel(); nscolor fieldText; if (NS_SUCCEEDED(lookAndFeel->GetColor(nsILookAndFeel::eColor__moz_fieldtext, fieldText)) && - fieldText == cssColor) { + fieldText == foregroundColor) { theme->DrawWidgetBackground(aCtx, aForFrame, NS_THEME_TEXTFIELD_CARET, drawCaretRect, drawCaretRect); return; @@ -567,7 +573,7 @@ void nsCaret::PaintCaret(nsDisplayListBuilder *aBuilder, } } - aCtx->SetColor(cssColor); + aCtx->SetColor(foregroundColor); aCtx->FillRect(drawCaretRect); if (!GetHookRect().IsEmpty()) aCtx->FillRect(GetHookRect() + aOffset); diff --git a/layout/base/nsCaret.h b/layout/base/nsCaret.h index dc74d1d9689..74346d81986 100644 --- a/layout/base/nsCaret.h +++ b/layout/base/nsCaret.h @@ -136,8 +136,10 @@ class nsCaret : public nsISelectionListener * Get the current frame that the caret should be drawn in. If the caret is * not currently visible (i.e., it is between blinks), then this will * return null. + * + * @param aOffset is result of the caret offset in the content. */ - nsIFrame* GetCaretFrame(); + nsIFrame* GetCaretFrame(PRInt32 *aOffset = nsnull); /** GetCaretRect * Get the current caret rect. Only call this when GetCaretFrame returns diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index e355927b553..e469b661f48 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -973,6 +973,13 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder, new (aBuilder) nsDisplayCaret(this, aBuilder->GetCaret())); } +nscolor +nsIFrame::GetCaretColorAt(PRInt32 aOffset) +{ + // Use text color. + return GetStyleColor()->mColor; +} + PRBool nsIFrame::HasBorder() const { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 56562799447..81a99cbe6ba 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -977,6 +977,13 @@ public: const nsRect& aDirtyRect, nsDisplayList* aList); + /** + * Get the preferred caret color at the offset. + * + * @param aOffset is offset of the content. + */ + virtual nscolor GetCaretColorAt(PRInt32 aOffset); + PRBool IsThemed(nsTransparencyMode* aTransparencyMode = nsnull) { return IsThemed(GetStyleDisplay(), aTransparencyMode); } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 757f5b68d87..8bbe7b9a54b 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -307,6 +307,8 @@ public: SelectionDetails* aDetails, SelectionType aSelectionType); + virtual nscolor GetCaretColorAt(PRInt32 aOffset); + PRInt16 GetSelectionStatus(PRInt16* aSelectionFlags); #ifdef DEBUG diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 70aad785e47..72af465d011 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -4717,6 +4717,48 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx, return PR_TRUE; } +nscolor +nsTextFrame::GetCaretColorAt(PRInt32 aOffset) +{ + NS_PRECONDITION(aOffset >= 0, "aOffset must be positive"); + + gfxSkipCharsIterator iter = EnsureTextRun(); + PropertyProvider provider(this, iter); + PRInt32 contentOffset = provider.GetStart().GetOriginalOffset(); + PRInt32 contentLength = provider.GetOriginalLength(); + NS_PRECONDITION(aOffset >= contentOffset && + aOffset <= contentOffset + contentLength, + "aOffset must be in the frame's range"); + PRInt32 offsetInFrame = aOffset - contentOffset; + if (offsetInFrame < 0 || offsetInFrame >= contentLength) { + return nsFrame::GetCaretColorAt(aOffset); + } + + nsTextPaintStyle textPaintStyle(this); + SelectionDetails* details = GetSelectionDetails(); + SelectionDetails* sdptr = details; + nscolor result = nsFrame::GetCaretColorAt(aOffset); + SelectionType type = 0; + while (sdptr) { + PRInt32 start = NS_MAX(0, sdptr->mStart - contentOffset); + PRInt32 end = NS_MIN(contentLength, sdptr->mEnd - contentOffset); + if (start <= offsetInFrame && offsetInFrame < end && + (type == 0 || sdptr->mType < type)) { + nscolor foreground, background; + if (GetSelectionTextColors(sdptr->mType, textPaintStyle, + sdptr->mTextRangeStyle, + &foreground, &background)) { + result = foreground; + type = sdptr->mType; + } + } + sdptr = sdptr->mNext; + } + + DestroySelectionDetails(details); + return result; +} + static PRUint32 ComputeTransformedLength(PropertyProvider& aProvider) {