Bug 738691 - Part 2: Add proper stroke and path support to Azure glyph drawing. r=jrmuizel

This commit is contained in:
Bas Schouten 2012-03-29 20:53:44 +02:00
parent 2bdf71a9a7
commit 28600eae8e
2 changed files with 77 additions and 29 deletions

View File

@ -54,6 +54,7 @@
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
typedef struct _cairo cairo_t; typedef struct _cairo cairo_t;
struct GlyphBufferAzure;
template <typename T> class FallibleTArray; template <typename T> class FallibleTArray;
/** /**
@ -717,6 +718,7 @@ public:
private: private:
friend class GeneralPattern; friend class GeneralPattern;
friend class GlyphBufferAzure;
typedef mozilla::gfx::Matrix Matrix; typedef mozilla::gfx::Matrix Matrix;
typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::DrawTarget DrawTarget;

View File

@ -1474,9 +1474,9 @@ struct GlyphBufferAzure {
return &mGlyphBuffer[mNumGlyphs++]; return &mGlyphBuffer[mNumGlyphs++];
} }
void Flush(DrawTarget *aDT, Pattern &aPattern, ScaledFont *aFont, void Flush(DrawTarget *aDT, gfxPattern *aStrokePattern, ScaledFont *aFont,
gfxFont::DrawMode aDrawMode, bool aReverse, const GlyphRenderingOptions *aOptions, gfxFont::DrawMode aDrawMode, bool aReverse, const GlyphRenderingOptions *aOptions,
bool aFinish = false) gfxContext *aThebesContext, const Matrix *invFontMatrix, bool aFinish = false)
{ {
// Ensure there's enough room for a glyph to be added to the buffer // Ensure there's enough room for a glyph to be added to the buffer
if (!aFinish && mNumGlyphs < GLYPH_BUFFER_SIZE || !mNumGlyphs) { if (!aFinish && mNumGlyphs < GLYPH_BUFFER_SIZE || !mNumGlyphs) {
@ -1489,13 +1489,57 @@ struct GlyphBufferAzure {
std::reverse(begin, end); std::reverse(begin, end);
} }
NS_ASSERTION(aDrawMode != gfxFont::GLYPH_FILL, "Not supported yet.");
gfx::GlyphBuffer buf; gfx::GlyphBuffer buf;
buf.mGlyphs = mGlyphBuffer; buf.mGlyphs = mGlyphBuffer;
buf.mNumGlyphs = mNumGlyphs; buf.mNumGlyphs = mNumGlyphs;
aDT->FillGlyphs(aFont, buf, aPattern, DrawOptions(), aOptions); gfxContext::AzureState state = aThebesContext->CurrentState();
if (aDrawMode & gfxFont::GLYPH_FILL) {
if (state.pattern) {
Pattern *pat = state.pattern->GetPattern(aDT, state.patternTransformChanged ? &state.patternTransform : nsnull);
if (invFontMatrix) {
// 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!
Matrix *mat;
if (pat->GetType() == PATTERN_LINEAR_GRADIENT) {
mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
} else if (pat->GetType() == PATTERN_RADIAL_GRADIENT) {
mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
} else if (pat->GetType() == PATTERN_SURFACE) {
mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
}
*mat = (*mat) * (*invFontMatrix);
}
aDT->FillGlyphs(aFont, buf, *pat,
DrawOptions(), aOptions);
} else if (state.sourceSurface) {
aDT->FillGlyphs(aFont, buf, SurfacePattern(state.sourceSurface,
EXTEND_CLAMP,
state.surfTransform),
DrawOptions(), aOptions);
} else {
aDT->FillGlyphs(aFont, buf, ColorPattern(state.color),
DrawOptions(), aOptions);
}
}
if (aDrawMode & gfxFont::GLYPH_PATH) {
aThebesContext->EnsurePathBuilder();
aFont->CopyGlyphsToBuilder(buf, aThebesContext->mPathBuilder);
}
if (aDrawMode & gfxFont::GLYPH_STROKE) {
RefPtr<Path> path = aFont->GetPathForGlyphs(buf, aDT);
if (aStrokePattern) {
aDT->Stroke(path, *aStrokePattern->GetPattern(aDT), state.strokeOptions);
}
}
mNumGlyphs = 0; mNumGlyphs = 0;
} }
@ -1571,17 +1615,13 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
cairo_t *cr = aContext->GetCairo(); cairo_t *cr = aContext->GetCairo();
RefPtr<DrawTarget> dt = aContext->GetDrawTarget(); RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
cairo_pattern_t *strokePattern = nsnull;
if (aStrokePattern) {
strokePattern = aStrokePattern->CairoPattern();
}
RefPtr<ScaledFont> scaledFont;
gfxRGBA color;
ColorPattern colPat(Color(0, 0, 0, 0));
if (aContext->IsCairo()) { if (aContext->IsCairo()) {
cairo_pattern_t *strokePattern = nsnull;
if (aStrokePattern) {
strokePattern = aStrokePattern->CairoPattern();
}
bool success = SetupCairoFont(aContext); bool success = SetupCairoFont(aContext);
if (NS_UNLIKELY(!success)) if (NS_UNLIKELY(!success))
return; return;
@ -1713,27 +1753,23 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
glyphs.Flush(cr, strokePattern, aDrawMode, isRTL, true); glyphs.Flush(cr, strokePattern, aDrawMode, isRTL, true);
} else { } else {
if (aDrawMode == gfxFont::GLYPH_PATH) { RefPtr<ScaledFont> scaledFont =
// This should never be reached with azure!
NS_ERROR("Attempt at drawing to a Path to an Azure gfxContext.");
return;
}
scaledFont =
gfxPlatform::GetPlatform()->GetScaledFontForFont(this); gfxPlatform::GetPlatform()->GetScaledFontForFont(this);
if (!scaledFont || !aContext->GetDeviceColor(color)) { if (!scaledFont) {
return; return;
} }
colPat.mColor = ToColor(color);
GlyphBufferAzure glyphs; GlyphBufferAzure glyphs;
Glyph *glyph; Glyph *glyph;
Matrix mat, matInv; Matrix mat, matInv;
Matrix oldMat = dt->GetTransform(); Matrix oldMat = dt->GetTransform();
// This is NULL when we have inverse-transformed glyphs and we need to
// transform the Brush inside flush.
Matrix *passedInvMatrix = nsnull;
RefPtr<GlyphRenderingOptions> renderingOptions = RefPtr<GlyphRenderingOptions> renderingOptions =
GetGlyphRenderingOptions(); GetGlyphRenderingOptions();
@ -1756,6 +1792,8 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
matInv = mat; matInv = mat;
matInv.Invert(); matInv.Invert();
passedInvMatrix = &matInv;
} }
} }
@ -1784,7 +1822,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit); glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->mPosition.y = ToDeviceUnits(y, devUnitsPerAppUnit); glyph->mPosition.y = ToDeviceUnits(y, devUnitsPerAppUnit);
glyph->mPosition = matInv * glyph->mPosition; glyph->mPosition = matInv * glyph->mPosition;
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, renderingOptions); glyphs.Flush(dt, aStrokePattern, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix);
// synthetic bolding by multi-striking with 1-pixel offsets // synthetic bolding by multi-striking with 1-pixel offsets
// at least once, more if there's room (large font sizes) // at least once, more if there's room (large font sizes)
@ -1801,7 +1841,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
doubleglyph->mPosition.y = glyph->mPosition.y; doubleglyph->mPosition.y = glyph->mPosition.y;
doubleglyph->mPosition = matInv * doubleglyph->mPosition; doubleglyph->mPosition = matInv * doubleglyph->mPosition;
strikeOffset += synBoldOnePixelOffset; strikeOffset += synBoldOnePixelOffset;
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, renderingOptions); glyphs.Flush(dt, aStrokePattern, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix);
} while (--strikeCount > 0); } while (--strikeCount > 0);
} }
} else { } else {
@ -1839,7 +1881,8 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit); glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->mPosition.y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit); glyph->mPosition.y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
glyph->mPosition = matInv * glyph->mPosition; glyph->mPosition = matInv * glyph->mPosition;
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, renderingOptions); glyphs.Flush(dt, aStrokePattern, scaledFont, aDrawMode,
isRTL, renderingOptions, aContext, passedInvMatrix);
if (IsSyntheticBold()) { if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset; double strikeOffset = synBoldOnePixelOffset;
@ -1855,7 +1898,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
doubleglyph->mPosition.y = glyph->mPosition.y; doubleglyph->mPosition.y = glyph->mPosition.y;
strikeOffset += synBoldOnePixelOffset; strikeOffset += synBoldOnePixelOffset;
doubleglyph->mPosition = matInv * doubleglyph->mPosition; doubleglyph->mPosition = matInv * doubleglyph->mPosition;
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, renderingOptions); glyphs.Flush(dt, aStrokePattern, scaledFont,
aDrawMode, isRTL, renderingOptions,
aContext, passedInvMatrix);
} while (--strikeCount > 0); } while (--strikeCount > 0);
} }
} }
@ -1873,7 +1918,8 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
} }
} }
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, renderingOptions, true); glyphs.Flush(dt, aStrokePattern, scaledFont, aDrawMode, isRTL,
renderingOptions, aContext, passedInvMatrix, true);
dt->SetTransform(oldMat); dt->SetTransform(oldMat);
} }