Bug 655877 - Part 46: Paint SVG glyphs with new SVG text frame. r=roc,jwatt

This commit is contained in:
Cameron McCormack 2013-02-11 17:22:20 +11:00
parent c09bbacdbf
commit 0335ceedb4
13 changed files with 653 additions and 222 deletions

View File

@ -1667,40 +1667,46 @@ struct GlyphBufferAzure {
nsRefPtr<gfxPattern> fillPattern;
if (!aObjectPaint ||
!(fillPattern = aObjectPaint->GetFillPattern(aThebesContext->CurrentMatrix()))) {
pat = state.pattern->GetPattern(aDT, state.patternTransformChanged ? &state.patternTransform : nullptr);
if (state.pattern) {
pat = state.pattern->GetPattern(aDT, state.patternTransformChanged ? &state.patternTransform : nullptr);
} else {
pat = nullptr;
}
} else {
pat = fillPattern->GetPattern(aDT);
}
Matrix saved;
Matrix *mat = nullptr;
if (aInvFontMatrix) {
// The brush matrix needs to be multiplied with the inverted matrix
// as well, to move the brush into the space of the glyphs. Before
// the render target transformation
if (pat) {
Matrix saved;
Matrix *mat = nullptr;
if (aInvFontMatrix) {
// The brush matrix needs to be multiplied with the inverted matrix
// as well, to move the brush into the space of the glyphs. Before
// the render target transformation
// This relies on the returned Pattern not to be reused by
// others, but regenerated on GetPattern calls. This is true!
if (pat->GetType() == PATTERN_LINEAR_GRADIENT) {
mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
} else if (pat->GetType() == PATTERN_RADIAL_GRADIENT) {
mat = &static_cast<RadialGradientPattern*>(pat)->mMatrix;
} else if (pat->GetType() == PATTERN_SURFACE) {
mat = &static_cast<SurfacePattern*>(pat)->mMatrix;
// This relies on the returned Pattern not to be reused by
// others, but regenerated on GetPattern calls. This is true!
if (pat->GetType() == PATTERN_LINEAR_GRADIENT) {
mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
} else if (pat->GetType() == PATTERN_RADIAL_GRADIENT) {
mat = &static_cast<RadialGradientPattern*>(pat)->mMatrix;
} else if (pat->GetType() == PATTERN_SURFACE) {
mat = &static_cast<SurfacePattern*>(pat)->mMatrix;
}
if (mat) {
saved = *mat;
*mat = (*mat) * (*aInvFontMatrix);
}
}
aDT->FillGlyphs(aFont, buf, *pat,
aDrawOptions, aOptions);
if (mat) {
saved = *mat;
*mat = (*mat) * (*aInvFontMatrix);
*mat = saved;
}
}
aDT->FillGlyphs(aFont, buf, *pat,
aDrawOptions, aOptions);
if (mat) {
*mat = saved;
}
} else if (state.sourceSurface) {
aDT->FillGlyphs(aFont, buf, SurfacePattern(state.sourceSurface,
EXTEND_CLAMP,
@ -1768,10 +1774,19 @@ gfxFont::CalcXScale(gfxContext *aContext)
return 1.0 / m;
}
static gfxFont::DrawMode
ForcePaintingDrawMode(gfxFont::DrawMode aDrawMode)
{
return aDrawMode == gfxFont::GLYPH_PATH ?
gfxFont::DrawMode(gfxFont::GLYPH_FILL | gfxFont::GLYPH_STROKE) :
aDrawMode;
}
void
gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aPt,
Spacing *aSpacing, gfxTextObjectPaint *aObjectPaint)
Spacing *aSpacing, gfxTextObjectPaint *aObjectPaint,
gfxTextRunDrawCallbacks *aCallbacks)
{
NS_ASSERTION(aDrawMode == gfxFont::GLYPH_PATH || !(aDrawMode & gfxFont::GLYPH_PATH),
"GLYPH_PATH cannot be used with GLYPH_FILL, GLYPH_STROKE or GLYPH_STROKE_UNDERNEATH");
@ -1816,6 +1831,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
cairo_t *cr = aContext->GetCairo();
RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
bool paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
bool emittedGlyphs = false;
if (aContext->IsCairo()) {
bool success = SetupCairoFont(aContext);
if (MOZ_UNLIKELY(!success))
@ -1841,11 +1859,15 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
}
if (haveSVGGlyphs) {
if (!paintSVGGlyphs) {
continue;
}
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
ToDeviceUnits(y, devUnitsPerAppUnit));
if (RenderSVGGlyph(aContext, point, aDrawMode,
glyphData->GetSimpleGlyph(),
aObjectPaint)) {
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
glyphData->GetSimpleGlyph(), aObjectPaint,
aCallbacks, emittedGlyphs)) {
continue;
}
}
@ -1878,14 +1900,16 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
} while (--strikeCount > 0);
}
emittedGlyphs = true;
} else {
uint32_t glyphCount = glyphData->GetGlyphCount();
if (glyphCount > 0) {
const gfxTextRun::DetailedGlyph *details =
aTextRun->GetDetailedGlyphs(i);
NS_ASSERTION(details, "detailedGlyph should not be missing!");
for (uint32_t j = 0; j < glyphCount; ++j, ++details) {
double advance = details->mAdvance;
double advance;
for (uint32_t j = 0; j < glyphCount; ++j, ++details, x += direction * advance) {
advance = details->mAdvance;
if (glyphData->IsMissing()) {
// default ignorable characters will have zero advance width.
// we don't have to draw the hexbox for them
@ -1913,34 +1937,43 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
ToDeviceUnits(y, devUnitsPerAppUnit));
if (!haveSVGGlyphs ||
!RenderSVGGlyph(aContext, point, aDrawMode,
details->mGlyphID, aObjectPaint)) {
glyph = glyphs.AppendGlyph();
glyph->index = details->mGlyphID;
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
int32_t strikeCount = strikes;
do {
cairo_glyph_t *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->index = glyph->index;
doubleglyph->x =
ToDeviceUnits(glyphX + strikeOffset *
appUnitsPerDevUnit,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
strikeOffset += synBoldOnePixelOffset;
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
} while (--strikeCount > 0);
if (haveSVGGlyphs) {
if (!paintSVGGlyphs) {
continue;
}
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
details->mGlyphID,
aObjectPaint, aCallbacks,
emittedGlyphs)) {
continue;
}
}
glyph = glyphs.AppendGlyph();
glyph->index = details->mGlyphID;
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
int32_t strikeCount = strikes;
do {
cairo_glyph_t *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->index = glyph->index;
doubleglyph->x =
ToDeviceUnits(glyphX + strikeOffset *
appUnitsPerDevUnit,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
strikeOffset += synBoldOnePixelOffset;
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix);
} while (--strikeCount > 0);
}
emittedGlyphs = true;
}
x += direction*advance;
}
}
}
@ -1966,6 +1999,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
// draw any remaining glyphs
glyphs.Flush(cr, aDrawMode, isRTL, aObjectPaint, globalMatrix, true);
if (aCallbacks && emittedGlyphs) {
aCallbacks->NotifyGlyphPathEmitted();
}
} else {
RefPtr<ScaledFont> scaledFont = GetScaledFont(dt);
@ -2037,11 +2073,15 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
}
if (haveSVGGlyphs) {
if (!paintSVGGlyphs) {
continue;
}
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
ToDeviceUnits(y, devUnitsPerAppUnit));
if (RenderSVGGlyph(aContext, point, aDrawMode,
glyphData->GetSimpleGlyph(),
aObjectPaint)) {
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
glyphData->GetSimpleGlyph(), aObjectPaint,
aCallbacks, emittedGlyphs)) {
continue;
}
}
@ -2082,14 +2122,16 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
drawOptions);
} while (--strikeCount > 0);
}
emittedGlyphs = true;
} else {
uint32_t glyphCount = glyphData->GetGlyphCount();
if (glyphCount > 0) {
const gfxTextRun::DetailedGlyph *details =
aTextRun->GetDetailedGlyphs(i);
NS_ASSERTION(details, "detailedGlyph should not be missing!");
for (uint32_t j = 0; j < glyphCount; ++j, ++details) {
double advance = details->mAdvance;
double advance;
for (uint32_t j = 0; j < glyphCount; ++j, ++details, x += direction * advance) {
advance = details->mAdvance;
if (glyphData->IsMissing()) {
// default ignorable characters will have zero advance width.
// we don't have to draw the hexbox for them
@ -2117,40 +2159,49 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
ToDeviceUnits(y, devUnitsPerAppUnit));
if (!haveSVGGlyphs ||
!RenderSVGGlyph(aContext, point, aDrawMode,
details->mGlyphID, aObjectPaint)) {
glyph = glyphs.AppendGlyph();
glyph->mIndex = details->mGlyphID;
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->mPosition.y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyph->mPosition = matInv * glyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont, aDrawMode,
isRTL, renderingOptions, aContext, passedInvMatrix,
drawOptions);
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
int32_t strikeCount = strikes;
do {
Glyph *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->mIndex = glyph->mIndex;
doubleglyph->mPosition.x =
ToDeviceUnits(glyphX + strikeOffset *
appUnitsPerDevUnit,
devUnitsPerAppUnit);
doubleglyph->mPosition.y = glyph->mPosition.y;
strikeOffset += synBoldOnePixelOffset;
doubleglyph->mPosition = matInv * doubleglyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix, drawOptions);
} while (--strikeCount > 0);
if (haveSVGGlyphs) {
if (!paintSVGGlyphs) {
continue;
}
gfxFont::DrawMode mode = ForcePaintingDrawMode(aDrawMode);
if (RenderSVGGlyph(aContext, point, mode,
details->mGlyphID,
aObjectPaint, aCallbacks,
emittedGlyphs)) {
continue;
}
}
glyph = glyphs.AppendGlyph();
glyph->mIndex = details->mGlyphID;
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->mPosition.y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyph->mPosition = matInv * glyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont, aDrawMode,
isRTL, renderingOptions, aContext, passedInvMatrix,
drawOptions);
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
int32_t strikeCount = strikes;
do {
Glyph *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->mIndex = glyph->mIndex;
doubleglyph->mPosition.x =
ToDeviceUnits(glyphX + strikeOffset *
appUnitsPerDevUnit,
devUnitsPerAppUnit);
doubleglyph->mPosition.y = glyph->mPosition.y;
strikeOffset += synBoldOnePixelOffset;
doubleglyph->mPosition = matInv * doubleglyph->mPosition;
glyphs.Flush(dt, aObjectPaint, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix, drawOptions);
} while (--strikeCount > 0);
}
emittedGlyphs = true;
}
x += direction*advance;
}
}
}
@ -2167,6 +2218,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
glyphs.Flush(dt, aObjectPaint, scaledFont, aDrawMode, isRTL,
renderingOptions, aContext, passedInvMatrix,
drawOptions, true);
if (aCallbacks && emittedGlyphs) {
aCallbacks->NotifyGlyphPathEmitted();
}
dt->SetTransform(oldMat);
@ -2196,6 +2250,27 @@ gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMod
aObjectPaint);
}
bool
gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint,
gfxTextRunDrawCallbacks *aCallbacks,
bool& aEmittedGlyphs)
{
if (aCallbacks) {
if (aEmittedGlyphs) {
aCallbacks->NotifyGlyphPathEmitted();
aEmittedGlyphs = false;
}
aCallbacks->NotifyBeforeSVGGlyphPainted();
}
bool rendered = RenderSVGGlyph(aContext, aPoint, aDrawMode, aGlyphId,
aObjectPaint);
if (aCallbacks) {
aCallbacks->NotifyAfterSVGGlyphPainted();
}
return rendered;
}
static void
UnionRange(gfxFloat aX, gfxFloat* aDestMin, gfxFloat* aDestMax)
{
@ -4945,13 +5020,15 @@ gfxTextRun::DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
gfxTextObjectPaint *aObjectPaint,
uint32_t aStart, uint32_t aEnd,
PropertyProvider *aProvider,
uint32_t aSpacingStart, uint32_t aSpacingEnd)
uint32_t aSpacingStart, uint32_t aSpacingEnd,
gfxTextRunDrawCallbacks *aCallbacks)
{
nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
aSpacingStart, aSpacingEnd, &spacingBuffer);
aFont->Draw(this, aStart, aEnd, aContext, aDrawMode, aPt,
haveSpacing ? spacingBuffer.Elements() : nullptr, aObjectPaint);
haveSpacing ? spacingBuffer.Elements() : nullptr, aObjectPaint,
aCallbacks);
}
static void
@ -4980,7 +5057,7 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx,
uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt,
PropertyProvider *aProvider,
gfxTextRun::DrawCallbacks *aCallbacks)
gfxTextRunDrawCallbacks *aCallbacks)
{
if (aStart >= aEnd)
return;
@ -5015,10 +5092,7 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx,
DrawGlyphs(aFont, aCtx,
aCallbacks ? gfxFont::GLYPH_PATH : gfxFont::GLYPH_FILL, &pt,
nullptr, data.mLigatureStart, data.mLigatureEnd, aProvider,
aStart, aEnd);
if (aCallbacks) {
aCallbacks->NotifyGlyphPathEmitted();
}
aStart, aEnd, aCallbacks);
aCtx->Restore();
aPt->x += direction*data.mPartWidth;
@ -5095,7 +5169,7 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, gfxFont::DrawMode aDrawMode
uint32_t aStart, uint32_t aLength,
PropertyProvider *aProvider, gfxFloat *aAdvanceWidth,
gfxTextObjectPaint *aObjectPaint,
gfxTextRun::DrawCallbacks *aCallbacks)
gfxTextRunDrawCallbacks *aCallbacks)
{
NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
NS_ASSERTION(aDrawMode == gfxFont::GLYPH_PATH || !(aDrawMode & gfxFont::GLYPH_PATH),
@ -5153,11 +5227,8 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, gfxFont::DrawMode aDrawMode
}
DrawGlyphs(font, aContext, aDrawMode, &pt, aObjectPaint, ligatureRunStart,
ligatureRunEnd, aProvider, ligatureRunStart, ligatureRunEnd);
if (aCallbacks) {
aCallbacks->NotifyGlyphPathEmitted();
}
ligatureRunEnd, aProvider, ligatureRunStart, ligatureRunEnd,
aCallbacks);
if (drawPartial) {
DrawPartialLigature(font, aContext, ligatureRunEnd, end, &pt,

View File

@ -56,6 +56,7 @@ typedef struct hb_blob_t hb_blob_t;
#define NO_FONT_LANGUAGE_OVERRIDE 0
struct FontListSizes;
struct gfxTextRunDrawCallbacks;
struct THEBES_API gfxFontStyle {
gfxFontStyle();
@ -1432,7 +1433,8 @@ public:
*/
virtual void Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aBaselineOrigin,
Spacing *aSpacing, gfxTextObjectPaint *aObjectPaint);
Spacing *aSpacing, gfxTextObjectPaint *aObjectPaint,
gfxTextRunDrawCallbacks *aCallbacks);
/**
* Measure a run of characters. See gfxTextRun::Metrics.
@ -1768,6 +1770,10 @@ protected:
bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint);
bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
uint32_t aGlyphId, gfxTextObjectPaint *aObjectPaint,
gfxTextRunDrawCallbacks *aCallbacks,
bool& aEmittedGlyphs);
// Bug 674909. When synthetic bolding text by drawing twice, need to
// render using a pixel offset in device pixels, otherwise text
@ -2402,6 +2408,45 @@ private:
CompressedGlyph mCharGlyphsStorage[1];
};
/**
* Callback for Draw() to use when drawing text with mode
* gfxFont::GLYPH_PATH.
*/
struct gfxTextRunDrawCallbacks {
/**
* Constructs a new DrawCallbacks object.
*
* @param aShouldPaintSVGGlyphs If true, SVG glyphs will be
* painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted
* callbacks will be invoked for each SVG glyph. If false, SVG glyphs
* will not be painted; fallback plain glyphs are not emitted either.
*/
gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false)
: mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs)
{
}
/**
* Called when a path has been emitted to the gfxContext when
* painting a text run. This can be called any number of times,
* due to partial ligatures and intervening SVG glyphs.
*/
virtual void NotifyGlyphPathEmitted() = 0;
/**
* Called just before an SVG glyph has been painted to the gfxContext.
*/
virtual void NotifyBeforeSVGGlyphPainted() { }
/**
* Called just after an SVG glyph has been painted to the gfxContext.
*/
virtual void NotifyAfterSVGGlyphPainted() { }
bool mShouldPaintSVGGlyphs;
};
/**
* gfxTextRun is an abstraction for drawing and measuring substrings of a run
* of text. It stores runs of positioned glyph data, each run having a single
@ -2555,22 +2600,6 @@ public:
uint32_t mCurrentChar;
};
/**
* Callback for Draw() to use when drawing text with mode
* gfxFont::GLYPH_PATH.
*/
struct DrawCallbacks {
/**
* Called when a path has been emitted to the gfxContext when
* painting a text run. This can be called up to three times:
* once for any partial ligature at the beginning of the text run,
* once for the main run of glyphs, and once for any partial ligature
* at the end of the text run.
*/
virtual void NotifyGlyphPathEmitted() = 0;
};
/**
* Draws a substring. Uses only GetSpacing from aBreakProvider.
* The provided point is the baseline origin on the left of the string
@ -2597,7 +2626,7 @@ public:
uint32_t aStart, uint32_t aLength,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidth, gfxTextObjectPaint *aObjectPaint,
DrawCallbacks *aCallbacks = nullptr);
gfxTextRunDrawCallbacks *aCallbacks = nullptr);
/**
* Computes the ReflowMetrics for a substring.
@ -2991,7 +3020,7 @@ private:
void DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx,
uint32_t aStart, uint32_t aEnd, gfxPoint *aPt,
PropertyProvider *aProvider,
DrawCallbacks *aCallbacks);
gfxTextRunDrawCallbacks *aCallbacks);
// Advance aStart to the start of the nearest ligature; back up aEnd
// to the nearest ligature end; may result in *aStart == *aEnd
void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd);
@ -3017,7 +3046,8 @@ private:
gfxFont::DrawMode aDrawMode, gfxPoint *aPt,
gfxTextObjectPaint *aObjectPaint, uint32_t aStart,
uint32_t aEnd, PropertyProvider *aProvider,
uint32_t aSpacingStart, uint32_t aSpacingEnd);
uint32_t aSpacingStart, uint32_t aSpacingEnd,
gfxTextRunDrawCallbacks *aCallbacks);
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
// for smaller size especially in the super-common one-glyphrun case

View File

@ -297,7 +297,8 @@ public:
* (NotifyBeforeSelectionBackground NotifySelectionBackgroundPathEmitted)?
* (NotifyBeforeDecorationLine NotifyDecorationLinePathEmitted)*
* NotifyBeforeText
* NotifyGlyphPathEmitted*
* (NotifyGlyphPathEmitted |
* (NotifyBeforeSVGGlyphPainted NotifyAfterSVGGlyphPainted))*
* NotifyAfterText
* (NotifyBeforeDecorationLine NotifyDecorationLinePathEmitted)*
* (NotifyBeforeSelectionDecorationLine NotifySelectionDecorationLinePathEmitted)*
@ -308,8 +309,16 @@ public:
* NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR and
* NS_40PERCENT_FOREGROUND_COLOR.
*/
struct DrawPathCallbacks : gfxTextRun::DrawCallbacks
struct DrawPathCallbacks : gfxTextRunDrawCallbacks
{
/**
* @param aShouldPaintSVGGlyphs Whether SVG glyphs should be painted.
*/
DrawPathCallbacks(bool aShouldPaintSVGGlyphs = false)
: gfxTextRunDrawCallbacks(aShouldPaintSVGGlyphs)
{
}
/**
* Called just before any paths have been emitted to the gfxContext
* for the glyphs of the frame's text.
@ -365,6 +374,7 @@ public:
// context.
void PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect, const nsCharClipDisplayItem& aItem,
gfxTextObjectPaint* aObjectPaint = nullptr,
DrawPathCallbacks* aCallbacks = nullptr);
// 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
@ -378,6 +388,7 @@ public:
uint32_t aContentLength,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxTextObjectPaint* aObjectPaint,
DrawPathCallbacks* aCallbacks);
// helper: paint text with foreground and background colors determined
// by selection(s). Also computes a mask of all selection types applying to
@ -639,6 +650,7 @@ protected:
nscolor aTextColor,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
gfxTextObjectPaint* aObjectPaint,
DrawPathCallbacks* aCallbacks);
void DrawTextRunAndDecorations(gfxContext* const aCtx,
@ -655,6 +667,7 @@ protected:
bool aDrawSoftHyphen,
const TextDecorations& aDecorations,
const nscolor* const aDecorationOverrideColor,
gfxTextObjectPaint* aObjectPaint,
DrawPathCallbacks* aCallbacks);
void DrawText(gfxContext* const aCtx,
@ -670,6 +683,7 @@ protected:
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
const nscolor* const aDecorationOverrideColor = nullptr,
gfxTextObjectPaint* aObjectPaint = nullptr,
DrawPathCallbacks* aCallbacks = nullptr);
// Set non empty rect to aRect, it should be overflow rect or frame rect.

View File

@ -5585,7 +5585,7 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
advance, hyphenWidth > 0, nullptr, aCallbacks);
advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks);
if (hyphenWidth) {
advance += hyphenWidth;
}
@ -5677,6 +5677,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
uint32_t aContentOffset, uint32_t aContentLength,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxTextObjectPaint* aObjectPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
NS_ASSERTION(GetContent()->IsSelectionDescendant(), "wrong paint path");
@ -5890,6 +5891,7 @@ void
nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect,
const nsCharClipDisplayItem& aItem,
gfxTextObjectPaint* aObjectPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
// Don't pass in aRenderingContext here, because we need a *reference*
@ -5932,7 +5934,8 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset;
if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect,
provider, contentOffset, contentLength,
textPaintStyle, clipEdges, aCallbacks)) {
textPaintStyle, clipEdges, aObjectPaint,
aCallbacks)) {
return;
}
}
@ -5960,7 +5963,7 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider,
textPaintStyle, foregroundColor, clipEdges, advanceWidth,
(GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
nullptr, aCallbacks);
nullptr, aObjectPaint, aCallbacks);
}
static void
@ -5971,6 +5974,7 @@ DrawTextRun(gfxTextRun* aTextRun,
PropertyProvider* aProvider,
nscolor aTextColor,
gfxFloat* aAdvanceWidth,
gfxTextObjectPaint* aObjectPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
gfxFont::DrawMode drawMode = aCallbacks ? gfxFont::GLYPH_PATH :
@ -5978,12 +5982,12 @@ DrawTextRun(gfxTextRun* aTextRun,
if (aCallbacks) {
aCallbacks->NotifyBeforeText(aTextColor);
aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
aProvider, aAdvanceWidth, nullptr, aCallbacks);
aProvider, aAdvanceWidth, aObjectPaint, aCallbacks);
aCallbacks->NotifyAfterText();
} else {
aCtx->SetColor(gfxRGBA(aTextColor));
aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
aProvider, aAdvanceWidth, nullptr);
aProvider, aAdvanceWidth, aObjectPaint);
}
}
@ -5995,10 +5999,11 @@ nsTextFrame::DrawTextRun(gfxContext* const aCtx,
nscolor aTextColor,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
gfxTextObjectPaint* aObjectPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
::DrawTextRun(mTextRun, aCtx, aTextBaselinePt, aOffset, aLength, &aProvider,
aTextColor, &aAdvanceWidth, aCallbacks);
aTextColor, &aAdvanceWidth, aObjectPaint, aCallbacks);
if (aDrawSoftHyphen) {
// Don't use ctx as the context, because we need a reference context here,
@ -6012,7 +6017,7 @@ nsTextFrame::DrawTextRun(gfxContext* const aCtx,
::DrawTextRun(hyphenTextRun.get(), aCtx,
gfxPoint(hyphenBaselineX, aTextBaselinePt.y),
0, hyphenTextRun->GetLength(),
nullptr, aTextColor, nullptr, aCallbacks);
nullptr, aTextColor, nullptr, aObjectPaint, aCallbacks);
}
}
}
@ -6030,6 +6035,7 @@ nsTextFrame::DrawTextRunAndDecorations(
bool aDrawSoftHyphen,
const TextDecorations& aDecorations,
const nscolor* const aDecorationOverrideColor,
gfxTextObjectPaint* aObjectPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel();
@ -6094,7 +6100,7 @@ nsTextFrame::DrawTextRunAndDecorations(
// CSS 2.1 mandates that text be painted after over/underlines, and *then*
// line-throughs
DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor,
aAdvanceWidth, aDrawSoftHyphen, aCallbacks);
aAdvanceWidth, aDrawSoftHyphen, aObjectPaint, aCallbacks);
// Line-throughs
for (uint32_t i = aDecorations.mStrikes.Length(); i-- > 0; ) {
@ -6130,6 +6136,7 @@ nsTextFrame::DrawText(
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
const nscolor* const aDecorationOverrideColor,
gfxTextObjectPaint* aObjectPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
TextDecorations decorations;
@ -6144,10 +6151,10 @@ nsTextFrame::DrawText(
DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aOffset, aLength,
aProvider, aTextStyle, aTextColor, aClipEdges, aAdvanceWidth,
aDrawSoftHyphen, decorations,
aDecorationOverrideColor, aCallbacks);
aDecorationOverrideColor, aObjectPaint, aCallbacks);
} else {
DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider,
aTextColor, aAdvanceWidth, aDrawSoftHyphen, aCallbacks);
aTextColor, aAdvanceWidth, aDrawSoftHyphen, aObjectPaint, aCallbacks);
}
}

View File

@ -2,6 +2,8 @@ pref(gfx.font_rendering.opentype_svg.enabled,false) != svg-glyph-basic.svg svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-basic.svg svg-glyph-basic-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,false) != svg-glyph-positioning.svg svg-glyph-positioning-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-positioning.svg svg-glyph-positioning-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-html.html svg-glyph-html-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-direct.svg svg-glyph-direct-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-invalid.html svg-glyph-invalid-ref.html
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectfill-solid.svg svg-glyph-objectfill-solid-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectstroke-solid.svg svg-glyph-objectstroke-solid-ref.svg

View File

@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg">
<title>Reference for SVG glyphs being painted when painting properties are simple</title>
<style>
<![CDATA[
@font-face {
font-family: "Liberation";
src: url(resources/svg.woff);
}
text {
font-family: Liberation;
font-size: 200px;
fill: url(#transparent);
}
]]>
</style>
<linearGradient id="transparent">
<stop/>
</linearGradient>
<!-- The gradient paint server fill is not used by the "L" glyph,
but setting it forces the code path that fills and strokes text
in the SVG text frame to be chosen. -->
<text x="0" y="200">L</text>
</svg>

After

Width:  |  Height:  |  Size: 685 B

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg">
<title>Test for SVG glyphs being painted when painting properties are simple</title>
<style>
<![CDATA[
@font-face {
font-family: "Liberation";
src: url(resources/svg.woff);
}
text {
font-family: Liberation;
font-size: 200px;
}
]]>
</style>
<text x="0" y="200">L</text>
</svg>

After

Width:  |  Height:  |  Size: 392 B

View File

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg">
<title>Reference for SVG glyphs being used in HTML content</title>
<style>
@font-face {
font-family: "Liberation";
src: url(resources/svg.woff);
}
text { font: 200px Liberation; fill: fuchsia; stroke: black; }
</style>
<text x="0" y="200">b</text>
</svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<title>Test for SVG glyphs being used in HTML content</title>
<style>
@font-face {
font-family: "Liberation";
src: url(resources/svg.woff);
}
html { width: 400px; height: 400px; background-color: white; }
body { margin: 0; }
div { font: 200px Liberation; color: fuchsia; line-height: 1; stroke: none; }
</style>
<div>b</div>

View File

@ -1092,23 +1092,23 @@ nsSVGGlyphFrame::SetupObjectPaint(gfxContext *aContext,
// SVGTextObjectPaint methods:
already_AddRefed<gfxPattern>
nsSVGGlyphFrame::SVGTextObjectPaint::GetFillPattern(float aOpacity,
const gfxMatrix& aCTM)
mozilla::SVGTextObjectPaint::GetFillPattern(float aOpacity,
const gfxMatrix& aCTM)
{
return mFillPaint.GetPattern(aOpacity, &nsStyleSVG::mFill, aCTM);
}
already_AddRefed<gfxPattern>
nsSVGGlyphFrame::SVGTextObjectPaint::GetStrokePattern(float aOpacity,
const gfxMatrix& aCTM)
mozilla::SVGTextObjectPaint::GetStrokePattern(float aOpacity,
const gfxMatrix& aCTM)
{
return mStrokePaint.GetPattern(aOpacity, &nsStyleSVG::mStroke, aCTM);
}
already_AddRefed<gfxPattern>
nsSVGGlyphFrame::SVGTextObjectPaint::Paint::GetPattern(float aOpacity,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
const gfxMatrix& aCTM)
mozilla::SVGTextObjectPaint::Paint::GetPattern(float aOpacity,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
const gfxMatrix& aCTM)
{
nsRefPtr<gfxPattern> pattern;
if (mPatternCache.Get(aOpacity, getter_AddRefs(pattern))) {

View File

@ -8,12 +8,12 @@
#include "mozilla/Attributes.h"
#include "gfxFont.h"
#include "nsISVGGlyphFragmentNode.h"
#include "gfxSVGGlyphs.h"
#include "nsISVGChildFrame.h"
#include "nsISVGGlyphFragmentNode.h"
#include "nsSVGGeometryFrame.h"
#include "nsSVGUtils.h"
#include "nsTextFragment.h"
#include "gfxSVGGlyphs.h"
class CharacterIterator;
class gfxContext;
@ -27,6 +27,79 @@ class gfxTextObjectPaint;
struct CharacterPosition;
namespace mozilla {
// Slightly horrible callback for deferring application of opacity
struct SVGTextObjectPaint : public gfxTextObjectPaint {
already_AddRefed<gfxPattern> GetFillPattern(float aOpacity,
const gfxMatrix& aCTM);
already_AddRefed<gfxPattern> GetStrokePattern(float aOpacity,
const gfxMatrix& aCTM);
void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; }
float GetFillOpacity() { return mFillOpacity; }
void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; }
float GetStrokeOpacity() { return mStrokeOpacity; }
struct Paint {
Paint() {
mPatternCache.Init();
}
void SetPaintServer(nsIFrame *aFrame, const gfxMatrix& aContextMatrix,
nsSVGPaintServerFrame *aPaintServerFrame) {
mPaintType = eStyleSVGPaintType_Server;
mPaintDefinition.mPaintServerFrame = aPaintServerFrame;
mFrame = aFrame;
mContextMatrix = aContextMatrix;
}
void SetColor(const nscolor &aColor) {
mPaintType = eStyleSVGPaintType_Color;
mPaintDefinition.mColor = aColor;
}
void SetObjectPaint(gfxTextObjectPaint *aObjectPaint,
nsStyleSVGPaintType aPaintType) {
NS_ASSERTION(aPaintType == eStyleSVGPaintType_ObjectFill ||
aPaintType == eStyleSVGPaintType_ObjectStroke,
"Invalid object paint type");
mPaintType = aPaintType;
mPaintDefinition.mObjectPaint = aObjectPaint;
}
union {
nsSVGPaintServerFrame *mPaintServerFrame;
gfxTextObjectPaint *mObjectPaint;
nscolor mColor;
} mPaintDefinition;
nsIFrame *mFrame;
// CTM defining the user space for the pattern we will use.
gfxMatrix mContextMatrix;
nsStyleSVGPaintType mPaintType;
// Device-space-to-pattern-space
gfxMatrix mPatternMatrix;
nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
already_AddRefed<gfxPattern> GetPattern(float aOpacity,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
const gfxMatrix& aCTM);
};
Paint mFillPaint;
Paint mStrokePaint;
float mFillOpacity;
float mStrokeOpacity;
};
} // namespace mozilla
using namespace mozilla;
typedef gfxFont::DrawMode DrawMode;
typedef nsSVGGeometryFrame nsSVGGlyphFrameBase;
@ -184,7 +257,6 @@ public:
}
private:
/**
* This class exists purely because it would be too messy to pass the "for"
* flag for GetCanvasTM through the call chains to the GetCanvasTM() call in
@ -271,73 +343,6 @@ private:
gfxTextObjectPaint *aOuterObjectPaint,
gfxTextObjectPaint **aThisObjectPaint);
// Slightly horrible callback for deferring application of opacity
struct SVGTextObjectPaint : public gfxTextObjectPaint {
already_AddRefed<gfxPattern> GetFillPattern(float aOpacity,
const gfxMatrix& aCTM);
already_AddRefed<gfxPattern> GetStrokePattern(float aOpacity,
const gfxMatrix& aCTM);
void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; }
float GetFillOpacity() { return mFillOpacity; }
void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; }
float GetStrokeOpacity() { return mStrokeOpacity; }
struct Paint {
Paint() {
mPatternCache.Init();
}
void SetPaintServer(nsIFrame *aFrame, const gfxMatrix& aContextMatrix,
nsSVGPaintServerFrame *aPaintServerFrame) {
mPaintType = eStyleSVGPaintType_Server;
mPaintDefinition.mPaintServerFrame = aPaintServerFrame;
mFrame = aFrame;
mContextMatrix = aContextMatrix;
}
void SetColor(const nscolor &aColor) {
mPaintType = eStyleSVGPaintType_Color;
mPaintDefinition.mColor = aColor;
}
void SetObjectPaint(gfxTextObjectPaint *aObjectPaint,
nsStyleSVGPaintType aPaintType) {
NS_ASSERTION(aPaintType == eStyleSVGPaintType_ObjectFill ||
aPaintType == eStyleSVGPaintType_ObjectStroke,
"Invalid object paint type");
mPaintType = aPaintType;
mPaintDefinition.mObjectPaint = aObjectPaint;
}
union {
nsSVGPaintServerFrame *mPaintServerFrame;
gfxTextObjectPaint *mObjectPaint;
nscolor mColor;
} mPaintDefinition;
nsIFrame *mFrame;
// CTM defining the user space for the pattern we will use.
gfxMatrix mContextMatrix;
nsStyleSVGPaintType mPaintType;
// Device-space-to-pattern-space
gfxMatrix mPatternMatrix;
nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
already_AddRefed<gfxPattern> GetPattern(float aOpacity,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
const gfxMatrix& aCTM);
};
Paint mFillPaint;
Paint mStrokePaint;
float mFillOpacity;
float mStrokeOpacity;
};
/**
* Sets up the stroke style in |aContext| and stores stroke pattern
* information in |aThisObjectPaint|.

View File

@ -27,6 +27,7 @@
#include "nsSVGEffects.h"
#include "nsSVGGlyphFrame.h"
#include "nsSVGOuterSVGFrame.h"
#include "nsSVGPaintServerFrame.h"
#include "nsSVGRect.h"
#include "nsSVGIntegrationUtils.h"
#include "nsSVGTextFrame2.h"
@ -2471,11 +2472,14 @@ public:
* @param aCanvasTM The transformation matrix to set when painting; this
* should be the FOR_OUTERSVG_TM canvas TM of the text, so that
* paint servers are painted correctly.
* @param aShouldPaintSVGGlyphs Whether SVG glyphs should be painted.
*/
SVGTextDrawPathCallbacks(nsRenderingContext* aContext,
nsTextFrame* aFrame,
const gfxMatrix& aCanvasTM)
: gfx(aContext->ThebesContext()),
const gfxMatrix& aCanvasTM,
bool aShouldPaintSVGGlyphs)
: DrawPathCallbacks(aShouldPaintSVGGlyphs),
gfx(aContext->ThebesContext()),
mRenderMode(SVGAutoRenderState::GetRenderMode(aContext)),
mFrame(aFrame),
mCanvasTM(aCanvasTM)
@ -2484,6 +2488,8 @@ public:
void NotifyBeforeText(nscolor aColor);
void NotifyGlyphPathEmitted();
void NotifyBeforeSVGGlyphPainted();
void NotifyAfterSVGGlyphPainted();
void NotifyAfterText();
void NotifyBeforeSelectionBackground(nscolor aColor);
void NotifySelectionBackgroundPathEmitted();
@ -2543,6 +2549,19 @@ SVGTextDrawPathCallbacks::NotifyGlyphPathEmitted()
gfx->NewPath();
}
void
SVGTextDrawPathCallbacks::NotifyBeforeSVGGlyphPainted()
{
gfx->Save();
}
void
SVGTextDrawPathCallbacks::NotifyAfterSVGGlyphPainted()
{
gfx->Restore();
gfx->NewPath();
}
void
SVGTextDrawPathCallbacks::NotifyAfterText()
{
@ -3143,6 +3162,15 @@ nsSVGTextFrame2::PaintSVG(nsRenderingContext* aContext,
// need to ignore.
SVGCharClipDisplayItem item(run);
// Set up the fill and stroke so that SVG glyphs can get painted correctly
// when they use -moz-objectFill values etc.
gfx->SetMatrix(initialMatrix);
gfxTextObjectPaint *outerObjectPaint =
(gfxTextObjectPaint*)aContext->GetUserData(&gfxTextObjectPaint::sUserDataKey);
nsAutoPtr<gfxTextObjectPaint> objectPaint;
SetupCairoState(gfx, frame, outerObjectPaint, getter_Transfers(objectPaint));
// Set up the transform for painting the text frame for the substring
// indicated by the run.
gfxMatrix runTransform =
@ -3151,11 +3179,15 @@ nsSVGTextFrame2::PaintSVG(nsRenderingContext* aContext,
gfx->SetMatrix(runTransform);
nsRect frameRect = frame->GetVisualOverflowRect();
if (ShouldRenderAsPath(aContext, frame)) {
SVGTextDrawPathCallbacks callbacks(aContext, frame, matrixForPaintServers);
frame->PaintText(aContext, nsPoint(), frameRect, item, &callbacks);
bool paintSVGGlyphs;
if (ShouldRenderAsPath(aContext, frame, paintSVGGlyphs)) {
SVGTextDrawPathCallbacks callbacks(aContext, frame, matrixForPaintServers,
paintSVGGlyphs);
frame->PaintText(aContext, nsPoint(), frameRect, item,
objectPaint, &callbacks);
} else {
frame->PaintText(aContext, nsPoint(), frameRect, item, nullptr);
frame->PaintText(aContext, nsPoint(), frameRect, item,
objectPaint, nullptr);
}
if (frame == caretFrame && ShouldPaintCaret(run, caret)) {
@ -3255,7 +3287,7 @@ nsSVGTextFrame2::ReflowSVG()
uint16_t hitTestFlags = nsSVGUtils::GetGeometryHitTestFlags(run.mFrame);
if ((hitTestFlags & SVG_HIT_TEST_FILL) ||
run.mFrame->GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None) {
run.mFrame->GetStyleSVG()->mFill.mType == eStyleSVGPaintType_None) {
runFlags |= TextRenderedRun::eIncludeFill;
}
if ((hitTestFlags & SVG_HIT_TEST_STROKE) ||
@ -4464,13 +4496,17 @@ nsSVGTextFrame2::DoGlyphPositioning()
bool
nsSVGTextFrame2::ShouldRenderAsPath(nsRenderingContext* aContext,
nsTextFrame* aFrame)
nsTextFrame* aFrame,
bool& aShouldPaintSVGGlyphs)
{
// Rendering to a clip path.
if (SVGAutoRenderState::GetRenderMode(aContext) != SVGAutoRenderState::NORMAL) {
aShouldPaintSVGGlyphs = false;
return true;
}
aShouldPaintSVGGlyphs = true;
const nsStyleSVG* style = aFrame->GetStyleSVG();
// Fill is a non-solid paint, has a non-default fill-rule or has
@ -4878,3 +4914,141 @@ nsSVGTextFrame2::TransformFrameRectFromTextChild(const nsRect& aRect,
return result - framePosition;
}
gfxFont::DrawMode
nsSVGTextFrame2::SetupCairoState(gfxContext* aContext,
nsIFrame* aFrame,
gfxTextObjectPaint* aOuterObjectPaint,
gfxTextObjectPaint** aThisObjectPaint)
{
gfxFont::DrawMode toDraw = gfxFont::DrawMode(0);
SVGTextObjectPaint *thisObjectPaint = new SVGTextObjectPaint();
if (SetupCairoStroke(aContext, aFrame, aOuterObjectPaint, thisObjectPaint)) {
toDraw = gfxFont::DrawMode(toDraw | gfxFont::GLYPH_STROKE);
}
if (SetupCairoFill(aContext, aFrame, aOuterObjectPaint, thisObjectPaint)) {
toDraw = gfxFont::DrawMode(toDraw | gfxFont::GLYPH_FILL);
}
*aThisObjectPaint = thisObjectPaint;
return toDraw;
}
bool
nsSVGTextFrame2::SetupCairoStroke(gfxContext* aContext,
nsIFrame* aFrame,
gfxTextObjectPaint* aOuterObjectPaint,
SVGTextObjectPaint* aThisObjectPaint)
{
const nsStyleSVG *style = aFrame->GetStyleSVG();
if (style->mStroke.mType == eStyleSVGPaintType_None) {
aThisObjectPaint->SetStrokeOpacity(0.0f);
return false;
}
gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
aContext->IdentityMatrix();
nsSVGUtils::SetupCairoStrokeHitGeometry(aFrame, aContext, aOuterObjectPaint);
float opacity = nsSVGUtils::GetOpacity(style->mStrokeOpacitySource,
style->mStrokeOpacity,
aOuterObjectPaint);
SetupInheritablePaint(aContext, aFrame, opacity, aOuterObjectPaint,
aThisObjectPaint->mStrokePaint, &nsStyleSVG::mStroke,
nsSVGEffects::StrokeProperty());
aThisObjectPaint->SetStrokeOpacity(opacity);
return opacity != 0.0f;
}
bool
nsSVGTextFrame2::SetupCairoFill(gfxContext* aContext,
nsIFrame* aFrame,
gfxTextObjectPaint* aOuterObjectPaint,
SVGTextObjectPaint* aThisObjectPaint)
{
const nsStyleSVG *style = aFrame->GetStyleSVG();
if (style->mFill.mType == eStyleSVGPaintType_None) {
aThisObjectPaint->SetFillOpacity(0.0f);
return false;
}
float opacity = nsSVGUtils::GetOpacity(style->mFillOpacitySource,
style->mFillOpacity,
aOuterObjectPaint);
SetupInheritablePaint(aContext, aFrame, opacity, aOuterObjectPaint,
aThisObjectPaint->mFillPaint, &nsStyleSVG::mFill,
nsSVGEffects::FillProperty());
aThisObjectPaint->SetFillOpacity(opacity);
return true;
}
void
nsSVGTextFrame2::SetupInheritablePaint(gfxContext* aContext,
nsIFrame* aFrame,
float& aOpacity,
gfxTextObjectPaint* aOuterObjectPaint,
SVGTextObjectPaint::Paint& aTargetPaint,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
const FramePropertyDescriptor* aProperty)
{
const nsStyleSVG *style = aFrame->GetStyleSVG();
nsSVGPaintServerFrame *ps =
nsSVGEffects::GetPaintServer(aFrame, &(style->*aFillOrStroke), aProperty);
if (ps && ps->SetupPaintServer(aContext, aFrame, aFillOrStroke, aOpacity)) {
aTargetPaint.SetPaintServer(aFrame, aContext->CurrentMatrix(), ps);
} else if (SetupObjectPaint(aContext, aFrame, aFillOrStroke, aOpacity, aOuterObjectPaint)) {
aTargetPaint.SetObjectPaint(aOuterObjectPaint, (style->*aFillOrStroke).mType);
} else {
nscolor color = nsSVGUtils::GetFallbackOrPaintColor(aContext,
aFrame->GetStyleContext(),
aFillOrStroke);
aTargetPaint.SetColor(color);
aContext->SetPattern(new gfxPattern(gfxRGBA(NS_GET_R(color) / 255.0,
NS_GET_G(color) / 255.0,
NS_GET_B(color) / 255.0,
NS_GET_A(color) / 255.0 * aOpacity)));
}
}
bool
nsSVGTextFrame2::SetupObjectPaint(gfxContext* aContext,
nsIFrame* aFrame,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float& aOpacity,
gfxTextObjectPaint* aOuterObjectPaint)
{
if (!aOuterObjectPaint) {
return false;
}
const nsStyleSVG *style = aFrame->GetStyleSVG();
const nsStyleSVGPaint &paint = style->*aFillOrStroke;
if (paint.mType != eStyleSVGPaintType_ObjectFill &&
paint.mType != eStyleSVGPaintType_ObjectStroke) {
return false;
}
gfxMatrix current = aContext->CurrentMatrix();
nsRefPtr<gfxPattern> pattern =
paint.mType == eStyleSVGPaintType_ObjectFill ?
aOuterObjectPaint->GetFillPattern(aOpacity, current) :
aOuterObjectPaint->GetStrokePattern(aOpacity, current);
if (!pattern) {
return false;
}
aContext->SetPattern(pattern);
return true;
}

View File

@ -6,9 +6,12 @@
#ifndef NS_SVGTEXTFRAME2_H
#define NS_SVGTEXTFRAME2_H
#include "gfxFont.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "gfxSVGGlyphs.h"
#include "nsStubMutationObserver.h"
#include "nsSVGGlyphFrame.h" // for SVGTextObjectPaint
#include "nsSVGTextContainerFrame.h"
class nsDisplaySVGText;
@ -450,8 +453,12 @@ private:
* Returns whether we need to render the text using
* nsTextFrame::DrawPathCallbacks rather than directly painting
* the text frames.
*
* @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text
* should be painted.
*/
bool ShouldRenderAsPath(nsRenderingContext* aContext, nsTextFrame* aFrame);
bool ShouldRenderAsPath(nsRenderingContext* aContext, nsTextFrame* aFrame,
bool& aShouldPaintSVGGlyphs);
// Methods to get information for a <textPath> frame.
nsIFrame* GetTextPathPathFrame(nsIFrame* aTextPathFrame);
@ -459,6 +466,58 @@ private:
gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);
gfxFont::DrawMode SetupCairoState(gfxContext* aContext,
nsIFrame* aFrame,
gfxTextObjectPaint* aOuterObjectPaint,
gfxTextObjectPaint** aThisObjectPaint);
/**
* Sets up the stroke style for |aFrame| in |aContext| and stores stroke
* pattern information in |aThisObjectPaint|.
*/
bool SetupCairoStroke(gfxContext* aContext,
nsIFrame* aFrame,
gfxTextObjectPaint* aOuterObjectPaint,
SVGTextObjectPaint* aThisObjectPaint);
/**
* Sets up the fill style for |aFrame| in |aContext| and stores fill pattern
* information in |aThisObjectPaint|.
*/
bool SetupCairoFill(gfxContext* aContext,
nsIFrame* aFrame,
gfxTextObjectPaint* aOuterObjectPaint,
SVGTextObjectPaint* aThisObjectPaint);
/**
* Sets the current pattern for |aFrame| to the fill or stroke style of the
* outer text object. Will also set the paint opacity to transparent if the
* paint is set to "none".
*/
bool SetupObjectPaint(gfxContext* aContext,
nsIFrame* aFrame,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
float& aOpacity,
gfxTextObjectPaint* aObjectPaint);
/**
* Stores in |aTargetPaint| information on how to reconstruct the current
* fill or stroke pattern. Will also set the paint opacity to transparent if
* the paint is set to "none".
* @param aOuterObjectPaint pattern information from the outer text object
* @param aTargetPaint where to store the current pattern information
* @param aFillOrStroke member pointer to the paint we are setting up
* @param aProperty the frame property descriptor of the fill or stroke paint
* server frame
*/
void SetupInheritablePaint(gfxContext* aContext,
nsIFrame* aFrame,
float& aOpacity,
gfxTextObjectPaint* aOuterObjectPaint,
SVGTextObjectPaint::Paint& aTargetPaint,
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
const FramePropertyDescriptor* aProperty);
/**
* The MutationObserver we have registered for the <text> element subtree.
*/