mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 710521 - Refactor gfxFont to separate out drawing stroke and drawing to path. r=roc
This commit is contained in:
parent
3216b07af4
commit
4701befff3
@ -2790,22 +2790,14 @@ struct NS_STACK_CLASS nsCanvasBidiProcessor : public nsBidiPresUtils::BidiProces
|
||||
// throughout the text layout process
|
||||
}
|
||||
|
||||
// stroke or fill the text depending on operation
|
||||
if (mOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE)
|
||||
mTextRun->DrawToPath(mThebes,
|
||||
point,
|
||||
0,
|
||||
mTextRun->GetLength(),
|
||||
nsnull,
|
||||
nsnull);
|
||||
else
|
||||
// mOp == TEXT_DRAW_OPERATION_FILL
|
||||
mTextRun->Draw(mThebes,
|
||||
point,
|
||||
0,
|
||||
mTextRun->GetLength(),
|
||||
nsnull,
|
||||
nsnull);
|
||||
mTextRun->Draw(mThebes,
|
||||
point,
|
||||
mOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE ?
|
||||
gfxFont::GLYPH_STROKE : gfxFont::GLYPH_FILL,
|
||||
0,
|
||||
mTextRun->GetLength(),
|
||||
nsnull,
|
||||
nsnull);
|
||||
}
|
||||
|
||||
// current text run
|
||||
@ -2887,10 +2879,11 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL;
|
||||
}
|
||||
|
||||
// don't need to take care of these with stroke since Stroke() does that
|
||||
bool doDrawShadow = aOp == TEXT_DRAW_OPERATION_FILL && NeedToDrawShadow();
|
||||
bool doUseIntermediateSurface = aOp == TEXT_DRAW_OPERATION_FILL &&
|
||||
(NeedToUseIntermediateSurface() || NeedIntermediateSurfaceToHandleGlobalAlpha(STYLE_FILL));
|
||||
Style style = aOp == TEXT_DRAW_OPERATION_FILL ? STYLE_FILL : STYLE_STROKE;
|
||||
|
||||
bool doDrawShadow = NeedToDrawShadow();
|
||||
bool doUseIntermediateSurface = NeedToUseIntermediateSurface()
|
||||
|| NeedIntermediateSurfaceToHandleGlobalAlpha(style);
|
||||
|
||||
// Clear the surface if we need to simulate unbounded SOURCE operator
|
||||
ClearSurfaceForUnboundedSource();
|
||||
@ -3027,6 +3020,7 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
gfxContext* ctx = ShadowInitialize(drawExtents, blur);
|
||||
|
||||
if (ctx) {
|
||||
ApplyStyle(style, false);
|
||||
CopyContext(ctx, mThebes);
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
processor.mThebes = ctx;
|
||||
@ -3052,23 +3046,15 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
|
||||
gfxContextPathAutoSaveRestore pathSR(mThebes, false);
|
||||
|
||||
// back up and clear path if stroking
|
||||
if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE) {
|
||||
pathSR.Save();
|
||||
mThebes->NewPath();
|
||||
}
|
||||
// doUseIntermediateSurface is mutually exclusive to op == STROKE
|
||||
else {
|
||||
if (doUseIntermediateSurface) {
|
||||
mThebes->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
if (doUseIntermediateSurface) {
|
||||
mThebes->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
|
||||
// don't want operators to be applied twice
|
||||
mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
}
|
||||
|
||||
ApplyStyle(STYLE_FILL);
|
||||
// don't want operators to be applied twice
|
||||
mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
}
|
||||
|
||||
ApplyStyle(style);
|
||||
|
||||
rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
|
||||
textToDraw.Length(),
|
||||
isRTL ? NSBIDI_RTL : NSBIDI_LTR,
|
||||
@ -3089,13 +3075,8 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE) {
|
||||
// DrawPath takes care of all shadows and composite oddities
|
||||
rv = DrawPath(STYLE_STROKE);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
} else if (doUseIntermediateSurface)
|
||||
mThebes->Paint(CurrentState().StyleIsColor(STYLE_FILL) ? 1.0 : CurrentState().globalAlpha);
|
||||
if (doUseIntermediateSurface)
|
||||
mThebes->Paint(CurrentState().StyleIsColor(style) ? 1.0 : CurrentState().globalAlpha);
|
||||
|
||||
if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_FILL && !doDrawShadow)
|
||||
return RedrawUser(boundingBox);
|
||||
|
@ -333,7 +333,7 @@ nsFontMetrics::DrawString(const char *aString, PRUint32 aLength,
|
||||
if (mTextRunRTL) {
|
||||
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
|
||||
}
|
||||
textRun->Draw(aContext->ThebesContext(), pt, 0, aLength, &provider, nsnull);
|
||||
textRun->Draw(aContext->ThebesContext(), pt, gfxFont::GLYPH_FILL, 0, aLength, &provider, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
@ -351,7 +351,7 @@ nsFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
|
||||
if (mTextRunRTL) {
|
||||
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
|
||||
}
|
||||
textRun->Draw(aContext->ThebesContext(), pt, 0, aLength, &provider, nsnull);
|
||||
textRun->Draw(aContext->ThebesContext(), pt, gfxFont::GLYPH_FILL, 0, aLength, &provider, nsnull);
|
||||
}
|
||||
|
||||
nsBoundingMetrics
|
||||
|
@ -1238,7 +1238,7 @@ struct GlyphBuffer {
|
||||
return &mGlyphBuffer[mNumGlyphs++];
|
||||
}
|
||||
|
||||
void Flush(cairo_t *aCR, bool aDrawToPath, bool aReverse,
|
||||
void Flush(cairo_t *aCR, gfxFont::DrawMode aDrawMode, bool aReverse,
|
||||
bool aFinish = false) {
|
||||
// Ensure there's enough room for a glyph to be added to the buffer
|
||||
if (!aFinish && mNumGlyphs < GLYPH_BUFFER_SIZE) {
|
||||
@ -1252,10 +1252,20 @@ struct GlyphBuffer {
|
||||
mGlyphBuffer[mNumGlyphs - 1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
if (aDrawToPath)
|
||||
|
||||
if (aDrawMode == gfxFont::GLYPH_PATH) {
|
||||
cairo_glyph_path(aCR, mGlyphBuffer, mNumGlyphs);
|
||||
else
|
||||
cairo_show_glyphs(aCR, mGlyphBuffer, mNumGlyphs);
|
||||
} else {
|
||||
if (aDrawMode & gfxFont::GLYPH_FILL) {
|
||||
cairo_show_glyphs(aCR, mGlyphBuffer, mNumGlyphs);
|
||||
}
|
||||
|
||||
if (aDrawMode & gfxFont::GLYPH_STROKE) {
|
||||
cairo_new_path(aCR);
|
||||
cairo_glyph_path(aCR, mGlyphBuffer, mNumGlyphs);
|
||||
cairo_stroke(aCR);
|
||||
}
|
||||
}
|
||||
|
||||
mNumGlyphs = 0;
|
||||
}
|
||||
@ -1275,7 +1285,7 @@ struct GlyphBufferAzure {
|
||||
}
|
||||
|
||||
void Flush(DrawTarget *aDT, Pattern &aPattern, ScaledFont *aFont,
|
||||
bool aDrawToPath, bool aReverse, bool aFinish = false)
|
||||
gfxFont::DrawMode aDrawMode, bool aReverse, bool aFinish = false)
|
||||
{
|
||||
// Ensure there's enough room for a glyph to be added to the buffer
|
||||
if (!aFinish && mNumGlyphs < GLYPH_BUFFER_SIZE || !mNumGlyphs) {
|
||||
@ -1288,7 +1298,7 @@ struct GlyphBufferAzure {
|
||||
std::reverse(begin, end);
|
||||
}
|
||||
|
||||
NS_ASSERTION(!aDrawToPath, "Not supported yet.");
|
||||
NS_ASSERTION(aDrawMode != gfxFont::GLYPH_FILL, "Not supported yet.");
|
||||
|
||||
gfx::GlyphBuffer buf;
|
||||
buf.mGlyphs = mGlyphBuffer;
|
||||
@ -1330,9 +1340,11 @@ gfxFont::CalcXScale(gfxContext *aContext)
|
||||
|
||||
void
|
||||
gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
gfxContext *aContext, bool aDrawToPath, gfxPoint *aPt,
|
||||
gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aPt,
|
||||
Spacing *aSpacing)
|
||||
{
|
||||
NS_ASSERTION(aDrawMode <= gfxFont::GLYPH_PATH, "GLYPH_PATH cannot be used with GLYPH_FILL or GLYPH_STROKE");
|
||||
|
||||
if (aStart >= aEnd)
|
||||
return;
|
||||
|
||||
@ -1398,7 +1410,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
}
|
||||
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit);
|
||||
glyphs.Flush(cr, aDrawToPath, isRTL);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL);
|
||||
|
||||
// synthetic bolding by multi-striking with 1-pixel offsets
|
||||
// at least once, more if there's room (large font sizes)
|
||||
@ -1414,7 +1426,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
devUnitsPerAppUnit);
|
||||
doubleglyph->y = glyph->y;
|
||||
strikeOffset += synBoldOnePixelOffset;
|
||||
glyphs.Flush(cr, aDrawToPath, isRTL);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
} else {
|
||||
@ -1428,7 +1440,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
if (glyphData->IsMissing()) {
|
||||
// default ignorable characters will have zero advance width.
|
||||
// we don't have to draw the hexbox for them
|
||||
if (!aDrawToPath && advance > 0) {
|
||||
if (aDrawMode != gfxFont::GLYPH_PATH && advance > 0) {
|
||||
double glyphX = x;
|
||||
if (isRTL) {
|
||||
glyphX -= advance;
|
||||
@ -1451,7 +1463,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
}
|
||||
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
|
||||
glyphs.Flush(cr, aDrawToPath, isRTL);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL);
|
||||
|
||||
if (IsSyntheticBold()) {
|
||||
double strikeOffset = synBoldOnePixelOffset;
|
||||
@ -1466,7 +1478,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
devUnitsPerAppUnit);
|
||||
doubleglyph->y = glyph->y;
|
||||
strikeOffset += synBoldOnePixelOffset;
|
||||
glyphs.Flush(cr, aDrawToPath, isRTL);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
}
|
||||
@ -1495,10 +1507,10 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
}
|
||||
|
||||
// draw any remaining glyphs
|
||||
glyphs.Flush(cr, aDrawToPath, isRTL, true);
|
||||
glyphs.Flush(cr, aDrawMode, isRTL, true);
|
||||
|
||||
} else {
|
||||
if (aDrawToPath) {
|
||||
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;
|
||||
@ -1566,7 +1578,7 @@ 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, aDrawToPath, isRTL);
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL);
|
||||
|
||||
// synthetic bolding by multi-striking with 1-pixel offsets
|
||||
// at least once, more if there's room (large font sizes)
|
||||
@ -1583,7 +1595,7 @@ 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, aDrawToPath, isRTL);
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
} else {
|
||||
@ -1597,7 +1609,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
if (glyphData->IsMissing()) {
|
||||
// default ignorable characters will have zero advance width.
|
||||
// we don't have to draw the hexbox for them
|
||||
if (!aDrawToPath && advance > 0) {
|
||||
if (aDrawMode != gfxFont::GLYPH_PATH && advance > 0) {
|
||||
double glyphX = x;
|
||||
if (isRTL) {
|
||||
glyphX -= advance;
|
||||
@ -1621,7 +1633,7 @@ 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, aDrawToPath, isRTL);
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL);
|
||||
|
||||
if (IsSyntheticBold()) {
|
||||
double strikeOffset = synBoldOnePixelOffset;
|
||||
@ -1637,7 +1649,7 @@ 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, aDrawToPath, isRTL);
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL);
|
||||
} while (--strikeCount > 0);
|
||||
}
|
||||
}
|
||||
@ -1655,7 +1667,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
}
|
||||
}
|
||||
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawToPath, isRTL, true);
|
||||
glyphs.Flush(dt, colPat, scaledFont, aDrawMode, isRTL, true);
|
||||
|
||||
dt->SetTransform(oldMat);
|
||||
}
|
||||
@ -4252,7 +4264,7 @@ gfxTextRun::ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd)
|
||||
|
||||
void
|
||||
gfxTextRun::DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
|
||||
bool aDrawToPath, gfxPoint *aPt,
|
||||
gfxFont::DrawMode aDrawMode, gfxPoint *aPt,
|
||||
PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider,
|
||||
PRUint32 aSpacingStart, PRUint32 aSpacingEnd)
|
||||
@ -4260,7 +4272,7 @@ gfxTextRun::DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
|
||||
nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
|
||||
bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
|
||||
aSpacingStart, aSpacingEnd, &spacingBuffer);
|
||||
aFont->Draw(this, aStart, aEnd, aContext, aDrawToPath, aPt,
|
||||
aFont->Draw(this, aStart, aEnd, aContext, aDrawMode, aPt,
|
||||
haveSpacing ? spacingBuffer.Elements() : nsnull);
|
||||
}
|
||||
|
||||
@ -4318,7 +4330,7 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx,
|
||||
aCtx->Clip();
|
||||
gfxFloat direction = GetDirection();
|
||||
gfxPoint pt(aPt->x - direction*data.mPartAdvance, aPt->y);
|
||||
DrawGlyphs(aFont, aCtx, false, &pt, data.mLigatureStart,
|
||||
DrawGlyphs(aFont, aCtx, gfxFont::GLYPH_FILL, &pt, data.mLigatureStart,
|
||||
data.mLigatureEnd, aProvider, aStart, aEnd);
|
||||
aCtx->Restore();
|
||||
|
||||
@ -4392,11 +4404,12 @@ struct BufferAlphaColor {
|
||||
};
|
||||
|
||||
void
|
||||
gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, gfxFont::DrawMode aDrawMode,
|
||||
PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aProvider, gfxFloat *aAdvanceWidth)
|
||||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
NS_ASSERTION(aDrawMode <= gfxFont::GLYPH_PATH, "GLYPH_PATH cannot be used with GLYPH_FILL or GLYPH_STROKE");
|
||||
|
||||
gfxFloat direction = GetDirection();
|
||||
|
||||
@ -4421,7 +4434,8 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
gfxRGBA currentColor;
|
||||
bool needToRestore = false;
|
||||
|
||||
if (HasNonOpaqueColor(aContext, currentColor) && HasSyntheticBold(this, aStart, aLength)) {
|
||||
if (aDrawMode == gfxFont::GLYPH_FILL && HasNonOpaqueColor(aContext, currentColor)
|
||||
&& HasSyntheticBold(this, aStart, aLength)) {
|
||||
needToRestore = true;
|
||||
// measure text, use the bounding box
|
||||
gfxTextRun::Metrics metrics = MeasureText(aStart, aLength, gfxFont::LOOSE_INK_EXTENTS,
|
||||
@ -4439,10 +4453,16 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
PRUint32 ligatureRunEnd = end;
|
||||
ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
|
||||
|
||||
DrawPartialLigature(font, aContext, start, ligatureRunStart, &pt, aProvider);
|
||||
DrawGlyphs(font, aContext, false, &pt, ligatureRunStart,
|
||||
if (aDrawMode == gfxFont::GLYPH_FILL) {
|
||||
DrawPartialLigature(font, aContext, start, ligatureRunStart, &pt, aProvider);
|
||||
}
|
||||
|
||||
DrawGlyphs(font, aContext, aDrawMode, &pt, ligatureRunStart,
|
||||
ligatureRunEnd, aProvider, ligatureRunStart, ligatureRunEnd);
|
||||
DrawPartialLigature(font, aContext, ligatureRunEnd, end, &pt, aProvider);
|
||||
|
||||
if (aDrawMode == gfxFont::GLYPH_FILL) {
|
||||
DrawPartialLigature(font, aContext, ligatureRunEnd, end, &pt, aProvider);
|
||||
}
|
||||
}
|
||||
|
||||
// composite result when synthetic bolding used
|
||||
@ -4455,38 +4475,6 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::DrawToPath(gfxContext *aContext, gfxPoint aPt,
|
||||
PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aProvider, gfxFloat *aAdvanceWidth)
|
||||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
|
||||
gfxFloat direction = GetDirection();
|
||||
gfxPoint pt = aPt;
|
||||
|
||||
GlyphRunIterator iter(this, aStart, aLength);
|
||||
while (iter.NextRun()) {
|
||||
gfxFont *font = iter.GetGlyphRun()->mFont;
|
||||
PRUint32 start = iter.GetStringStart();
|
||||
PRUint32 end = iter.GetStringEnd();
|
||||
PRUint32 ligatureRunStart = start;
|
||||
PRUint32 ligatureRunEnd = end;
|
||||
ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
|
||||
NS_ASSERTION(ligatureRunStart == start,
|
||||
"Can't draw path starting inside ligature");
|
||||
NS_ASSERTION(ligatureRunEnd == end,
|
||||
"Can't end drawing path inside ligature");
|
||||
|
||||
DrawGlyphs(font, aContext, true, &pt, ligatureRunStart, ligatureRunEnd, aProvider,
|
||||
ligatureRunStart, ligatureRunEnd);
|
||||
}
|
||||
|
||||
if (aAdvanceWidth) {
|
||||
*aAdvanceWidth = (pt.x - aPt.x)*direction;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
|
||||
PRUint32 aStart, PRUint32 aEnd,
|
||||
|
@ -1076,6 +1076,18 @@ public:
|
||||
kAntialiasSubpixel
|
||||
} AntialiasOption;
|
||||
|
||||
// Options for how the text should be drawn
|
||||
typedef enum {
|
||||
// GLYPH_FILL and GLYPH_STROKE draw into the current context
|
||||
// and may be used together with bitwise OR.
|
||||
GLYPH_FILL = 1,
|
||||
// Note: using GLYPH_STROKE will destroy the current path.
|
||||
GLYPH_STROKE = 2,
|
||||
// Appends glyphs to the current path. Can NOT be used with
|
||||
// GLYPH_FILL or GLYPH_STROKE.
|
||||
GLYPH_PATH = 4
|
||||
} DrawMode;
|
||||
|
||||
protected:
|
||||
nsAutoRefCnt mRefCnt;
|
||||
cairo_scaled_font_t *mScaledFont;
|
||||
@ -1288,8 +1300,8 @@ public:
|
||||
* glyphs, before-spacing is inserted to the right of characters). There
|
||||
* are aEnd - aStart elements in this array, unless it's null to indicate
|
||||
* that there is no spacing.
|
||||
* @param aDrawToPath when true, add the glyph outlines to the current path
|
||||
* instead of drawing the glyphs
|
||||
* @param aDrawMode specifies whether the fill or stroke of the glyph should be
|
||||
* drawn, or if it should be drawn into the current path
|
||||
*
|
||||
* Callers guarantee:
|
||||
* -- aStart and aEnd are aligned to cluster and ligature boundaries
|
||||
@ -1299,7 +1311,7 @@ public:
|
||||
* calls cairo_show_glyphs or cairo_glyph_path.
|
||||
*/
|
||||
virtual void Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
gfxContext *aContext, bool aDrawToPath, gfxPoint *aBaselineOrigin,
|
||||
gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aBaselineOrigin,
|
||||
Spacing *aSpacing);
|
||||
/**
|
||||
* Measure a run of characters. See gfxTextRun::Metrics.
|
||||
@ -2343,29 +2355,11 @@ public:
|
||||
* if they overlap (perhaps due to negative spacing).
|
||||
*/
|
||||
void Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
gfxFont::DrawMode aDrawMode,
|
||||
PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aProvider,
|
||||
gfxFloat *aAdvanceWidth);
|
||||
|
||||
/**
|
||||
* Renders a substring to a path. Uses only GetSpacing from aBreakProvider.
|
||||
* The provided point is the baseline origin on the left of the string
|
||||
* for LTR, on the right of the string for RTL.
|
||||
* @param aAdvanceWidth if non-null, the advance width of the substring
|
||||
* is returned here.
|
||||
*
|
||||
* Drawing should respect advance widths in the way that Draw above does.
|
||||
*
|
||||
* Glyphs should be drawn in logical content order.
|
||||
*
|
||||
* UNLIKE Draw above, this cannot be used to render substrings that start or
|
||||
* end inside a ligature.
|
||||
*/
|
||||
void DrawToPath(gfxContext *aContext, gfxPoint aPt,
|
||||
PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aBreakProvider,
|
||||
gfxFloat *aAdvanceWidth);
|
||||
|
||||
/**
|
||||
* Computes the ReflowMetrics for a substring.
|
||||
* Uses GetSpacing from aBreakProvider.
|
||||
@ -2807,8 +2801,9 @@ private:
|
||||
Metrics *aMetrics);
|
||||
|
||||
// **** drawing helper ****
|
||||
void DrawGlyphs(gfxFont *aFont, gfxContext *aContext, bool aDrawToPath,
|
||||
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
|
||||
void DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
|
||||
gfxFont::DrawMode aDrawMode, gfxPoint *aPt,
|
||||
PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider,
|
||||
PRUint32 aSpacingStart, PRUint32 aSpacingEnd);
|
||||
|
||||
|
@ -5562,7 +5562,7 @@ nsTextFrame::DrawTextRun(gfxContext* const aCtx,
|
||||
gfxFloat& aAdvanceWidth,
|
||||
bool aDrawSoftHyphen)
|
||||
{
|
||||
mTextRun->Draw(aCtx, aTextBaselinePt, aOffset, aLength,
|
||||
mTextRun->Draw(aCtx, aTextBaselinePt, gfxFont::GLYPH_FILL, aOffset, aLength,
|
||||
&aProvider, &aAdvanceWidth);
|
||||
|
||||
if (aDrawSoftHyphen) {
|
||||
@ -5575,7 +5575,7 @@ nsTextFrame::DrawTextRun(gfxContext* const aCtx,
|
||||
gfxFloat hyphenBaselineX = aTextBaselinePt.x + mTextRun->GetDirection() * aAdvanceWidth -
|
||||
(mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nsnull) : 0);
|
||||
hyphenTextRun->Draw(aCtx, gfxPoint(hyphenBaselineX, aTextBaselinePt.y),
|
||||
0, hyphenTextRun->GetLength(), nsnull, nsnull);
|
||||
gfxFont::GLYPH_FILL, 0, hyphenTextRun->GetLength(), nsnull, nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,10 @@
|
||||
|
||||
<g transform="scale(2)">
|
||||
<text x="10" y="30"
|
||||
fill="black" stroke="black" stroke-width="1">abc</text>
|
||||
fill="black" stroke="black" stroke-width="1">a</text>
|
||||
<text x="20" y="30"
|
||||
fill="black" stroke="black" stroke-width="1">b</text>
|
||||
<text x="30" y="30"
|
||||
fill="black" stroke="black" stroke-width="1">c</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 496 B |
@ -5,7 +5,7 @@
|
||||
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=595209 -->
|
||||
|
||||
<g transform="scale(2)">
|
||||
<text x="10" y="30" rotate="0"
|
||||
<text x="10, 20, 30" y="30" rotate="0"
|
||||
fill="black" stroke="black" stroke-width="1">abc</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 340 B |
@ -382,12 +382,7 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext,
|
||||
// there is a pattern or gradient on the text
|
||||
iter.Reset();
|
||||
|
||||
gfx->NewPath();
|
||||
AddCharactersToPath(&iter, gfx);
|
||||
gfx->Stroke();
|
||||
// We need to clear the context's path so state doesn't leak
|
||||
// out. See bug 337753.
|
||||
gfx->NewPath();
|
||||
StrokeCharacters(&iter, gfx);
|
||||
}
|
||||
gfx->Restore();
|
||||
|
||||
@ -554,18 +549,17 @@ void
|
||||
nsSVGGlyphFrame::AddCharactersToPath(CharacterIterator *aIter,
|
||||
gfxContext *aContext)
|
||||
{
|
||||
aIter->SetLineWidthAndDashesForDrawing(aContext);
|
||||
if (aIter->SetupForDirectTextRunDrawing(aContext)) {
|
||||
mTextRun->DrawToPath(aContext, gfxPoint(0, 0), 0,
|
||||
mTextRun->GetLength(), nsnull, nsnull);
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), gfxFont::GLYPH_PATH, 0,
|
||||
mTextRun->GetLength(), nsnull, nsnull);
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 i;
|
||||
while ((i = aIter->NextCluster()) != aIter->InvalidCluster()) {
|
||||
aIter->SetupForDrawing(aContext);
|
||||
mTextRun->DrawToPath(aContext, gfxPoint(0, 0), i, aIter->ClusterLength(),
|
||||
nsnull, nsnull);
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), gfxFont::GLYPH_PATH, i,
|
||||
aIter->ClusterLength(), nsnull, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,7 +590,7 @@ nsSVGGlyphFrame::FillCharacters(CharacterIterator *aIter,
|
||||
gfxContext *aContext)
|
||||
{
|
||||
if (aIter->SetupForDirectTextRunDrawing(aContext)) {
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), 0,
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), gfxFont::GLYPH_FILL, 0,
|
||||
mTextRun->GetLength(), nsnull, nsnull);
|
||||
return;
|
||||
}
|
||||
@ -604,8 +598,27 @@ nsSVGGlyphFrame::FillCharacters(CharacterIterator *aIter,
|
||||
PRUint32 i;
|
||||
while ((i = aIter->NextCluster()) != aIter->InvalidCluster()) {
|
||||
aIter->SetupForDrawing(aContext);
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), i, aIter->ClusterLength(),
|
||||
nsnull, nsnull);
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), gfxFont::GLYPH_FILL, i,
|
||||
aIter->ClusterLength(), nsnull, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGGlyphFrame::StrokeCharacters(CharacterIterator *aIter,
|
||||
gfxContext *aContext)
|
||||
{
|
||||
aIter->SetLineWidthAndDashesForDrawing(aContext);
|
||||
if (aIter->SetupForDirectTextRunDrawing(aContext)) {
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), gfxFont::GLYPH_STROKE, 0,
|
||||
mTextRun->GetLength(), nsnull, nsnull);
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 i;
|
||||
while ((i = aIter->NextCluster()) != aIter->InvalidCluster()) {
|
||||
aIter->SetupForDrawing(aContext);
|
||||
mTextRun->Draw(aContext, gfxPoint(0, 0), gfxFont::GLYPH_STROKE, i,
|
||||
aIter->ClusterLength(), nsnull, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,8 @@ protected:
|
||||
gfxContext *aContext);
|
||||
void FillCharacters(CharacterIterator *aIter,
|
||||
gfxContext *aContext);
|
||||
void StrokeCharacters(CharacterIterator *aIter,
|
||||
gfxContext *aContext);
|
||||
|
||||
void NotifyGlyphMetricsChange();
|
||||
void SetupGlobalTransform(gfxContext *aContext);
|
||||
|
Loading…
Reference in New Issue
Block a user