mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 738691 - Part 2: Add proper stroke and path support to Azure glyph drawing. r=jrmuizel
This commit is contained in:
parent
2bdf71a9a7
commit
28600eae8e
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user