Bug 554822 Caret should refer the actual text color instead of the value of CSS color property r=roc
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -492,32 +492,35 @@ nsresult nsCaret::DrawAtPosition(nsIDOMN
nsresult rv = DrawAtPositionWithHint(aNode, aOffset,
nsFrameSelection::HINTLEFT,
bidiLevel, PR_TRUE)
? NS_OK : NS_ERROR_FAILURE;
ToggleDrawnStatus();
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)
return nsnull;
// 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;
}
void nsCaret::InvalidateOutsideCaret()
{
nsIFrame *frame = GetCaretFrame();
// Only invalidate if we are not fully contained by our frame's rect.
@@ -540,39 +543,42 @@ void nsCaret::UpdateCaretPosition()
void nsCaret::PaintCaret(nsDisplayListBuilder *aBuilder,
nsIRenderingContext *aCtx,
nsIFrame* aForFrame,
const nsPoint &aOffset)
{
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
// we are likely in contenteditable or a custom widget and we risk being hard to see
// against the background. In that case, fall back to the CSS color.
nsPresContext* presContext = aForFrame->PresContext();
if (GetHookRect().IsEmpty() && presContext) {
nsITheme *theme = presContext->GetTheme();
if (theme && theme->ThemeSupportsWidget(presContext, aForFrame, NS_THEME_TEXTFIELD_CARET)) {
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;
}
}
}
- aCtx->SetColor(cssColor);
+ aCtx->SetColor(foregroundColor);
aCtx->FillRect(drawCaretRect);
if (!GetHookRect().IsEmpty())
aCtx->FillRect(GetHookRect() + aOffset);
}
//-----------------------------------------------------------------------------
NS_IMETHODIMP nsCaret::NotifySelectionChanged(nsIDOMDocument *, nsISelection *aDomSel, PRInt16 aReason)
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -131,18 +131,20 @@ class nsCaret : public nsISelectionListe
* Note: This call breaks the caret's ability to blink at all.
**/
nsresult DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset);
/** GetCaretFrame
* 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
* non-null.
*/
nsRect GetCaretRect()
{
nsRect r;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -968,16 +968,23 @@ nsIFrame::DisplayCaret(nsDisplayListBuil
{
if (!IsVisibleForPainting(aBuilder))
return NS_OK;
return aList->AppendNewToTop(
new (aBuilder) nsDisplayCaret(this, aBuilder->GetCaret()));
}
+nscolor
+nsIFrame::GetCaretColorAt(PRInt32 aOffset)
+{
+ // Use text color.
+ return GetStyleColor()->mColor;
+}
+
PRBool
nsIFrame::HasBorder() const
{
// Border images contribute to the background of the content area
// even if there's no border proper.
return (GetUsedBorder() != nsMargin(0,0,0,0) ||
GetStyleBorder()->IsBorderImageLoaded());
}
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -972,16 +972,23 @@ public:
* painted on top of the rest of the display list items.
*
* @param aDirtyRect is the dirty rectangle that we're repainting.
*/
nsresult DisplayCaret(nsDisplayListBuilder* aBuilder,
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);
}
PRBool IsThemed(const nsStyleDisplay* aDisp,
nsTransparencyMode* aTransparencyMode = nsnull) {
if (!aDisp->mAppearance)
return PR_FALSE;
nsPresContext* pc = PresContext();
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -302,16 +302,18 @@ public:
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails,
SelectionType aSelectionType);
+ virtual nscolor GetCaretColorAt(PRInt32 aOffset);
+
PRInt16 GetSelectionStatus(PRInt16* aSelectionFlags);
#ifdef DEBUG
void ToCString(nsCString& aBuf, PRInt32* aTotalContentLength) const;
#endif
PRInt32 GetContentOffset() const { return mContentOffset; }
PRInt32 GetContentLength() const
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -4712,16 +4712,58 @@ nsTextFrame::PaintTextWithSelection(gfxC
aProvider, aTextPaintStyle, details, type);
}
}
DestroySelectionDetails(details);
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)
{
gfxSkipCharsIterator iter(aProvider.GetStart());
PRUint32 start = iter.GetSkippedOffset();
iter.AdvanceOriginal(aProvider.GetOriginalLength());
return iter.GetSkippedOffset() - start;
}