#include "GrFontScaler.h"
#include "GrIndexBuffer.h"
#include "GrStrokeInfo.h"
+#include "GrTexturePriv.h"
#include "GrTextStrike.h"
#include "GrTextStrike_impl.h"
-#include "SkColorPriv.h"
-#include "SkPath.h"
-#include "SkRTConf.h"
-#include "SkStrokeRec.h"
#include "effects/GrCustomCoordsTextureEffect.h"
+#include "effects/GrSimpleTextureEffect.h"
#include "SkAutoKern.h"
+#include "SkColorPriv.h"
#include "SkDraw.h"
#include "SkDrawProcs.h"
#include "SkGlyphCache.h"
#include "SkGpuDevice.h"
#include "SkGr.h"
+#include "SkPath.h"
+#include "SkRTConf.h"
+#include "SkStrokeRec.h"
#include "SkTextMapStateProc.h"
SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
namespace {
// position + texture coord
-extern const GrVertexAttrib gTextVertexAttribs[] = {
+extern const GrVertexAttrib gLCDVertexAttribs[] = {
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
{kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
};
-static const size_t kTextVASize = 2 * sizeof(SkPoint);
+static const size_t kLCDTextVASize = 2 * sizeof(SkPoint);
+
+// position + local coord
+extern const GrVertexAttrib gColorVertexAttribs[] = {
+ {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
+ {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}
+};
+
+static const size_t kColorTextVASize = 2 * sizeof(SkPoint);
// position + color + texture coord
-extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
+extern const GrVertexAttrib gGrayVertexAttribs[] = {
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
{kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
{kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
};
-static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
+static const size_t kGrayTextVASize = 2 * sizeof(SkPoint) + sizeof(GrColor);
+static const int kVerticesPerGlyph = 4;
+static const int kIndicesPerGlyph = 6;
};
GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
fStrike = NULL;
fCurrTexture = NULL;
- fCurrVertex = 0;
fEffectTextureUniqueID = SK_InvalidUniqueID;
fVertices = NULL;
- fMaxVertices = 0;
+ fCurrVertex = 0;
+ fAllocVertexCount = 0;
+ fTotalVertexCount = 0;
fVertexBounds.setLargestInverted();
}
+GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context,
+ const SkDeviceProperties& props) {
+ return SkNEW_ARGS(GrBitmapTextContext, (context, props));
+}
+
GrBitmapTextContext::~GrBitmapTextContext() {
- this->flushGlyphs();
+ this->finish();
}
bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
}
-static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
- unsigned r = SkColorGetR(c);
- unsigned g = SkColorGetG(c);
- unsigned b = SkColorGetB(c);
- return GrColorPackRGBA(r, g, b, 0xff);
-}
-
-void GrBitmapTextContext::flushGlyphs() {
- if (NULL == fDrawTarget) {
- return;
- }
-
- GrDrawState* drawState = fDrawTarget->drawState();
- GrDrawState::AutoRestoreEffects are(drawState);
- drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
-
- if (fCurrVertex > 0) {
- // setup our sampler state for our text texture/atlas
- SkASSERT(SkIsAlign4(fCurrVertex));
- SkASSERT(fCurrTexture);
- GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
-
- uint32_t textureUniqueID = fCurrTexture->getUniqueID();
-
- if (textureUniqueID != fEffectTextureUniqueID) {
- fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
- params));
- fEffectTextureUniqueID = textureUniqueID;
- }
-
- // This effect could be stored with one of the cache objects (atlas?)
- drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
- SkASSERT(fStrike);
- switch (fStrike->getMaskFormat()) {
- // Color bitmap text
- case kARGB_GrMaskFormat:
- SkASSERT(!drawState->hasColorVertexAttribute());
- drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
- drawState->setColor(0xffffffff);
- break;
- // LCD text
- case kA888_GrMaskFormat:
- case kA565_GrMaskFormat: {
- if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
- kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
- fPaint.numColorStages()) {
- GrPrintf("LCD Text will not draw correctly.\n");
- }
- SkASSERT(!drawState->hasColorVertexAttribute());
- // We don't use the GrPaint's color in this case because it's been premultiplied by
- // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
- // the mask texture color. The end result is that we get
- // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
- int a = SkColorGetA(fSkPaint.getColor());
- // paintAlpha
- drawState->setColor(SkColorSetARGB(a, a, a, a));
- // paintColor
- drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
- drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
- break;
- }
- // Grayscale/BW text
- case kA8_GrMaskFormat:
- // set back to normal in case we took LCD path previously.
- drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
- // We're using per-vertex color.
- SkASSERT(drawState->hasColorVertexAttribute());
- break;
- default:
- SkFAIL("Unexepected mask format.");
- }
- int nGlyphs = fCurrVertex / 4;
- fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
- fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
- nGlyphs,
- 4, 6, &fVertexBounds);
-
- fDrawTarget->resetVertexSource();
- fVertices = NULL;
- fMaxVertices = 0;
- fCurrVertex = 0;
- fVertexBounds.setLargestInverted();
- SkSafeSetNull(fCurrTexture);
- }
-}
-
inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
GrTextContext::init(paint, skPaint);
fCurrVertex = 0;
fVertices = NULL;
- fMaxVertices = 0;
+ fAllocVertexCount = 0;
+ fTotalVertexCount = 0;
}
-inline void GrBitmapTextContext::finish() {
- this->flushGlyphs();
-
- GrTextContext::finish();
-}
-
-void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
+void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
const char text[], size_t byteLength,
SkScalar x, SkScalar y) {
SkASSERT(byteLength == 0 || text != NULL);
}
// need to measure first
+ int numGlyphs;
if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
- SkVector stop;
-
- MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
+ SkVector stopVector;
+ numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
- SkScalar stopX = stop.fX;
- SkScalar stopY = stop.fY;
+ SkScalar stopX = stopVector.fX;
+ SkScalar stopY = stopVector.fY;
if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
stopX = SkScalarHalf(stopX);
}
x -= stopX;
y -= stopY;
+ } else {
+ numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
}
+ fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
const char* stop = text + byteLength;
fx += autokern.adjust(glyph);
if (glyph.fWidth) {
- this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
- glyph.getSubXFixed(),
- glyph.getSubYFixed()),
- SkFixedFloorToFixed(fx),
- SkFixedFloorToFixed(fy),
- fontScaler);
+ this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+ glyph.getSubXFixed(),
+ glyph.getSubYFixed()),
+ SkFixedFloorToFixed(fx),
+ SkFixedFloorToFixed(fy),
+ fontScaler);
}
fx += glyph.fAdvanceX;
this->finish();
}
-void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
+void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
const char text[], size_t byteLength,
- const SkScalar pos[], SkScalar constY,
- int scalarsPerPosition) {
+ const SkScalar pos[], int scalarsPerPosition,
+ const SkPoint& offset) {
SkASSERT(byteLength == 0 || text != NULL);
SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
GrContext::AutoMatrix autoMatrix;
autoMatrix.setIdentity(fContext, &fPaint);
+ int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
+ fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
+
const char* stop = text + byteLength;
SkTextAlignProc alignProc(fSkPaint.getTextAlign());
- SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
+ SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
SkFixed halfSampleX = 0, halfSampleY = 0;
if (cache->isSubpixel()) {
fx & fxMask, fy & fyMask);
if (glyph.fWidth) {
- this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
- glyph.getSubXFixed(),
- glyph.getSubYFixed()),
- SkFixedFloorToFixed(fx),
- SkFixedFloorToFixed(fy),
- fontScaler);
+ this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+ glyph.getSubXFixed(),
+ glyph.getSubYFixed()),
+ SkFixedFloorToFixed(fx),
+ SkFixedFloorToFixed(fy),
+ fontScaler);
}
pos += scalarsPerPosition;
}
SkASSERT(prevAdvY == glyph.fAdvanceY);
SkASSERT(glyph.fWidth);
- this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
- glyph.getSubXFixed(),
- glyph.getSubYFixed()),
- SkFixedFloorToFixed(fx),
- SkFixedFloorToFixed(fy),
- fontScaler);
+ this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+ glyph.getSubXFixed(),
+ glyph.getSubYFixed()),
+ SkFixedFloorToFixed(fx),
+ SkFixedFloorToFixed(fy),
+ fontScaler);
}
pos += scalarsPerPosition;
}
SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
- this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
- glyph.getSubXFixed(),
- glyph.getSubYFixed()),
- SkFixedFloorToFixed(fx),
- SkFixedFloorToFixed(fy),
- fontScaler);
+ this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+ glyph.getSubXFixed(),
+ glyph.getSubYFixed()),
+ SkFixedFloorToFixed(fx),
+ SkFixedFloorToFixed(fy),
+ fontScaler);
}
pos += scalarsPerPosition;
}
SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
- this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
- glyph.getSubXFixed(),
- glyph.getSubYFixed()),
- SkFixedFloorToFixed(fx),
- SkFixedFloorToFixed(fy),
- fontScaler);
+ this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+ glyph.getSubXFixed(),
+ glyph.getSubYFixed()),
+ SkFixedFloorToFixed(fx),
+ SkFixedFloorToFixed(fy),
+ fontScaler);
}
pos += scalarsPerPosition;
}
this->finish();
}
-void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
- SkFixed vx, SkFixed vy,
- GrFontScaler* scaler) {
+static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, GrMaskFormat maskFormat) {
+ if (numVertices <= 0) {
+ return NULL;
+ }
+
+ // set up attributes
+ if (kA8_GrMaskFormat == maskFormat) {
+ drawTarget->drawState()->setVertexAttribs<gGrayVertexAttribs>(
+ SK_ARRAY_COUNT(gGrayVertexAttribs), kGrayTextVASize);
+ } else if (kARGB_GrMaskFormat == maskFormat) {
+ drawTarget->drawState()->setVertexAttribs<gColorVertexAttribs>(
+ SK_ARRAY_COUNT(gColorVertexAttribs), kColorTextVASize);
+ } else {
+ drawTarget->drawState()->setVertexAttribs<gLCDVertexAttribs>(
+ SK_ARRAY_COUNT(gLCDVertexAttribs), kLCDTextVASize);
+ }
+ void* vertices = NULL;
+ bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
+ 0,
+ &vertices,
+ NULL);
+ GrAlwaysAssert(success);
+ return vertices;
+}
+
+void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
+ SkFixed vx, SkFixed vy,
+ GrFontScaler* scaler) {
if (NULL == fDrawTarget) {
return;
}
}
// try to clear out an unused plot before we flush
- if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
+ if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
fStrike->addGlyphToAtlas(glyph, scaler)) {
goto HAS_ATLAS;
}
}
// flush any accumulated draws to allow us to free up a plot
- this->flushGlyphs();
+ this->flush();
fContext->flush();
// we should have an unused plot now
- if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
+ if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
fStrike->addGlyphToAtlas(glyph, scaler)) {
goto HAS_ATLAS;
}
glyph->fPath = path;
}
+ // flush any accumulated draws before drawing this glyph as a path.
+ this->flush();
+
GrContext::AutoMatrix am;
SkMatrix translate;
translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
am.setPreConcat(fContext, translate, &tmpPaint);
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
+
+ // remove this glyph from the vertices we need to allocate
+ fTotalVertexCount -= kVerticesPerGlyph;
return;
}
width = SkIntToFixed(width);
height = SkIntToFixed(height);
+ // the current texture/maskformat must match what the glyph needs
GrTexture* texture = glyph->fPlot->texture();
SkASSERT(texture);
- if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
- this->flushGlyphs();
+ if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
+ this->flush();
fCurrTexture = texture;
fCurrTexture->ref();
+ fCurrMaskFormat = glyph->fMaskFormat;
}
- bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
-
if (NULL == fVertices) {
- // If we need to reserve vertices allow the draw target to suggest
- // a number of verts to reserve and whether to perform a flush.
- fMaxVertices = kMinRequestedVerts;
- if (useColorVerts) {
- fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
- SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
- } else {
- fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
- SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
- }
- bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
- if (flush) {
- this->flushGlyphs();
- fContext->flush();
- if (useColorVerts) {
- fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
- SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
- } else {
- fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
- SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
- }
- }
- fMaxVertices = kDefaultRequestedVerts;
- // ignore return, no point in flushing again.
- fDrawTarget->geometryHints(&fMaxVertices, NULL);
-
- int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
- if (fMaxVertices < kMinRequestedVerts) {
- fMaxVertices = kDefaultRequestedVerts;
- } else if (fMaxVertices > maxQuadVertices) {
- // don't exceed the limit of the index buffer
- fMaxVertices = maxQuadVertices;
- }
- bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
- 0,
- &fVertices,
- NULL);
- GrAlwaysAssert(success);
+ int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
+ fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
+ fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
}
SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
r.fRight = SkFixedToFloat(vx + width);
r.fBottom = SkFixedToFloat(vy + height);
- fVertexBounds.growToInclude(r);
-
- size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
- (2 * sizeof(SkPoint));
+ fVertexBounds.joinNonEmptyArg(r);
+
+ size_t vertSize;
+ switch (fCurrMaskFormat) {
+ case kA8_GrMaskFormat:
+ vertSize = kGrayTextVASize;
+ break;
+ case kARGB_GrMaskFormat:
+ vertSize = kColorTextVASize;
+ default:
+ vertSize = kLCDTextVASize;
+ }
SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
// The texture coords are last in both the with and without color vertex layouts.
SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
- textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
- SkFixedToFloat(texture->normalizeFixedY(ty)),
- SkFixedToFloat(texture->normalizeFixedX(tx + width)),
- SkFixedToFloat(texture->normalizeFixedY(ty + height)),
+ textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
+ SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
+ SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
+ SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
vertSize);
- if (useColorVerts) {
+ if (kA8_GrMaskFormat == fCurrMaskFormat) {
if (0xFF == GrColorUnpackA(fPaint.getColor())) {
fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
}
}
fCurrVertex += 4;
}
+
+static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
+ unsigned r = SkColorGetR(c);
+ unsigned g = SkColorGetG(c);
+ unsigned b = SkColorGetB(c);
+ return GrColorPackRGBA(r, g, b, 0xff);
+}
+
+void GrBitmapTextContext::flush() {
+ if (NULL == fDrawTarget) {
+ return;
+ }
+
+ GrDrawState* drawState = fDrawTarget->drawState();
+ GrDrawState::AutoRestoreEffects are(drawState);
+ drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
+
+ if (fCurrVertex > 0) {
+ // setup our sampler state for our text texture/atlas
+ SkASSERT(SkIsAlign4(fCurrVertex));
+ SkASSERT(fCurrTexture);
+ GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
+
+ // This effect could be stored with one of the cache objects (atlas?)
+ if (kARGB_GrMaskFormat == fCurrMaskFormat) {
+ GrFragmentProcessor* fragProcessor = GrSimpleTextureEffect::Create(fCurrTexture,
+ SkMatrix::I(),
+ params);
+ drawState->addColorProcessor(fragProcessor)->unref();
+ } else {
+ uint32_t textureUniqueID = fCurrTexture->getUniqueID();
+ if (textureUniqueID != fEffectTextureUniqueID) {
+ fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
+ params));
+ fEffectTextureUniqueID = textureUniqueID;
+ }
+
+ drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
+ }
+
+ SkASSERT(fStrike);
+ switch (fCurrMaskFormat) {
+ // Color bitmap text
+ case kARGB_GrMaskFormat:
+ SkASSERT(!drawState->hasColorVertexAttribute());
+ drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
+ drawState->setAlpha(fSkPaint.getAlpha());
+ break;
+ // LCD text
+ case kA888_GrMaskFormat:
+ case kA565_GrMaskFormat: {
+ if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
+ kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
+ fPaint.numColorStages()) {
+ SkDebugf("LCD Text will not draw correctly.\n");
+ }
+ SkASSERT(!drawState->hasColorVertexAttribute());
+ // We don't use the GrPaint's color in this case because it's been premultiplied by
+ // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
+ // the mask texture color. The end result is that we get
+ // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
+ int a = SkColorGetA(fSkPaint.getColor());
+ // paintAlpha
+ drawState->setColor(SkColorSetARGB(a, a, a, a));
+ // paintColor
+ drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
+ drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
+ break;
+ }
+ // Grayscale/BW text
+ case kA8_GrMaskFormat:
+ // set back to normal in case we took LCD path previously.
+ drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
+ // We're using per-vertex color.
+ SkASSERT(drawState->hasColorVertexAttribute());
+ break;
+ default:
+ SkFAIL("Unexpected mask format.");
+ }
+ int nGlyphs = fCurrVertex / kVerticesPerGlyph;
+ fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
+ fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
+ nGlyphs,
+ kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds);
+
+ fDrawTarget->resetVertexSource();
+ fVertices = NULL;
+ fAllocVertexCount = 0;
+ // reset to be those that are left
+ fTotalVertexCount -= fCurrVertex;
+ fCurrVertex = 0;
+ fVertexBounds.setLargestInverted();
+ SkSafeSetNull(fCurrTexture);
+ }
+}
+
+inline void GrBitmapTextContext::finish() {
+ this->flush();
+ fTotalVertexCount = 0;
+
+ GrTextContext::finish();
+}
+