зеркало из https://github.com/mozilla/gecko-dev.git
Bug 738691 - Part 2: Add proper stroke and path support to Azure glyph drawing. r=jrmuizel
This commit is contained in:
Родитель
5ce9db7075
Коммит
a8e8d73c32
|
@ -54,6 +54,7 @@
|
|||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
typedef struct _cairo cairo_t;
|
||||
struct GlyphBufferAzure;
|
||||
template <typename T> class FallibleTArray;
|
||||
|
||||
/**
|
||||
|
@ -717,6 +718,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class GeneralPattern;
|
||||
friend class GlyphBufferAzure;
|
||||
|
||||
typedef mozilla::gfx::Matrix Matrix;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
|
|
@ -1474,9 +1474,9 @@ struct GlyphBufferAzure {
|
|||
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,
|
||||
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
|
||||
if (!aFinish && mNumGlyphs < GLYPH_BUFFER_SIZE || !mNumGlyphs) {
|
||||
|
@ -1489,13 +1489,57 @@ struct GlyphBufferAzure {
|
|||
std::reverse(begin, end);
|
||||
}
|
||||
|
||||
NS_ASSERTION(aDrawMode != gfxFont::GLYPH_FILL, "Not supported yet.");
|
||||
|
||||
gfx::GlyphBuffer buf;
|
||||
buf.mGlyphs = mGlyphBuffer;
|
||||
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;
|
||||
}
|
||||
|
@ -1571,17 +1615,13 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
|
||||
cairo_t *cr = aContext->GetCairo();
|
||||
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()) {
|
||||
cairo_pattern_t *strokePattern = nsnull;
|
||||
if (aStrokePattern) {
|
||||
strokePattern = aStrokePattern->CairoPattern();
|
||||
}
|
||||
|
||||
bool success = SetupCairoFont(aContext);
|
||||
if (NS_UNLIKELY(!success))
|
||||
return;
|
||||
|
@ -1713,27 +1753,23 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
glyphs.Flush(cr, strokePattern, aDrawMode, isRTL, true);
|
||||
|
||||
} else {
|
||||
if (aDrawMode == gfxFont::GLYPH_PATH) {
|
||||
// This should never be reached with azure!
|
||||
NS_ERROR("Attempt at drawing to a Path to an Azure gfxContext.");
|
||||
return;
|
||||
}
|
||||
|
||||
scaledFont =
|
||||
RefPtr<ScaledFont> scaledFont =
|
||||
gfxPlatform::GetPlatform()->GetScaledFontForFont(this);
|
||||
|
||||
if (!scaledFont || !aContext->GetDeviceColor(color)) {
|
||||
if (!scaledFont) {
|
||||
return;
|
||||
}
|
||||
|
||||
colPat.mColor = ToColor(color);
|
||||
|
||||
GlyphBufferAzure glyphs;
|
||||
Glyph *glyph;
|
||||
|
||||
Matrix mat, matInv;
|
||||
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 =
|
||||
GetGlyphRenderingOptions();
|
||||
|
||||
|
@ -1756,6 +1792,8 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
|
||||
matInv = mat;
|
||||
matInv.Invert();
|
||||
|
||||
passedInvMatrix = &matInv;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1784,7 +1822,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
glyph->mPosition.y = ToDeviceUnits(y, devUnitsPerAppUnit);
|
||||
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
|
||||
// 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 = matInv * doubleglyph->mPosition;
|
||||
strikeOffset += synBoldOnePixelOffset;
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, renderingOptions);
|
||||
glyphs.Flush(dt, aStrokePattern, scaledFont,
|
||||
aDrawMode, isRTL, renderingOptions,
|
||||
aContext, passedInvMatrix);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
} else {
|
||||
|
@ -1839,7 +1881,8 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
glyph->mPosition.y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
|
||||
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()) {
|
||||
double strikeOffset = synBoldOnePixelOffset;
|
||||
|
@ -1855,7 +1898,9 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
doubleglyph->mPosition.y = glyph->mPosition.y;
|
||||
strikeOffset += synBoldOnePixelOffset;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче