blob: f4a3df6429e05fb31bcf5bdedb87776a70ae3a01 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2010 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com375ff852012-06-29 18:37:57 +000010#include "GrTextContext.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000011#include "GrAtlas.h"
12#include "GrContext.h"
bsalomon@google.comf4a9c822012-03-16 14:02:46 +000013#include "GrDrawTarget.h"
14#include "GrFontScaler.h"
tomhudson@google.com375ff852012-06-29 18:37:57 +000015#include "GrIndexBuffer.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000016#include "GrTextStrike.h"
17#include "GrTextStrike_impl.h"
tomhudson@google.com375ff852012-06-29 18:37:57 +000018#include "SkPath.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000019#include "SkStrokeRec.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000020
bsalomon@google.comc7818882013-03-20 19:19:53 +000021static const int kGlyphCoordsAttributeIndex = 1;
tomhudson@google.com375ff852012-06-29 18:37:57 +000022
23void GrTextContext::flushGlyphs() {
tomhudson@google.comcb325ce2012-07-11 14:41:19 +000024 if (NULL == fDrawTarget) {
25 return;
26 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000027
tomhudson@google.comcb325ce2012-07-11 14:41:19 +000028 GrDrawState* drawState = fDrawTarget->drawState();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000029 GrDrawState::AutoRestoreEffects are(drawState);
bsalomon@google.com21c10c52013-06-13 17:44:07 +000030 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
31
reed@google.comac10a2d2010-12-22 21:39:39 +000032 if (fCurrVertex > 0) {
reed@google.comac10a2d2010-12-22 21:39:39 +000033 // setup our sampler state for our text texture/atlas
reed@google.comac10a2d2010-12-22 21:39:39 +000034 GrAssert(GrIsALIGN4(fCurrVertex));
reed@google.comac10a2d2010-12-22 21:39:39 +000035 GrAssert(fCurrTexture);
humper@google.comb86add12013-07-25 18:49:07 +000036 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
bsalomon@google.comc7818882013-03-20 19:19:53 +000037
38 // This effect could be stored with one of the cache objects (atlas?)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +000039 drawState->addCoverageEffect(
40 GrSimpleTextureEffect::CreateWithCustomCoords(fCurrTexture, params),
41 kGlyphCoordsAttributeIndex)->unref();
bsalomon@google.com080773c2011-03-15 19:09:25 +000042
bsalomon@google.com669fdc42011-04-05 17:08:27 +000043 if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000044 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
45 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +000046 fPaint.numColorStages()) {
bsalomon@google.com080773c2011-03-15 19:09:25 +000047 GrPrintf("LCD Text will not draw correctly.\n");
48 }
49 // setup blend so that we get mask * paintColor + (1-mask)*dstColor
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000050 drawState->setBlendConstant(fPaint.getColor());
bsalomon@google.com47059542012-06-06 20:51:20 +000051 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
bsalomon@google.com080773c2011-03-15 19:09:25 +000052 // don't modulate by the paint's color in the frag since we're
53 // already doing it via the blend const.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000054 drawState->setColor(0xffffffff);
bsalomon@google.com080773c2011-03-15 19:09:25 +000055 } else {
56 // set back to normal in case we took LCD path previously.
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000057 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
58 drawState->setColor(fPaint.getColor());
bsalomon@google.com080773c2011-03-15 19:09:25 +000059 }
60
bsalomon@google.com934c5702012-03-20 21:17:58 +000061 int nGlyphs = fCurrVertex / 4;
tomhudson@google.com375ff852012-06-29 18:37:57 +000062 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
bsalomon@google.com47059542012-06-06 20:51:20 +000063 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
bsalomon@google.com934c5702012-03-20 21:17:58 +000064 nGlyphs,
65 4, 6);
tomhudson@google.com375ff852012-06-29 18:37:57 +000066 fDrawTarget->resetVertexSource();
reed@google.comac10a2d2010-12-22 21:39:39 +000067 fVertices = NULL;
tomhudson@google.com375ff852012-06-29 18:37:57 +000068 fMaxVertices = 0;
69 fCurrVertex = 0;
70 GrSafeSetNull(fCurrTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +000071 }
72}
73
bsalomon@google.com0e354aa2012-10-08 20:44:25 +000074GrTextContext::GrTextContext(GrContext* context, const GrPaint& paint) : fPaint(paint) {
tomhudson@google.com375ff852012-06-29 18:37:57 +000075 fContext = context;
bsalomon@google.comf4a9c822012-03-16 14:02:46 +000076 fStrike = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000077
tomhudson@google.com375ff852012-06-29 18:37:57 +000078 fCurrTexture = NULL;
79 fCurrVertex = 0;
80
robertphillips@google.combeb1af72012-07-26 18:52:16 +000081 const GrClipData* clipData = context->getClip();
82
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000083 SkRect devConservativeBound;
robertphillips@google.com641f8b12012-07-31 19:15:58 +000084 clipData->fClipStack->getConservativeBounds(
85 -clipData->fOrigin.fX,
86 -clipData->fOrigin.fY,
87 context->getRenderTarget()->width(),
88 context->getRenderTarget()->height(),
89 &devConservativeBound);
robertphillips@google.combeb1af72012-07-26 18:52:16 +000090
robertphillips@google.com641f8b12012-07-31 19:15:58 +000091 devConservativeBound.roundOut(&fClipRect);
robertphillips@google.combeb1af72012-07-26 18:52:16 +000092
bsalomon@google.com858804d2012-10-15 14:25:50 +000093 fAutoMatrix.setIdentity(fContext, &fPaint);
bsalomon@google.com39149582011-06-13 21:55:32 +000094
bsalomon@google.com21c10c52013-06-13 17:44:07 +000095 fDrawTarget = fContext->getTextTarget();
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000096
reed@google.comac10a2d2010-12-22 21:39:39 +000097 fVertices = NULL;
tomhudson@google.com375ff852012-06-29 18:37:57 +000098 fMaxVertices = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +000099}
100
tomhudson@google.com375ff852012-06-29 18:37:57 +0000101GrTextContext::~GrTextContext() {
102 this->flushGlyphs();
reed@google.comac10a2d2010-12-22 21:39:39 +0000103}
104
tomhudson@google.com375ff852012-06-29 18:37:57 +0000105void GrTextContext::flush() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000106 this->flushGlyphs();
107}
108
robertphillips@google.com42903302013-04-20 12:26:07 +0000109namespace {
110
111// position + texture coord
112extern const GrVertexAttrib gTextVertexAttribs[] = {
113 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
114 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
115};
116
117};
118
tomhudson@google.com375ff852012-06-29 18:37:57 +0000119void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
reed@google.comac10a2d2010-12-22 21:39:39 +0000120 GrFixed vx, GrFixed vy,
121 GrFontScaler* scaler) {
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000122 if (NULL == fDrawTarget) {
123 return;
124 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000125 if (NULL == fStrike) {
126 fStrike = fContext->getFontCache()->getStrike(scaler);
127 }
128
129 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
130 if (NULL == glyph || glyph->fBounds.isEmpty()) {
131 return;
132 }
133
bsalomon@google.com81712882012-11-01 17:12:34 +0000134 vx += SkIntToFixed(glyph->fBounds.fLeft);
135 vy += SkIntToFixed(glyph->fBounds.fTop);
reed@google.comac10a2d2010-12-22 21:39:39 +0000136
137 // keep them as ints until we've done the clip-test
138 GrFixed width = glyph->fBounds.width();
139 GrFixed height = glyph->fBounds.height();
140
141 // check if we clipped out
142 if (true || NULL == glyph->fAtlas) {
143 int x = vx >> 16;
144 int y = vy >> 16;
145 if (fClipRect.quickReject(x, y, x + width, y + height)) {
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000146// SkCLZ(3); // so we can set a break-point in the debugger
reed@google.comac10a2d2010-12-22 21:39:39 +0000147 return;
148 }
149 }
150
commit-bot@chromium.orga8916ff2013-08-16 15:53:46 +0000151 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
reed@google.comac10a2d2010-12-22 21:39:39 +0000152 if (NULL == glyph->fAtlas) {
commit-bot@chromium.orga8916ff2013-08-16 15:53:46 +0000153 if (fStrike->getGlyphAtlas(glyph, scaler, drawToken)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000154 goto HAS_ATLAS;
155 }
reed@google.com0ebe81a2011-04-04 20:06:59 +0000156
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000157 // try to clear out an unused atlas before we flush
158 fContext->getFontCache()->freeAtlasExceptFor(fStrike);
commit-bot@chromium.orga8916ff2013-08-16 15:53:46 +0000159 if (fStrike->getGlyphAtlas(glyph, scaler, drawToken)) {
commit-bot@chromium.org67ed64e2013-08-05 19:42:56 +0000160 goto HAS_ATLAS;
161 }
162
reed@google.com0ebe81a2011-04-04 20:06:59 +0000163 // before we purge the cache, we must flush any accumulated draws
164 this->flushGlyphs();
bsalomon@google.com193395c2012-03-30 17:35:12 +0000165 fContext->flush();
reed@google.com313e4032010-12-22 22:16:59 +0000166
reed@google.comac10a2d2010-12-22 21:39:39 +0000167 // try to purge
168 fContext->getFontCache()->purgeExceptFor(fStrike);
commit-bot@chromium.orga8916ff2013-08-16 15:53:46 +0000169 // need to use new flush count here
170 if (fStrike->getGlyphAtlas(glyph, scaler, drawToken)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 goto HAS_ATLAS;
172 }
173
reed@google.comac10a2d2010-12-22 21:39:39 +0000174 if (NULL == glyph->fPath) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000175 SkPath* path = SkNEW(SkPath);
reed@google.comac10a2d2010-12-22 21:39:39 +0000176 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
177 // flag the glyph as being dead?
178 delete path;
179 return;
180 }
181 glyph->fPath = path;
182 }
reed@google.com07f3ee12011-05-16 17:21:57 +0000183
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000184 GrContext::AutoMatrix am;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000185 SkMatrix translate;
bsalomon@google.com81712882012-11-01 17:12:34 +0000186 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
187 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000188 GrPaint tmpPaint(fPaint);
189 am.setPreConcat(fContext, translate, &tmpPaint);
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000190 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
191 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
reed@google.comac10a2d2010-12-22 21:39:39 +0000192 return;
193 }
194
195HAS_ATLAS:
196 GrAssert(glyph->fAtlas);
197
bsalomon@google.com85983282013-02-07 22:00:29 +0000198 // now promote them to fixed (TODO: Rethink using fixed pt).
bsalomon@google.com81712882012-11-01 17:12:34 +0000199 width = SkIntToFixed(width);
200 height = SkIntToFixed(height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000201
202 GrTexture* texture = glyph->fAtlas->texture();
tomhudson@google.com375ff852012-06-29 18:37:57 +0000203 GrAssert(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000204
tomhudson@google.com375ff852012-06-29 18:37:57 +0000205 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
206 this->flushGlyphs();
207 fCurrTexture = texture;
208 fCurrTexture->ref();
209 }
210
211 if (NULL == fVertices) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000212 // If we need to reserve vertices allow the draw target to suggest
tomhudson@google.com375ff852012-06-29 18:37:57 +0000213 // a number of verts to reserve and whether to perform a flush.
214 fMaxVertices = kMinRequestedVerts;
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000215 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
216 SK_ARRAY_COUNT(gTextVertexAttribs));
217 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
tomhudson@google.com375ff852012-06-29 18:37:57 +0000218 if (flush) {
219 this->flushGlyphs();
220 fContext->flush();
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000221 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
222 SK_ARRAY_COUNT(gTextVertexAttribs));
tomhudson@google.com375ff852012-06-29 18:37:57 +0000223 }
tomhudson@google.comcb325ce2012-07-11 14:41:19 +0000224 fMaxVertices = kDefaultRequestedVerts;
225 // ignore return, no point in flushing again.
bsalomon@google.comf3a7bc72013-02-05 21:32:06 +0000226 fDrawTarget->geometryHints(&fMaxVertices, NULL);
tomhudson@google.com375ff852012-06-29 18:37:57 +0000227
228 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
229 if (fMaxVertices < kMinRequestedVerts) {
230 fMaxVertices = kDefaultRequestedVerts;
231 } else if (fMaxVertices > maxQuadVertices) {
232 // don't exceed the limit of the index buffer
233 fMaxVertices = maxQuadVertices;
234 }
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000235 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
236 0,
237 GrTCast<void**>(&fVertices),
238 NULL);
tomhudson@google.com375ff852012-06-29 18:37:57 +0000239 GrAlwaysAssert(success);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000240 GrAssert(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
tomhudson@google.com375ff852012-06-29 18:37:57 +0000241 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000242
bsalomon@google.com81712882012-11-01 17:12:34 +0000243 GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
244 GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
reed@google.comac10a2d2010-12-22 21:39:39 +0000245
bsalomon@google.com85983282013-02-07 22:00:29 +0000246 fVertices[2*fCurrVertex].setRectFan(SkFixedToFloat(vx),
247 SkFixedToFloat(vy),
248 SkFixedToFloat(vx + width),
249 SkFixedToFloat(vy + height),
250 2 * sizeof(SkPoint));
251 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
252 SkFixedToFloat(texture->normalizeFixedY(ty)),
253 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
254 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
255 2 * sizeof(SkPoint));
reed@google.comac10a2d2010-12-22 21:39:39 +0000256 fCurrVertex += 4;
257}