mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 655877 - Part 46: Paint SVG glyphs with new SVG text frame. r=roc,jwatt
This commit is contained in:
parent
c09bbacdbf
commit
0335ceedb4
@ -1667,11 +1667,16 @@ struct GlyphBufferAzure {
|
||||
nsRefPtr<gfxPattern> fillPattern;
|
||||
if (!aObjectPaint ||
|
||||
!(fillPattern = aObjectPaint->GetFillPattern(aThebesContext->CurrentMatrix()))) {
|
||||
if (state.pattern) {
|
||||
pat = state.pattern->GetPattern(aDT, state.patternTransformChanged ? &state.patternTransform : nullptr);
|
||||
} else {
|
||||
pat = nullptr;
|
||||
}
|
||||
} else {
|
||||
pat = fillPattern->GetPattern(aDT);
|
||||
}
|
||||
|
||||
if (pat) {
|
||||
Matrix saved;
|
||||
Matrix *mat = nullptr;
|
||||
if (aInvFontMatrix) {
|
||||
@ -1701,6 +1706,7 @@ struct GlyphBufferAzure {
|
||||
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,9 +1937,19 @@ 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)) {
|
||||
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);
|
||||
@ -1938,10 +1972,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
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,9 +2159,19 @@ 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)) {
|
||||
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);
|
||||
@ -2148,10 +2200,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
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,
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
27
layout/reftests/text-svgglyphs/svg-glyph-direct-ref.svg
Normal file
27
layout/reftests/text-svgglyphs/svg-glyph-direct-ref.svg
Normal 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 |
19
layout/reftests/text-svgglyphs/svg-glyph-direct.svg
Normal file
19
layout/reftests/text-svgglyphs/svg-glyph-direct.svg
Normal 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 |
11
layout/reftests/text-svgglyphs/svg-glyph-html-ref.svg
Normal file
11
layout/reftests/text-svgglyphs/svg-glyph-html-ref.svg
Normal 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 |
12
layout/reftests/text-svgglyphs/svg-glyph-html.html
Normal file
12
layout/reftests/text-svgglyphs/svg-glyph-html.html
Normal 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>
|
@ -1092,21 +1092,21 @@ nsSVGGlyphFrame::SetupObjectPaint(gfxContext *aContext,
|
||||
// SVGTextObjectPaint methods:
|
||||
|
||||
already_AddRefed<gfxPattern>
|
||||
nsSVGGlyphFrame::SVGTextObjectPaint::GetFillPattern(float aOpacity,
|
||||
mozilla::SVGTextObjectPaint::GetFillPattern(float aOpacity,
|
||||
const gfxMatrix& aCTM)
|
||||
{
|
||||
return mFillPaint.GetPattern(aOpacity, &nsStyleSVG::mFill, aCTM);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxPattern>
|
||||
nsSVGGlyphFrame::SVGTextObjectPaint::GetStrokePattern(float aOpacity,
|
||||
mozilla::SVGTextObjectPaint::GetStrokePattern(float aOpacity,
|
||||
const gfxMatrix& aCTM)
|
||||
{
|
||||
return mStrokePaint.GetPattern(aOpacity, &nsStyleSVG::mStroke, aCTM);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxPattern>
|
||||
nsSVGGlyphFrame::SVGTextObjectPaint::Paint::GetPattern(float aOpacity,
|
||||
mozilla::SVGTextObjectPaint::Paint::GetPattern(float aOpacity,
|
||||
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
|
||||
const gfxMatrix& aCTM)
|
||||
{
|
||||
|
@ -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|.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user