Bug 655877 - Part 26: Give nsTextFrames the ability to invoke callbacks after painting different parts of the text. r=roc

This commit is contained in:
Cameron McCormack 2012-08-08 21:37:12 +10:00
parent a30b13e813
commit 42d55dff42
2 changed files with 287 additions and 87 deletions

View File

@ -274,10 +274,86 @@ public:
PRUint32* aStartOffset, PRUint32* aMaxLength, PRUint32* aStartOffset, PRUint32* aMaxLength,
nscoord* aSnappedLeftEdge, nscoord* aSnappedLeftEdge,
nscoord* aSnappedRightEdge); nscoord* aSnappedRightEdge);
// primary frame paint method called from nsDisplayText
// The private DrawText() is what applies the text to a graphics context /**
* Object with various callbacks for PaintText() to invoke for different parts
* of the frame's text rendering, when we're generating paths rather than
* painting.
*
* Callbacks are invoked in the following order:
*
* (NotifyBeforeSelectionBackground NotifySelectionBackgroundPathEmitted)?
* (NotifyBeforeDecorationLine NotifyDecorationLinePathEmitted)*
* NotifyBeforeText
* NotifyGlyphPathEmitted*
* NotifyAfterText
* (NotifyBeforeDecorationLine NotifyDecorationLinePathEmitted)*
* (NotifyBeforeSelectionDecorationLine NotifySelectionDecorationLinePathEmitted)*
*
* The color of each part of the frame's text rendering is passed as an argument
* to the NotifyBefore* callback for that part. The nscolor can take on one of
* the three selection special colors defined in LookAndFeel.h --
* NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR and
* NS_40PERCENT_FOREGROUND_COLOR.
*/
struct DrawPathCallbacks : gfxTextRun::DrawCallbacks
{
/**
* Called just before any paths have been emitted to the gfxContext
* for the glyphs of the frame's text.
*/
virtual void NotifyBeforeText(nscolor aColor) { }
/**
* Called just after all the paths have been emitted to the gfxContext
* for the glyphs of the frame's text.
*/
virtual void NotifyAfterText() { }
/**
* Called just before a path corresponding to the selection background
* has been emitted to the gfxContext.
*/
virtual void NotifyBeforeSelectionBackground(nscolor aColor) { }
/**
* Called just after a path corresponding to the selection background
* has been emitted to the gfxContext.
*/
virtual void NotifySelectionBackgroundPathEmitted() { }
/**
* Called just before a path corresponding to a text decoration line
* has been emitted to the gfxContext.
*/
virtual void NotifyBeforeDecorationLine(nscolor aColor) { }
/**
* Called just after a path corresponding to a text decoration line
* has been emitted to the gfxContext.
*/
virtual void NotifyDecorationLinePathEmitted() { }
/**
* Called just before a path corresponding to a selection decoration line
* has been emitted to the gfxContext.
*/
virtual void NotifyBeforeSelectionDecorationLine(nscolor aColor) { }
/**
* Called just after a path corresponding to a selection decoration line
* has been emitted to the gfxContext.
*/
virtual void NotifySelectionDecorationLinePathEmitted() { }
};
// Primary frame paint method called from nsDisplayText. Can also be used
// to generate paths rather than paint the frame's text by passing a callback
// object. The private DrawText() is what applies the text to a graphics
// context.
void PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, void PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect, const nsCharClipDisplayItem& aItem); const nsRect& aDirtyRect, const nsCharClipDisplayItem& aItem,
DrawPathCallbacks* aCallbacks = nullptr);
// helper: paint text frame when we're impacted by at least one selection. // helper: paint text frame when we're impacted by at least one selection.
// Return false if the text was not painted and we should continue with // Return false if the text was not painted and we should continue with
// the fast path. // the fast path.
@ -289,7 +365,8 @@ public:
PRUint32 aContentOffset, PRUint32 aContentOffset,
PRUint32 aContentLength, PRUint32 aContentLength,
nsTextPaintStyle& aTextPaintStyle, nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges); const nsCharClipDisplayItem::ClipEdges& aClipEdges,
DrawPathCallbacks* aCallbacks);
// helper: paint text with foreground and background colors determined // helper: paint text with foreground and background colors determined
// by selection(s). Also computes a mask of all selection types applying to // by selection(s). Also computes a mask of all selection types applying to
// our text, returned in aAllTypes. // our text, returned in aAllTypes.
@ -305,7 +382,8 @@ public:
nsTextPaintStyle& aTextPaintStyle, nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails, SelectionDetails* aDetails,
SelectionType* aAllTypes, SelectionType* aAllTypes,
const nsCharClipDisplayItem::ClipEdges& aClipEdges); const nsCharClipDisplayItem::ClipEdges& aClipEdges,
DrawPathCallbacks* aCallbacks);
// helper: paint text decorations for text selected by aSelectionType // helper: paint text decorations for text selected by aSelectionType
void PaintTextSelectionDecorations(gfxContext* aCtx, void PaintTextSelectionDecorations(gfxContext* aCtx,
const gfxPoint& aFramePt, const gfxPoint& aFramePt,
@ -316,7 +394,8 @@ public:
PRUint32 aContentLength, PRUint32 aContentLength,
nsTextPaintStyle& aTextPaintStyle, nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails, SelectionDetails* aDetails,
SelectionType aSelectionType); SelectionType aSelectionType,
DrawPathCallbacks* aCallbacks);
virtual nscolor GetCaretColorAt(PRInt32 aOffset); virtual nscolor GetCaretColorAt(PRInt32 aOffset);
@ -526,8 +605,10 @@ protected:
PRUint32 aOffset, PRUint32 aOffset,
PRUint32 aLength, PRUint32 aLength,
PropertyProvider& aProvider, PropertyProvider& aProvider,
nscolor aTextColor,
gfxFloat& aAdvanceWidth, gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen); bool aDrawSoftHyphen,
DrawPathCallbacks* aCallbacks);
void DrawTextRunAndDecorations(gfxContext* const aCtx, void DrawTextRunAndDecorations(gfxContext* const aCtx,
const gfxRect& aDirtyRect, const gfxRect& aDirtyRect,
@ -537,11 +618,13 @@ protected:
PRUint32 aLength, PRUint32 aLength,
PropertyProvider& aProvider, PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle, const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges, const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth, gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen, bool aDrawSoftHyphen,
const TextDecorations& aDecorations, const TextDecorations& aDecorations,
const nscolor* const aDecorationOverrideColor); const nscolor* const aDecorationOverrideColor,
DrawPathCallbacks* aCallbacks);
void DrawText(gfxContext* const aCtx, void DrawText(gfxContext* const aCtx,
const gfxRect& aDirtyRect, const gfxRect& aDirtyRect,
@ -551,10 +634,12 @@ protected:
PRUint32 aLength, PRUint32 aLength,
PropertyProvider& aProvider, PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle, const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges, const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth, gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen, bool aDrawSoftHyphen,
const nscolor* const aDecorationOverrideColor = nullptr); const nscolor* const aDecorationOverrideColor = nullptr,
DrawPathCallbacks* aCallbacks = nullptr);
// Set non empty rect to aRect, it should be overflow rect or frame rect. // Set non empty rect to aRect, it should be overflow rect or frame rect.
// If the result rect is larger than the given rect, this returns true. // If the result rect is larger than the given rect, this returns true.

View File

@ -278,6 +278,12 @@ class nsTextPaintStyle {
public: public:
nsTextPaintStyle(nsTextFrame* aFrame); nsTextPaintStyle(nsTextFrame* aFrame);
void SetResolveColors(bool aResolveColors) {
NS_ASSERTION(mFrame->IsSVGText() || aResolveColors,
"must resolve colors is frame is not for SVG text");
mResolveColors = aResolveColors;
}
nscolor GetTextColor(); nscolor GetTextColor();
/** /**
* Compute the colors for normally-selected text. Returns false if * Compute the colors for normally-selected text. Returns false if
@ -342,6 +348,7 @@ protected:
nsPresContext* mPresContext; nsPresContext* mPresContext;
bool mInitCommonColors; bool mInitCommonColors;
bool mInitSelectionColorsAndShadow; bool mInitSelectionColorsAndShadow;
bool mResolveColors;
// Selection data // Selection data
@ -356,9 +363,10 @@ protected:
PRInt32 mSufficientContrast; PRInt32 mSufficientContrast;
nscolor mFrameBackgroundColor; nscolor mFrameBackgroundColor;
// selection colors and underline info, the colors are resolved colors, // selection colors and underline info, the colors are resolved colors if
// i.e., the foreground color and background color are swapped if it's needed. // mResolveColors is true (which is the default), i.e., the foreground color
// And also line color will be resolved from them. // and background color are swapped if it's needed. And also line color will
// be resolved from them.
struct nsSelectionStyle { struct nsSelectionStyle {
bool mInit; bool mInit;
nscolor mTextColor; nscolor mTextColor;
@ -3401,6 +3409,7 @@ nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
mPresContext(aFrame->PresContext()), mPresContext(aFrame->PresContext()),
mInitCommonColors(false), mInitCommonColors(false),
mInitSelectionColorsAndShadow(false), mInitSelectionColorsAndShadow(false),
mResolveColors(true),
mHasSelectionShadow(false) mHasSelectionShadow(false)
{ {
for (PRUint32 i = 0; i < ArrayLength(mSelectionStyle); i++) for (PRUint32 i = 0; i < ArrayLength(mSelectionStyle); i++)
@ -3642,6 +3651,7 @@ nsTextPaintStyle::InitSelectionColorsAndShadow()
mSelectionTextColor = mSelectionTextColor =
LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForeground); LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForeground);
if (mResolveColors) {
// On MacOS X, we don't exchange text color and BG color. // On MacOS X, we don't exchange text color and BG color.
if (mSelectionTextColor == NS_DONT_CHANGE_COLOR) { if (mSelectionTextColor == NS_DONT_CHANGE_COLOR) {
nscolor frameColor = mFrame->GetVisitedDependentColor(eCSSProperty_color); nscolor frameColor = mFrame->GetVisitedDependentColor(eCSSProperty_color);
@ -3649,6 +3659,11 @@ nsTextPaintStyle::InitSelectionColorsAndShadow()
} else { } else {
EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor); EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
} }
} else {
if (mSelectionTextColor == NS_DONT_CHANGE_COLOR) {
mSelectionTextColor = NS_SAME_AS_FOREGROUND_COLOR;
}
}
return true; return true;
} }
@ -3722,16 +3737,20 @@ nsTextPaintStyle::InitSelectionStyle(PRInt32 aIndex)
NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR, NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR,
"backColor cannot be NS_40PERCENT_FOREGROUND_COLOR"); "backColor cannot be NS_40PERCENT_FOREGROUND_COLOR");
if (mResolveColors) {
foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor); foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor);
if (NS_GET_A(backColor) > 0) if (NS_GET_A(backColor) > 0)
EnsureSufficientContrast(&foreColor, &backColor); EnsureSufficientContrast(&foreColor, &backColor);
}
nscolor lineColor; nscolor lineColor;
float relativeSize; float relativeSize;
PRUint8 lineStyle; PRUint8 lineStyle;
GetSelectionUnderline(mPresContext, aIndex, GetSelectionUnderline(mPresContext, aIndex,
&lineColor, &relativeSize, &lineStyle); &lineColor, &relativeSize, &lineStyle);
if (mResolveColors)
lineColor = GetResolvedForeColor(lineColor, foreColor, backColor); lineColor = GetResolvedForeColor(lineColor, foreColor, backColor);
selectionStyle->mTextColor = foreColor; selectionStyle->mTextColor = foreColor;
@ -4536,9 +4555,15 @@ nsTextFrame::GetSelectionDetails()
} }
static void static void
FillClippedRect(gfxContext* aCtx, nsPresContext* aPresContext, PaintSelectionBackground(gfxContext* aCtx, nsPresContext* aPresContext,
nscolor aColor, const gfxRect& aDirtyRect, const gfxRect& aRect) nscolor aColor, const gfxRect& aDirtyRect,
const gfxRect& aRect,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
if (aCallbacks) {
aCallbacks->NotifyBeforeSelectionBackground(aColor);
}
gfxRect r = aRect.Intersect(aDirtyRect); gfxRect r = aRect.Intersect(aDirtyRect);
// For now, we need to put this in pixel coordinates // For now, we need to put this in pixel coordinates
PRInt32 app = aPresContext->AppUnitsPerDevPixel(); PRInt32 app = aPresContext->AppUnitsPerDevPixel();
@ -4546,9 +4571,14 @@ FillClippedRect(gfxContext* aCtx, nsPresContext* aPresContext,
// pixel-snap // pixel-snap
aCtx->Rectangle(gfxRect(r.X() / app, r.Y() / app, aCtx->Rectangle(gfxRect(r.X() / app, r.Y() / app,
r.Width() / app, r.Height() / app), true); r.Width() / app, r.Height() / app), true);
if (aCallbacks) {
aCallbacks->NotifySelectionBackgroundPathEmitted();
} else {
aCtx->SetColor(gfxRGBA(aColor)); aCtx->SetColor(gfxRGBA(aColor));
aCtx->Fill(); aCtx->Fill();
} }
}
void void
nsTextFrame::GetTextDecorations(nsPresContext* aPresContext, nsTextFrame::GetTextDecorations(nsPresContext* aPresContext,
@ -4848,6 +4878,50 @@ ComputeSelectionUnderlineHeight(nsPresContext* aPresContext,
} }
} }
enum DecorationType {
eNormalDecoration,
eSelectionDecoration
};
static void
PaintDecorationLine(nsIFrame* aFrame,
gfxContext* const aCtx,
const gfxRect& aDirtyRect,
nscolor aColor,
const nscolor* aOverrideColor,
const gfxPoint& aPt,
gfxFloat aXInFrame,
const gfxSize& aLineSize,
gfxFloat aAscent,
gfxFloat aOffset,
PRUint8 aDecoration,
PRUint8 aStyle,
DecorationType aDecorationType,
nsTextFrame::DrawPathCallbacks* aCallbacks,
gfxFloat aDescentLimit = -1.0)
{
nscolor lineColor = aOverrideColor ? *aOverrideColor : aColor;
if (aCallbacks) {
if (aDecorationType == eNormalDecoration) {
aCallbacks->NotifyBeforeDecorationLine(lineColor);
} else {
aCallbacks->NotifyBeforeSelectionDecorationLine(lineColor);
}
nsCSSRendering::DecorationLineToPath(aFrame, aCtx, aDirtyRect, lineColor,
aPt, aXInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
aDescentLimit);
if (aDecorationType == eNormalDecoration) {
aCallbacks->NotifyDecorationLinePathEmitted();
} else {
aCallbacks->NotifySelectionDecorationLinePathEmitted();
}
} else {
nsCSSRendering::PaintDecorationLine(aFrame, aCtx, aDirtyRect, lineColor,
aPt, aXInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
aDescentLimit);
}
}
/** /**
* This, plus SelectionTypesWithDecorations, encapsulates all knowledge about * This, plus SelectionTypesWithDecorations, encapsulates all knowledge about
* drawing text decoration for selections. * drawing text decoration for selections.
@ -4859,7 +4933,8 @@ static void DrawSelectionDecorations(gfxContext* aContext,
nsTextPaintStyle& aTextPaintStyle, nsTextPaintStyle& aTextPaintStyle,
const nsTextRangeStyle &aRangeStyle, const nsTextRangeStyle &aRangeStyle,
const gfxPoint& aPt, gfxFloat aXInFrame, gfxFloat aWidth, const gfxPoint& aPt, gfxFloat aXInFrame, gfxFloat aWidth,
gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics) gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
gfxPoint pt(aPt); gfxPoint pt(aPt);
gfxSize size(aWidth, gfxSize size(aWidth,
@ -4935,9 +5010,10 @@ static void DrawSelectionDecorations(gfxContext* aContext,
return; return;
} }
size.height *= relativeSize; size.height *= relativeSize;
nsCSSRendering::PaintDecorationLine(aFrame, aContext, aDirtyRect, color, pt, PaintDecorationLine(aFrame, aContext, aDirtyRect, color, nullptr, pt,
pt.x - aPt.x + aXInFrame, size, aAscent, aFontMetrics.underlineOffset, pt.x - aPt.x + aXInFrame, size, aAscent, aFontMetrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, style, descentLimit); NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, style, eSelectionDecoration,
aCallbacks, descentLimit);
} }
/** /**
@ -5188,7 +5264,7 @@ nsTextFrame::PaintOneShadow(PRUint32 aOffset, PRUint32 aLength,
aDirtyRect.width, aDirtyRect.height); aDirtyRect.width, aDirtyRect.height);
DrawText(shadowContext, dirtyRect, aFramePt + shadowOffset, DrawText(shadowContext, dirtyRect, aFramePt + shadowOffset,
aTextBaselinePt + shadowOffset, aOffset, aLength, *aProvider, aTextBaselinePt + shadowOffset, aOffset, aLength, *aProvider,
nsTextPaintStyle(this), aClipEdges, advanceWidth, nsTextPaintStyle(this), shadowColor, aClipEdges, advanceWidth,
(GetStateBits() & TEXT_HYPHEN_BREAK) != 0, decorationOverrideColor); (GetStateBits() & TEXT_HYPHEN_BREAK) != 0, decorationOverrideColor);
contextBoxBlur.DoPaint(); contextBoxBlur.DoPaint();
@ -5205,7 +5281,8 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
PRUint32 aContentOffset, PRUint32 aContentLength, PRUint32 aContentOffset, PRUint32 aContentLength,
nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
SelectionType* aAllTypes, SelectionType* aAllTypes,
const nsCharClipDisplayItem::ClipEdges& aClipEdges) const nsCharClipDisplayItem::ClipEdges& aClipEdges,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
// Figure out which selections control the colors to use for each character. // Figure out which selections control the colors to use for each character.
AutoFallibleTArray<SelectionDetails*,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer; AutoFallibleTArray<SelectionDetails*,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer;
@ -5273,9 +5350,10 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
mTextRun->GetAdvanceWidth(offset, length, &aProvider); mTextRun->GetAdvanceWidth(offset, length, &aProvider);
if (NS_GET_A(background) > 0) { if (NS_GET_A(background) > 0) {
gfxFloat x = xOffset - (mTextRun->IsRightToLeft() ? advance : 0); gfxFloat x = xOffset - (mTextRun->IsRightToLeft() ? advance : 0);
FillClippedRect(aCtx, aTextPaintStyle.PresContext(), PaintSelectionBackground(aCtx, aTextPaintStyle.PresContext(),
background, aDirtyRect, background, aDirtyRect,
gfxRect(aFramePt.x + x, aFramePt.y, advance, GetSize().height)); gfxRect(aFramePt.x + x, aFramePt.y, advance,
GetSize().height), aCallbacks);
} }
iterator.UpdateWithAdvance(advance); iterator.UpdateWithAdvance(advance);
} }
@ -5320,12 +5398,11 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
} }
// Draw text segment // Draw text segment
aCtx->SetColor(gfxRGBA(foreground));
gfxFloat advance; gfxFloat advance;
DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt, DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
offset, length, aProvider, aTextPaintStyle, aClipEdges, advance, offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
hyphenWidth > 0); advance, hyphenWidth > 0, nullptr, aCallbacks);
if (hyphenWidth) { if (hyphenWidth) {
advance += hyphenWidth; advance += hyphenWidth;
} }
@ -5341,7 +5418,8 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
PropertyProvider& aProvider, PropertyProvider& aProvider,
PRUint32 aContentOffset, PRUint32 aContentLength, PRUint32 aContentOffset, PRUint32 aContentLength,
nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
SelectionType aSelectionType) SelectionType aSelectionType,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
// Hide text decorations if we're currently hiding @font-face fallback text // Hide text decorations if we're currently hiding @font-face fallback text
if (aProvider.GetFontGroup()->ShouldSkipDrawing()) if (aProvider.GetFontGroup()->ShouldSkipDrawing())
@ -5401,7 +5479,8 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
gfxFloat xInFrame = pt.x - (aFramePt.x / app); gfxFloat xInFrame = pt.x - (aFramePt.x / app);
DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this, DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this,
aTextPaintStyle, selectedStyle, pt, xInFrame, aTextPaintStyle, selectedStyle, pt, xInFrame,
width, mAscent / app, decorationMetrics); width, mAscent / app, decorationMetrics,
aCallbacks);
} }
iterator.UpdateWithAdvance(advance); iterator.UpdateWithAdvance(advance);
} }
@ -5414,7 +5493,8 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
PropertyProvider& aProvider, PropertyProvider& aProvider,
PRUint32 aContentOffset, PRUint32 aContentLength, PRUint32 aContentOffset, PRUint32 aContentLength,
nsTextPaintStyle& aTextPaintStyle, nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges) const nsCharClipDisplayItem::ClipEdges& aClipEdges,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
NS_ASSERTION(GetContent()->IsSelectionDescendant(), "wrong paint path"); NS_ASSERTION(GetContent()->IsSelectionDescendant(), "wrong paint path");
@ -5427,7 +5507,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect, if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
aProvider, aContentOffset, aContentLength, aProvider, aContentOffset, aContentLength,
aTextPaintStyle, details, &allTypes, aTextPaintStyle, details, &allTypes,
aClipEdges)) { aClipEdges, aCallbacks)) {
DestroySelectionDetails(details); DestroySelectionDetails(details);
return false; return false;
} }
@ -5445,7 +5525,8 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
// PaintTextSelectionDecorations will exit early). // PaintTextSelectionDecorations will exit early).
PaintTextSelectionDecorations(aCtx, aFramePt, aTextBaselinePt, aDirtyRect, PaintTextSelectionDecorations(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
aProvider, aContentOffset, aContentLength, aProvider, aContentOffset, aContentLength,
aTextPaintStyle, details, type); aTextPaintStyle, details, type,
aCallbacks);
} }
} }
@ -5610,7 +5691,8 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
void void
nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect, const nsRect& aDirtyRect,
const nsCharClipDisplayItem& aItem) const nsCharClipDisplayItem& aItem,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
// Don't pass in aRenderingContext here, because we need a *reference* // Don't pass in aRenderingContext here, because we need a *reference*
// context and aRenderingContext might have some transform in it // context and aRenderingContext might have some transform in it
@ -5640,6 +5722,7 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge, nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge,
snappedRightEdge); snappedRightEdge);
nsTextPaintStyle textPaintStyle(this); nsTextPaintStyle textPaintStyle(this);
textPaintStyle.SetResolveColors(!aCallbacks);
gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y, gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height); aDirtyRect.width, aDirtyRect.height);
@ -5651,12 +5734,13 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset; tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset;
if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect, if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect,
provider, contentOffset, contentLength, provider, contentOffset, contentLength,
textPaintStyle, clipEdges)) { textPaintStyle, clipEdges, aCallbacks)) {
return; return;
} }
} }
nscolor foregroundColor = textPaintStyle.GetTextColor(); nscolor foregroundColor = textPaintStyle.GetTextColor();
if (!aCallbacks) {
const nsStyleText* textStyle = GetStyleText(); const nsStyleText* textStyle = GetStyleText();
if (textStyle->mTextShadow) { if (textStyle->mTextShadow) {
// Text shadow happens with the last value being painted at the back, // Text shadow happens with the last value being painted at the back,
@ -5672,13 +5756,37 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
snappedLeftEdge, shadowMetrics.mBoundingBox); snappedLeftEdge, shadowMetrics.mBoundingBox);
} }
} }
}
ctx->SetColor(gfxRGBA(foregroundColor));
gfxFloat advanceWidth; gfxFloat advanceWidth;
DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider, DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider,
textPaintStyle, clipEdges, advanceWidth, textPaintStyle, foregroundColor, clipEdges, advanceWidth,
(GetStateBits() & TEXT_HYPHEN_BREAK) != 0); (GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
nullptr, aCallbacks);
}
static void
DrawTextRun(gfxTextRun* aTextRun,
gfxContext* const aCtx,
const gfxPoint& aTextBaselinePt,
PRUint32 aOffset, PRUint32 aLength,
PropertyProvider* aProvider,
nscolor aTextColor,
gfxFloat* aAdvanceWidth,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
gfxFont::DrawMode drawMode = aCallbacks ? gfxFont::GLYPH_PATH :
gfxFont::GLYPH_FILL;
if (aCallbacks) {
aCallbacks->NotifyBeforeText(aTextColor);
aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
aProvider, aAdvanceWidth, nullptr, aCallbacks);
aCallbacks->NotifyAfterText();
} else {
aCtx->SetColor(gfxRGBA(aTextColor));
aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
aProvider, aAdvanceWidth, nullptr);
}
} }
void void
@ -5686,11 +5794,13 @@ nsTextFrame::DrawTextRun(gfxContext* const aCtx,
const gfxPoint& aTextBaselinePt, const gfxPoint& aTextBaselinePt,
PRUint32 aOffset, PRUint32 aLength, PRUint32 aOffset, PRUint32 aLength,
PropertyProvider& aProvider, PropertyProvider& aProvider,
nscolor aTextColor,
gfxFloat& aAdvanceWidth, gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen) bool aDrawSoftHyphen,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
mTextRun->Draw(aCtx, aTextBaselinePt, gfxFont::GLYPH_FILL, aOffset, aLength, ::DrawTextRun(mTextRun, aCtx, aTextBaselinePt, aOffset, aLength, &aProvider,
&aProvider, &aAdvanceWidth, nullptr); aTextColor, &aAdvanceWidth, aCallbacks);
if (aDrawSoftHyphen) { if (aDrawSoftHyphen) {
// Don't use ctx as the context, because we need a reference context here, // Don't use ctx as the context, because we need a reference context here,
@ -5701,9 +5811,10 @@ nsTextFrame::DrawTextRun(gfxContext* const aCtx,
// of the text, minus its own width // of the text, minus its own width
gfxFloat hyphenBaselineX = aTextBaselinePt.x + mTextRun->GetDirection() * aAdvanceWidth - gfxFloat hyphenBaselineX = aTextBaselinePt.x + mTextRun->GetDirection() * aAdvanceWidth -
(mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nullptr) : 0); (mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nullptr) : 0);
hyphenTextRun->Draw(aCtx, gfxPoint(hyphenBaselineX, aTextBaselinePt.y), ::DrawTextRun(hyphenTextRun.get(), aCtx,
gfxFont::GLYPH_FILL, 0, hyphenTextRun->GetLength(), gfxPoint(hyphenBaselineX, aTextBaselinePt.y),
nullptr, nullptr, nullptr); 0, hyphenTextRun->GetLength(),
nullptr, aTextColor, nullptr, aCallbacks);
} }
} }
} }
@ -5715,11 +5826,13 @@ nsTextFrame::DrawTextRunAndDecorations(
PRUint32 aOffset, PRUint32 aLength, PRUint32 aOffset, PRUint32 aLength,
PropertyProvider& aProvider, PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle, const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges, const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth, gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen, bool aDrawSoftHyphen,
const TextDecorations& aDecorations, const TextDecorations& aDecorations,
const nscolor* const aDecorationOverrideColor) const nscolor* const aDecorationOverrideColor,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel(); const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel();
@ -5751,10 +5864,10 @@ nsTextFrame::DrawTextRunAndDecorations(
decSize.height = metrics.underlineSize; decSize.height = metrics.underlineSize;
decPt.y = (frameTop - dec.mBaselineOffset) / app; decPt.y = (frameTop - dec.mBaselineOffset) / app;
const nscolor lineColor = aDecorationOverrideColor ? *aDecorationOverrideColor : dec.mColor; PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
nsCSSRendering::PaintDecorationLine(this, aCtx, dirtyRect, lineColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
decPt, 0.0, decSize, ascent, metrics.underlineOffset, metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, dec.mStyle); dec.mStyle, eNormalDecoration, aCallbacks);
} }
// Overlines // Overlines
for (PRUint32 i = aDecorations.mOverlines.Length(); i-- > 0; ) { for (PRUint32 i = aDecorations.mOverlines.Length(); i-- > 0; ) {
@ -5768,16 +5881,16 @@ nsTextFrame::DrawTextRunAndDecorations(
decSize.height = metrics.underlineSize; decSize.height = metrics.underlineSize;
decPt.y = (frameTop - dec.mBaselineOffset) / app; decPt.y = (frameTop - dec.mBaselineOffset) / app;
const nscolor lineColor = aDecorationOverrideColor ? *aDecorationOverrideColor : dec.mColor; PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
nsCSSRendering::PaintDecorationLine(this, aCtx, dirtyRect, lineColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
decPt, 0.0, decSize, ascent, metrics.maxAscent, metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle); eNormalDecoration, aCallbacks);
} }
// CSS 2.1 mandates that text be painted after over/underlines, and *then* // CSS 2.1 mandates that text be painted after over/underlines, and *then*
// line-throughs // line-throughs
DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aAdvanceWidth, DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor,
aDrawSoftHyphen); aAdvanceWidth, aDrawSoftHyphen, aCallbacks);
// Line-throughs // Line-throughs
for (PRUint32 i = aDecorations.mStrikes.Length(); i-- > 0; ) { for (PRUint32 i = aDecorations.mStrikes.Length(); i-- > 0; ) {
@ -5791,10 +5904,10 @@ nsTextFrame::DrawTextRunAndDecorations(
decSize.height = metrics.strikeoutSize; decSize.height = metrics.strikeoutSize;
decPt.y = (frameTop - dec.mBaselineOffset) / app; decPt.y = (frameTop - dec.mBaselineOffset) / app;
const nscolor lineColor = aDecorationOverrideColor ? *aDecorationOverrideColor : dec.mColor; PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
nsCSSRendering::PaintDecorationLine(this, aCtx, dirtyRect, lineColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
decPt, 0.0, decSize, ascent, metrics.strikeoutOffset, metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, dec.mStyle); dec.mStyle, eNormalDecoration, aCallbacks);
} }
} }
@ -5805,10 +5918,12 @@ nsTextFrame::DrawText(
PRUint32 aOffset, PRUint32 aLength, PRUint32 aOffset, PRUint32 aLength,
PropertyProvider& aProvider, PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle, const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges, const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth, gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen, bool aDrawSoftHyphen,
const nscolor* const aDecorationOverrideColor) const nscolor* const aDecorationOverrideColor,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{ {
TextDecorations decorations; TextDecorations decorations;
GetTextDecorations(aTextStyle.PresContext(), decorations); GetTextDecorations(aTextStyle.PresContext(), decorations);
@ -5818,12 +5933,12 @@ nsTextFrame::DrawText(
decorations.HasDecorationLines(); decorations.HasDecorationLines();
if (drawDecorations) { if (drawDecorations) {
DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aOffset, aLength, DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aOffset, aLength,
aProvider, aTextStyle, aClipEdges, aAdvanceWidth, aProvider, aTextStyle, aTextColor, aClipEdges, aAdvanceWidth,
aDrawSoftHyphen, decorations, aDrawSoftHyphen, decorations,
aDecorationOverrideColor); aDecorationOverrideColor, aCallbacks);
} else { } else {
DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider,
aAdvanceWidth, aDrawSoftHyphen); aTextColor, aAdvanceWidth, aDrawSoftHyphen, aCallbacks);
} }
} }