Rearrange code in TextContexts to be more consistent and match style guide.
Review URL: https://codereview.chromium.org/641613003
This commit is contained in:
parent
e97d82b6e5
commit
0fedb19812
@ -67,99 +67,13 @@ GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
|
||||
}
|
||||
|
||||
GrBitmapTextContext::~GrBitmapTextContext() {
|
||||
this->flushGlyphs();
|
||||
this->flush();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -172,12 +86,6 @@ inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPai
|
||||
fMaxVertices = 0;
|
||||
}
|
||||
|
||||
inline void GrBitmapTextContext::finish() {
|
||||
this->flushGlyphs();
|
||||
|
||||
GrTextContext::finish();
|
||||
}
|
||||
|
||||
void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) {
|
||||
@ -254,12 +162,12 @@ void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
|
||||
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;
|
||||
@ -328,12 +236,12 @@ void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPai
|
||||
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;
|
||||
}
|
||||
@ -361,12 +269,12 @@ void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPai
|
||||
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;
|
||||
}
|
||||
@ -384,12 +292,12 @@ void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPai
|
||||
|
||||
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;
|
||||
}
|
||||
@ -407,12 +315,12 @@ void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPai
|
||||
|
||||
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;
|
||||
}
|
||||
@ -422,9 +330,9 @@ void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPai
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
|
||||
SkFixed vx, SkFixed vy,
|
||||
GrFontScaler* scaler) {
|
||||
void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
|
||||
SkFixed vx, SkFixed vy,
|
||||
GrFontScaler* scaler) {
|
||||
if (NULL == fDrawTarget) {
|
||||
return;
|
||||
}
|
||||
@ -474,7 +382,7 @@ void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -518,7 +426,7 @@ HAS_ATLAS:
|
||||
SkASSERT(texture);
|
||||
|
||||
if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
|
||||
this->flushGlyphs();
|
||||
this->flush();
|
||||
fCurrTexture = texture;
|
||||
fCurrTexture->ref();
|
||||
}
|
||||
@ -538,7 +446,7 @@ HAS_ATLAS:
|
||||
}
|
||||
bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
|
||||
if (flush) {
|
||||
this->flushGlyphs();
|
||||
this->flush();
|
||||
fContext->flush();
|
||||
if (useColorVerts) {
|
||||
fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
|
||||
@ -607,3 +515,96 @@ HAS_ATLAS:
|
||||
}
|
||||
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);
|
||||
|
||||
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::finish() {
|
||||
this->flush();
|
||||
|
||||
GrTextContext::finish();
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ public:
|
||||
GrBitmapTextContext(GrContext*, const SkDeviceProperties&);
|
||||
virtual ~GrBitmapTextContext();
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
virtual void drawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) SK_OVERRIDE;
|
||||
virtual void drawPosText(const GrPaint&, const SkPaint&,
|
||||
@ -28,16 +30,7 @@ public:
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset) SK_OVERRIDE;
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
GrTextStrike* fStrike;
|
||||
|
||||
void init(const GrPaint&, const SkPaint&);
|
||||
void drawPackedGlyph(GrGlyph::PackedID, SkFixed left, SkFixed top, GrFontScaler*);
|
||||
void flushGlyphs(); // automatically called by destructor
|
||||
void finish();
|
||||
|
||||
enum {
|
||||
kMinRequestedGlyphs = 1,
|
||||
kDefaultRequestedGlyphs = 64,
|
||||
@ -45,6 +38,7 @@ private:
|
||||
kDefaultRequestedVerts = kDefaultRequestedGlyphs * 4,
|
||||
};
|
||||
|
||||
GrTextStrike* fStrike;
|
||||
void* fVertices;
|
||||
int32_t fMaxVertices;
|
||||
GrTexture* fCurrTexture;
|
||||
@ -53,6 +47,12 @@ private:
|
||||
uint32_t fEffectTextureUniqueID;
|
||||
int fCurrVertex;
|
||||
SkRect fVertexBounds;
|
||||
|
||||
void init(const GrPaint&, const SkPaint&);
|
||||
void appendGlyph(GrGlyph::PackedID, SkFixed left, SkFixed top, GrFontScaler*);
|
||||
void flush(); // automatically called by destructor
|
||||
void finish();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -81,7 +81,7 @@ GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
|
||||
}
|
||||
|
||||
GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
|
||||
this->flushGlyphs();
|
||||
this->flush();
|
||||
SkSafeSetNull(fGammaTexture);
|
||||
}
|
||||
|
||||
@ -114,337 +114,6 @@ bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
|
||||
return rec.getFormat() != SkMask::kARGB32_Format;
|
||||
}
|
||||
|
||||
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 GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColor) {
|
||||
GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
|
||||
GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
|
||||
|
||||
uint32_t textureUniqueID = fCurrTexture->getUniqueID();
|
||||
const SkMatrix& ctm = fContext->getMatrix();
|
||||
|
||||
// set up any flags
|
||||
uint32_t flags = 0;
|
||||
flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
|
||||
flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
|
||||
flags |= fUseLCDText && ctm.rectStaysRect() ?
|
||||
kRectToRect_DistanceFieldEffectFlag : 0;
|
||||
bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.fPixelGeometry);
|
||||
flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
|
||||
|
||||
// see if we need to create a new effect
|
||||
if (textureUniqueID != fEffectTextureUniqueID ||
|
||||
filteredColor != fEffectColor ||
|
||||
flags != fEffectFlags) {
|
||||
if (fUseLCDText) {
|
||||
GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
|
||||
fCachedGeometryProcessor.reset(
|
||||
GrDistanceFieldLCDTextureEffect::Create(fCurrTexture,
|
||||
params,
|
||||
fGammaTexture,
|
||||
gammaParams,
|
||||
colorNoPreMul,
|
||||
flags));
|
||||
} else {
|
||||
#ifdef SK_GAMMA_APPLY_TO_A8
|
||||
U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.getGamma(),
|
||||
filteredColor);
|
||||
fCachedGeometryProcessor.reset(
|
||||
GrDistanceFieldTextureEffect::Create(fCurrTexture,
|
||||
params,
|
||||
fGammaTexture,
|
||||
gammaParams,
|
||||
lum/255.f,
|
||||
flags));
|
||||
#else
|
||||
fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
|
||||
params, flags));
|
||||
#endif
|
||||
}
|
||||
fEffectTextureUniqueID = textureUniqueID;
|
||||
fEffectColor = filteredColor;
|
||||
fEffectFlags = flags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GrDistanceFieldTextContext::flushGlyphs() {
|
||||
if (NULL == fDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
GrDrawState* drawState = fDrawTarget->drawState();
|
||||
GrDrawState::AutoRestoreEffects are(drawState);
|
||||
|
||||
drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
|
||||
|
||||
if (fCurrVertex > 0) {
|
||||
// setup our sampler state for our text texture/atlas
|
||||
SkASSERT(SkIsAlign4(fCurrVertex));
|
||||
|
||||
// get our current color
|
||||
SkColor filteredColor;
|
||||
SkColorFilter* colorFilter = fSkPaint.getColorFilter();
|
||||
if (colorFilter) {
|
||||
filteredColor = colorFilter->filterColor(fSkPaint.getColor());
|
||||
} else {
|
||||
filteredColor = fSkPaint.getColor();
|
||||
}
|
||||
this->setupCoverageEffect(filteredColor);
|
||||
|
||||
// Effects could be stored with one of the cache objects (atlas?)
|
||||
drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
|
||||
|
||||
// Set draw state
|
||||
if (fUseLCDText) {
|
||||
GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
|
||||
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(colorNoPreMul);
|
||||
drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
|
||||
} else {
|
||||
// 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());
|
||||
}
|
||||
int nGlyphs = fCurrVertex / 4;
|
||||
fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
|
||||
fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
|
||||
nGlyphs,
|
||||
4, 6, &fVertexBounds);
|
||||
fDrawTarget->resetVertexSource();
|
||||
fVertices = NULL;
|
||||
fMaxVertices = 0;
|
||||
fCurrVertex = 0;
|
||||
SkSafeSetNull(fCurrTexture);
|
||||
fVertexBounds.setLargestInverted();
|
||||
}
|
||||
}
|
||||
|
||||
void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
|
||||
SkFixed vx, SkFixed vy,
|
||||
GrFontScaler* scaler) {
|
||||
if (NULL == fDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == fStrike) {
|
||||
fStrike = fContext->getFontCache()->getStrike(scaler, true);
|
||||
}
|
||||
|
||||
GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
|
||||
if (NULL == glyph || glyph->fBounds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar sx = SkFixedToScalar(vx);
|
||||
SkScalar sy = SkFixedToScalar(vy);
|
||||
/*
|
||||
// not valid, need to find a different solution for this
|
||||
vx += SkIntToFixed(glyph->fBounds.fLeft);
|
||||
vy += SkIntToFixed(glyph->fBounds.fTop);
|
||||
|
||||
// keep them as ints until we've done the clip-test
|
||||
GrFixed width = glyph->fBounds.width();
|
||||
GrFixed height = glyph->fBounds.height();
|
||||
|
||||
// check if we clipped out
|
||||
if (true || NULL == glyph->fPlot) {
|
||||
int x = vx >> 16;
|
||||
int y = vy >> 16;
|
||||
if (fClipRect.quickReject(x, y, x + width, y + height)) {
|
||||
// SkCLZ(3); // so we can set a break-point in the debugger
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (NULL == glyph->fPlot) {
|
||||
if (!fStrike->glyphTooLargeForAtlas(glyph)) {
|
||||
if (fStrike->addGlyphToAtlas(glyph, scaler)) {
|
||||
goto HAS_ATLAS;
|
||||
}
|
||||
|
||||
// try to clear out an unused plot before we flush
|
||||
if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
|
||||
fStrike->addGlyphToAtlas(glyph, scaler)) {
|
||||
goto HAS_ATLAS;
|
||||
}
|
||||
|
||||
if (c_DumpFontCache) {
|
||||
#ifdef SK_DEVELOPER
|
||||
fContext->getFontCache()->dump();
|
||||
#endif
|
||||
}
|
||||
|
||||
// before we purge the cache, we must flush any accumulated draws
|
||||
this->flushGlyphs();
|
||||
fContext->flush();
|
||||
|
||||
// we should have an unused plot now
|
||||
if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
|
||||
fStrike->addGlyphToAtlas(glyph, scaler)) {
|
||||
goto HAS_ATLAS;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == glyph->fPath) {
|
||||
SkPath* path = SkNEW(SkPath);
|
||||
if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
|
||||
// flag the glyph as being dead?
|
||||
delete path;
|
||||
return;
|
||||
}
|
||||
glyph->fPath = path;
|
||||
}
|
||||
|
||||
GrContext::AutoMatrix am;
|
||||
SkMatrix ctm;
|
||||
ctm.setScale(fTextRatio, fTextRatio);
|
||||
ctm.postTranslate(sx, sy);
|
||||
GrPaint tmpPaint(fPaint);
|
||||
am.setPreConcat(fContext, ctm, &tmpPaint);
|
||||
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
|
||||
fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
HAS_ATLAS:
|
||||
SkASSERT(glyph->fPlot);
|
||||
GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
|
||||
glyph->fPlot->setDrawToken(drawToken);
|
||||
|
||||
GrTexture* texture = glyph->fPlot->texture();
|
||||
SkASSERT(texture);
|
||||
|
||||
if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
|
||||
this->flushGlyphs();
|
||||
fCurrTexture = texture;
|
||||
fCurrTexture->ref();
|
||||
}
|
||||
|
||||
bool useColorVerts = !fUseLCDText;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
|
||||
SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
|
||||
SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
|
||||
SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
|
||||
|
||||
SkScalar scale = fTextRatio;
|
||||
dx *= scale;
|
||||
dy *= scale;
|
||||
sx += dx;
|
||||
sy += dy;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
|
||||
SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
|
||||
SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
|
||||
SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
|
||||
SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
|
||||
|
||||
SkRect r;
|
||||
r.fLeft = sx;
|
||||
r.fTop = sy;
|
||||
r.fRight = sx + width;
|
||||
r.fBottom = sy + height;
|
||||
|
||||
fVertexBounds.joinNonEmptyArg(r);
|
||||
|
||||
size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint))
|
||||
: (2 * sizeof(SkPoint) + sizeof(GrColor));
|
||||
|
||||
SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
|
||||
|
||||
SkPoint* positions = reinterpret_cast<SkPoint*>(
|
||||
reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
|
||||
positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
|
||||
|
||||
// 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->texturePriv().normalizeFixedX(tx)),
|
||||
SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
|
||||
SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
|
||||
SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
|
||||
vertSize);
|
||||
if (useColorVerts) {
|
||||
if (0xFF == GrColorUnpackA(fPaint.getColor())) {
|
||||
fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
|
||||
}
|
||||
// color comes after position.
|
||||
GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*colors = fPaint.getColor();
|
||||
colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
|
||||
}
|
||||
}
|
||||
|
||||
fCurrVertex += 4;
|
||||
}
|
||||
|
||||
inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
|
||||
GrTextContext::init(paint, skPaint);
|
||||
|
||||
@ -488,12 +157,6 @@ inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
|
||||
|
||||
}
|
||||
|
||||
inline void GrDistanceFieldTextContext::finish() {
|
||||
this->flushGlyphs();
|
||||
|
||||
GrTextContext::finish();
|
||||
}
|
||||
|
||||
static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
|
||||
const SkDeviceProperties& deviceProperties,
|
||||
GrTexture** gammaTexture) {
|
||||
@ -594,12 +257,12 @@ void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& s
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
||||
|
||||
if (glyph.fWidth) {
|
||||
this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
fx,
|
||||
fy,
|
||||
fontScaler);
|
||||
this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
fx,
|
||||
fy,
|
||||
fontScaler);
|
||||
}
|
||||
|
||||
fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
|
||||
@ -643,12 +306,12 @@ void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint
|
||||
SkScalar x = offset.x() + pos[0];
|
||||
SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
|
||||
|
||||
this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
SkScalarToFixed(x),
|
||||
SkScalarToFixed(y),
|
||||
fontScaler);
|
||||
this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
SkScalarToFixed(x),
|
||||
SkScalarToFixed(y),
|
||||
fontScaler);
|
||||
}
|
||||
pos += scalarsPerPosition;
|
||||
}
|
||||
@ -662,12 +325,12 @@ void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint
|
||||
SkScalar x = offset.x() + pos[0];
|
||||
SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
|
||||
|
||||
this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
|
||||
SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
|
||||
fontScaler);
|
||||
this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
||||
glyph.getSubXFixed(),
|
||||
glyph.getSubYFixed()),
|
||||
SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
|
||||
SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
|
||||
fontScaler);
|
||||
}
|
||||
pos += scalarsPerPosition;
|
||||
}
|
||||
@ -675,3 +338,335 @@ void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint
|
||||
|
||||
this->finish();
|
||||
}
|
||||
|
||||
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 GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColor) {
|
||||
GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
|
||||
GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
|
||||
|
||||
uint32_t textureUniqueID = fCurrTexture->getUniqueID();
|
||||
const SkMatrix& ctm = fContext->getMatrix();
|
||||
|
||||
// set up any flags
|
||||
uint32_t flags = 0;
|
||||
flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
|
||||
flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
|
||||
flags |= fUseLCDText && ctm.rectStaysRect() ?
|
||||
kRectToRect_DistanceFieldEffectFlag : 0;
|
||||
bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.fPixelGeometry);
|
||||
flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
|
||||
|
||||
// see if we need to create a new effect
|
||||
if (textureUniqueID != fEffectTextureUniqueID ||
|
||||
filteredColor != fEffectColor ||
|
||||
flags != fEffectFlags) {
|
||||
if (fUseLCDText) {
|
||||
GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
|
||||
fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Create(fCurrTexture,
|
||||
params,
|
||||
fGammaTexture,
|
||||
gammaParams,
|
||||
colorNoPreMul,
|
||||
flags));
|
||||
} else {
|
||||
#ifdef SK_GAMMA_APPLY_TO_A8
|
||||
U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.getGamma(),
|
||||
filteredColor);
|
||||
fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
|
||||
params,
|
||||
fGammaTexture,
|
||||
gammaParams,
|
||||
lum/255.f,
|
||||
flags));
|
||||
#else
|
||||
fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
|
||||
params, flags));
|
||||
#endif
|
||||
}
|
||||
fEffectTextureUniqueID = textureUniqueID;
|
||||
fEffectColor = filteredColor;
|
||||
fEffectFlags = flags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
|
||||
SkFixed vx, SkFixed vy,
|
||||
GrFontScaler* scaler) {
|
||||
if (NULL == fDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == fStrike) {
|
||||
fStrike = fContext->getFontCache()->getStrike(scaler, true);
|
||||
}
|
||||
|
||||
GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
|
||||
if (NULL == glyph || glyph->fBounds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar sx = SkFixedToScalar(vx);
|
||||
SkScalar sy = SkFixedToScalar(vy);
|
||||
/*
|
||||
// not valid, need to find a different solution for this
|
||||
vx += SkIntToFixed(glyph->fBounds.fLeft);
|
||||
vy += SkIntToFixed(glyph->fBounds.fTop);
|
||||
|
||||
// keep them as ints until we've done the clip-test
|
||||
GrFixed width = glyph->fBounds.width();
|
||||
GrFixed height = glyph->fBounds.height();
|
||||
|
||||
// check if we clipped out
|
||||
if (true || NULL == glyph->fPlot) {
|
||||
int x = vx >> 16;
|
||||
int y = vy >> 16;
|
||||
if (fClipRect.quickReject(x, y, x + width, y + height)) {
|
||||
// SkCLZ(3); // so we can set a break-point in the debugger
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (NULL == glyph->fPlot) {
|
||||
if (!fStrike->glyphTooLargeForAtlas(glyph)) {
|
||||
if (fStrike->addGlyphToAtlas(glyph, scaler)) {
|
||||
goto HAS_ATLAS;
|
||||
}
|
||||
|
||||
// try to clear out an unused plot before we flush
|
||||
if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
|
||||
fStrike->addGlyphToAtlas(glyph, scaler)) {
|
||||
goto HAS_ATLAS;
|
||||
}
|
||||
|
||||
if (c_DumpFontCache) {
|
||||
#ifdef SK_DEVELOPER
|
||||
fContext->getFontCache()->dump();
|
||||
#endif
|
||||
}
|
||||
|
||||
// before we purge the cache, we must flush any accumulated draws
|
||||
this->flush();
|
||||
fContext->flush();
|
||||
|
||||
// we should have an unused plot now
|
||||
if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
|
||||
fStrike->addGlyphToAtlas(glyph, scaler)) {
|
||||
goto HAS_ATLAS;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == glyph->fPath) {
|
||||
SkPath* path = SkNEW(SkPath);
|
||||
if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
|
||||
// flag the glyph as being dead?
|
||||
delete path;
|
||||
return;
|
||||
}
|
||||
glyph->fPath = path;
|
||||
}
|
||||
|
||||
GrContext::AutoMatrix am;
|
||||
SkMatrix ctm;
|
||||
ctm.setScale(fTextRatio, fTextRatio);
|
||||
ctm.postTranslate(sx, sy);
|
||||
GrPaint tmpPaint(fPaint);
|
||||
am.setPreConcat(fContext, ctm, &tmpPaint);
|
||||
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
|
||||
fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
HAS_ATLAS:
|
||||
SkASSERT(glyph->fPlot);
|
||||
GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
|
||||
glyph->fPlot->setDrawToken(drawToken);
|
||||
|
||||
GrTexture* texture = glyph->fPlot->texture();
|
||||
SkASSERT(texture);
|
||||
|
||||
if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
|
||||
this->flush();
|
||||
fCurrTexture = texture;
|
||||
fCurrTexture->ref();
|
||||
}
|
||||
|
||||
bool useColorVerts = !fUseLCDText;
|
||||
|
||||
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->flush();
|
||||
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);
|
||||
}
|
||||
|
||||
SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
|
||||
SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
|
||||
SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
|
||||
SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
|
||||
|
||||
SkScalar scale = fTextRatio;
|
||||
dx *= scale;
|
||||
dy *= scale;
|
||||
sx += dx;
|
||||
sy += dy;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
|
||||
SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
|
||||
SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
|
||||
SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
|
||||
SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
|
||||
|
||||
SkRect r;
|
||||
r.fLeft = sx;
|
||||
r.fTop = sy;
|
||||
r.fRight = sx + width;
|
||||
r.fBottom = sy + height;
|
||||
|
||||
fVertexBounds.joinNonEmptyArg(r);
|
||||
|
||||
size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint))
|
||||
: (2 * sizeof(SkPoint) + sizeof(GrColor));
|
||||
|
||||
SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
|
||||
|
||||
SkPoint* positions = reinterpret_cast<SkPoint*>(
|
||||
reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
|
||||
positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
|
||||
|
||||
// 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->texturePriv().normalizeFixedX(tx)),
|
||||
SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
|
||||
SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
|
||||
SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
|
||||
vertSize);
|
||||
if (useColorVerts) {
|
||||
if (0xFF == GrColorUnpackA(fPaint.getColor())) {
|
||||
fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
|
||||
}
|
||||
// color comes after position.
|
||||
GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*colors = fPaint.getColor();
|
||||
colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
|
||||
}
|
||||
}
|
||||
|
||||
fCurrVertex += 4;
|
||||
}
|
||||
|
||||
void GrDistanceFieldTextContext::flush() {
|
||||
if (NULL == fDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
GrDrawState* drawState = fDrawTarget->drawState();
|
||||
GrDrawState::AutoRestoreEffects are(drawState);
|
||||
|
||||
drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
|
||||
|
||||
if (fCurrVertex > 0) {
|
||||
// setup our sampler state for our text texture/atlas
|
||||
SkASSERT(SkIsAlign4(fCurrVertex));
|
||||
|
||||
// get our current color
|
||||
SkColor filteredColor;
|
||||
SkColorFilter* colorFilter = fSkPaint.getColorFilter();
|
||||
if (colorFilter) {
|
||||
filteredColor = colorFilter->filterColor(fSkPaint.getColor());
|
||||
} else {
|
||||
filteredColor = fSkPaint.getColor();
|
||||
}
|
||||
this->setupCoverageEffect(filteredColor);
|
||||
|
||||
// Effects could be stored with one of the cache objects (atlas?)
|
||||
drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
|
||||
|
||||
// Set draw state
|
||||
if (fUseLCDText) {
|
||||
GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
|
||||
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(colorNoPreMul);
|
||||
drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
|
||||
} else {
|
||||
// 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());
|
||||
}
|
||||
int nGlyphs = fCurrVertex / 4;
|
||||
fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
|
||||
fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
|
||||
nGlyphs,
|
||||
4, 6, &fVertexBounds);
|
||||
fDrawTarget->resetVertexSource();
|
||||
fVertices = NULL;
|
||||
fMaxVertices = 0;
|
||||
fCurrVertex = 0;
|
||||
SkSafeSetNull(fCurrTexture);
|
||||
fVertexBounds.setLargestInverted();
|
||||
}
|
||||
}
|
||||
|
||||
inline void GrDistanceFieldTextContext::finish() {
|
||||
this->flush();
|
||||
|
||||
GrTextContext::finish();
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ public:
|
||||
GrDistanceFieldTextContext(GrContext*, const SkDeviceProperties&, bool enable);
|
||||
virtual ~GrDistanceFieldTextContext();
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
virtual void drawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) SK_OVERRIDE;
|
||||
virtual void drawPosText(const GrPaint&, const SkPaint&,
|
||||
@ -28,26 +30,7 @@ public:
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset) SK_OVERRIDE;
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
GrTextStrike* fStrike;
|
||||
SkScalar fTextRatio;
|
||||
bool fUseLCDText;
|
||||
bool fEnableDFRendering;
|
||||
SkAutoTUnref<GrGeometryProcessor> fCachedGeometryProcessor;
|
||||
// Used to check whether fCachedEffect is still valid.
|
||||
uint32_t fEffectTextureUniqueID;
|
||||
SkColor fEffectColor;
|
||||
uint32_t fEffectFlags;
|
||||
GrTexture* fGammaTexture;
|
||||
|
||||
void init(const GrPaint&, const SkPaint&);
|
||||
void drawPackedGlyph(GrGlyph::PackedID, SkFixed left, SkFixed top, GrFontScaler*);
|
||||
void flushGlyphs(); // automatically called by destructor
|
||||
void setupCoverageEffect(const SkColor& filteredColor);
|
||||
void finish();
|
||||
|
||||
enum {
|
||||
kMinRequestedGlyphs = 1,
|
||||
kDefaultRequestedGlyphs = 64,
|
||||
@ -55,11 +38,27 @@ private:
|
||||
kDefaultRequestedVerts = kDefaultRequestedGlyphs * 4,
|
||||
};
|
||||
|
||||
void* fVertices;
|
||||
int32_t fMaxVertices;
|
||||
GrTexture* fCurrTexture;
|
||||
int fCurrVertex;
|
||||
SkRect fVertexBounds;
|
||||
GrTextStrike* fStrike;
|
||||
SkScalar fTextRatio;
|
||||
bool fUseLCDText;
|
||||
bool fEnableDFRendering;
|
||||
SkAutoTUnref<GrGeometryProcessor> fCachedGeometryProcessor;
|
||||
// Used to check whether fCachedEffect is still valid.
|
||||
uint32_t fEffectTextureUniqueID;
|
||||
SkColor fEffectColor;
|
||||
uint32_t fEffectFlags;
|
||||
GrTexture* fGammaTexture;
|
||||
void* fVertices;
|
||||
int32_t fMaxVertices;
|
||||
GrTexture* fCurrTexture;
|
||||
int fCurrVertex;
|
||||
SkRect fVertexBounds;
|
||||
|
||||
void init(const GrPaint&, const SkPaint&);
|
||||
void appendGlyph(GrGlyph::PackedID, SkFixed left, SkFixed top, GrFontScaler*);
|
||||
void setupCoverageEffect(const SkColor& filteredColor);
|
||||
void flush(); // automatically called by destructor
|
||||
void finish();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -28,6 +28,30 @@ GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(
|
||||
GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() {
|
||||
}
|
||||
|
||||
bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) {
|
||||
if (paint.getRasterizer()) {
|
||||
return false;
|
||||
}
|
||||
if (paint.getMaskFilter()) {
|
||||
return false;
|
||||
}
|
||||
if (paint.getPathEffect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No hairlines unless we can map the 1 px width to the object space.
|
||||
if (paint.getStyle() == SkPaint::kStroke_Style
|
||||
&& paint.getStrokeWidth() == 0
|
||||
&& fContext->getMatrix().hasPerspective()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No color bitmap fonts.
|
||||
SkScalerContext::Rec rec;
|
||||
SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
|
||||
return rec.getFormat() != SkMask::kARGB32_Format;
|
||||
}
|
||||
|
||||
void GrStencilAndCoverTextContext::drawText(const GrPaint& paint,
|
||||
const SkPaint& skPaint,
|
||||
const char text[],
|
||||
@ -189,30 +213,6 @@ void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint,
|
||||
this->finish();
|
||||
}
|
||||
|
||||
bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) {
|
||||
if (paint.getRasterizer()) {
|
||||
return false;
|
||||
}
|
||||
if (paint.getMaskFilter()) {
|
||||
return false;
|
||||
}
|
||||
if (paint.getPathEffect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No hairlines unless we can map the 1 px width to the object space.
|
||||
if (paint.getStyle() == SkPaint::kStroke_Style
|
||||
&& paint.getStrokeWidth() == 0
|
||||
&& fContext->getMatrix().hasPerspective()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No color bitmap fonts.
|
||||
SkScalerContext::Rec rec;
|
||||
SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
|
||||
return rec.getFormat() != SkMask::kARGB32_Format;
|
||||
}
|
||||
|
||||
static GrPathRange* get_gr_glyphs(GrContext* ctx,
|
||||
const SkTypeface* typeface,
|
||||
const SkDescriptor* desc,
|
||||
|
@ -27,6 +27,8 @@ public:
|
||||
GrStencilAndCoverTextContext(GrContext*, const SkDeviceProperties&);
|
||||
virtual ~GrStencilAndCoverTextContext();
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
virtual void drawText(const GrPaint&, const SkPaint&, const char text[],
|
||||
size_t byteLength,
|
||||
SkScalar x, SkScalar y) SK_OVERRIDE;
|
||||
@ -35,8 +37,6 @@ public:
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset) SK_OVERRIDE;
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
static const int kGlyphBufferSize = 1024;
|
||||
|
||||
@ -61,6 +61,18 @@ private:
|
||||
kMaxPerformance_RenderMode,
|
||||
};
|
||||
|
||||
GrDrawState::AutoRestoreEffects fStateRestore;
|
||||
SkScalar fTextRatio;
|
||||
float fTextInverseRatio;
|
||||
SkGlyphCache* fGlyphCache;
|
||||
GrPathRange* fGlyphs;
|
||||
uint32_t fIndexBuffer[kGlyphBufferSize];
|
||||
float fTransformBuffer[2 * kGlyphBufferSize];
|
||||
GrDrawTarget::PathTransformType fTransformType;
|
||||
int fPendingGlyphCount;
|
||||
SkMatrix fContextInitialMatrix;
|
||||
bool fNeedsDeviceSpaceGlyphs;
|
||||
|
||||
void init(const GrPaint&, const SkPaint&, size_t textByteLength,
|
||||
RenderMode, const SkPoint& textTranslate);
|
||||
void initGlyphs(SkGlyphCache* cache);
|
||||
@ -69,17 +81,6 @@ private:
|
||||
void flush();
|
||||
void finish();
|
||||
|
||||
GrDrawState::AutoRestoreEffects fStateRestore;
|
||||
SkScalar fTextRatio;
|
||||
float fTextInverseRatio;
|
||||
SkGlyphCache* fGlyphCache;
|
||||
GrPathRange* fGlyphs;
|
||||
uint32_t fIndexBuffer[kGlyphBufferSize];
|
||||
float fTransformBuffer[2 * kGlyphBufferSize];
|
||||
GrDrawTarget::PathTransformType fTransformType;
|
||||
int fPendingGlyphCount;
|
||||
SkMatrix fContextInitialMatrix;
|
||||
bool fNeedsDeviceSpaceGlyphs;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -24,6 +24,9 @@ class GrFontScaler;
|
||||
class GrTextContext {
|
||||
public:
|
||||
virtual ~GrTextContext() {}
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) = 0;
|
||||
|
||||
virtual void drawText(const GrPaint&, const SkPaint&, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y) = 0;
|
||||
virtual void drawPosText(const GrPaint&, const SkPaint&,
|
||||
@ -31,18 +34,7 @@ public:
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset) = 0;
|
||||
|
||||
virtual bool canDraw(const SkPaint& paint) = 0;
|
||||
|
||||
protected:
|
||||
GrTextContext(GrContext*, const SkDeviceProperties&);
|
||||
|
||||
static GrFontScaler* GetGrFontScaler(SkGlyphCache* cache);
|
||||
static void MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
|
||||
const char text[], size_t byteLength, SkVector* stopVector);
|
||||
|
||||
void init(const GrPaint&, const SkPaint&);
|
||||
void finish() { fDrawTarget = NULL; }
|
||||
|
||||
GrContext* fContext;
|
||||
SkDeviceProperties fDeviceProperties;
|
||||
|
||||
@ -50,6 +42,15 @@ protected:
|
||||
SkIRect fClipRect;
|
||||
GrPaint fPaint;
|
||||
SkPaint fSkPaint;
|
||||
|
||||
GrTextContext(GrContext*, const SkDeviceProperties&);
|
||||
|
||||
void init(const GrPaint&, const SkPaint&);
|
||||
void finish() { fDrawTarget = NULL; }
|
||||
|
||||
static GrFontScaler* GetGrFontScaler(SkGlyphCache* cache);
|
||||
static void MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
|
||||
const char text[], size_t byteLength, SkVector* stopVector);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user