blob: e599fc9500af0c9d8b38ee52c812f78c6220d514 [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
tomhudson@google.com375ff852012-06-29 18:37:57 +000021enum {
22 kGlyphMaskStage = GrPaint::kTotalStages,
23};
24
25void GrTextContext::flushGlyphs() {
tomhudson@google.comcb325ce2012-07-11 14:41:19 +000026 if (NULL == fDrawTarget) {
27 return;
28 }
29 GrDrawState* drawState = fDrawTarget->drawState();
reed@google.comac10a2d2010-12-22 21:39:39 +000030 if (fCurrVertex > 0) {
reed@google.comac10a2d2010-12-22 21:39:39 +000031 // setup our sampler state for our text texture/atlas
reed@google.comac10a2d2010-12-22 21:39:39 +000032 GrAssert(GrIsALIGN4(fCurrVertex));
reed@google.comac10a2d2010-12-22 21:39:39 +000033 GrAssert(fCurrTexture);
bsalomon@google.com0e354aa2012-10-08 20:44:25 +000034 GrTextureParams params(SkShader::kRepeat_TileMode, false);
bsalomon@google.comb9086a02012-11-01 18:02:54 +000035 drawState->createTextureEffect(kGlyphMaskStage, fCurrTexture, SkMatrix::I(), params);
bsalomon@google.com080773c2011-03-15 19:09:25 +000036
bsalomon@google.com669fdc42011-04-05 17:08:27 +000037 if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000038 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
39 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
bsalomon@google.com88becf42012-10-05 14:54:42 +000040 fPaint.hasColorStage()) {
bsalomon@google.com080773c2011-03-15 19:09:25 +000041 GrPrintf("LCD Text will not draw correctly.\n");
42 }
43 // setup blend so that we get mask * paintColor + (1-mask)*dstColor
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000044 drawState->setBlendConstant(fPaint.getColor());
bsalomon@google.com47059542012-06-06 20:51:20 +000045 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
bsalomon@google.com080773c2011-03-15 19:09:25 +000046 // don't modulate by the paint's color in the frag since we're
47 // already doing it via the blend const.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000048 drawState->setColor(0xffffffff);
bsalomon@google.com080773c2011-03-15 19:09:25 +000049 } else {
50 // set back to normal in case we took LCD path previously.
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000051 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
52 drawState->setColor(fPaint.getColor());
bsalomon@google.com080773c2011-03-15 19:09:25 +000053 }
54
bsalomon@google.com934c5702012-03-20 21:17:58 +000055 int nGlyphs = fCurrVertex / 4;
tomhudson@google.com375ff852012-06-29 18:37:57 +000056 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
bsalomon@google.com47059542012-06-06 20:51:20 +000057 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
bsalomon@google.com934c5702012-03-20 21:17:58 +000058 nGlyphs,
59 4, 6);
tomhudson@google.com375ff852012-06-29 18:37:57 +000060 fDrawTarget->resetVertexSource();
reed@google.comac10a2d2010-12-22 21:39:39 +000061 fVertices = NULL;
tomhudson@google.com375ff852012-06-29 18:37:57 +000062 fMaxVertices = 0;
63 fCurrVertex = 0;
64 GrSafeSetNull(fCurrTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +000065 }
tomhudson@google.comcb325ce2012-07-11 14:41:19 +000066 drawState->disableStages();
67 fDrawTarget = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000068}
69
bsalomon@google.com0e354aa2012-10-08 20:44:25 +000070GrTextContext::GrTextContext(GrContext* context, const GrPaint& paint) : fPaint(paint) {
tomhudson@google.com375ff852012-06-29 18:37:57 +000071 fContext = context;
bsalomon@google.comf4a9c822012-03-16 14:02:46 +000072 fStrike = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000073
tomhudson@google.com375ff852012-06-29 18:37:57 +000074 fCurrTexture = NULL;
75 fCurrVertex = 0;
76
robertphillips@google.combeb1af72012-07-26 18:52:16 +000077 const GrClipData* clipData = context->getClip();
78
robertphillips@google.com641f8b12012-07-31 19:15:58 +000079 GrRect devConservativeBound;
80 clipData->fClipStack->getConservativeBounds(
81 -clipData->fOrigin.fX,
82 -clipData->fOrigin.fY,
83 context->getRenderTarget()->width(),
84 context->getRenderTarget()->height(),
85 &devConservativeBound);
robertphillips@google.combeb1af72012-07-26 18:52:16 +000086
robertphillips@google.com641f8b12012-07-31 19:15:58 +000087 devConservativeBound.roundOut(&fClipRect);
robertphillips@google.combeb1af72012-07-26 18:52:16 +000088
bsalomon@google.com858804d2012-10-15 14:25:50 +000089 fAutoMatrix.setIdentity(fContext, &fPaint);
bsalomon@google.com39149582011-06-13 21:55:32 +000090
tomhudson@google.comcb325ce2012-07-11 14:41:19 +000091 fDrawTarget = NULL;
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000092
reed@google.comac10a2d2010-12-22 21:39:39 +000093 fVertices = NULL;
tomhudson@google.com375ff852012-06-29 18:37:57 +000094 fMaxVertices = 0;
robertphillips@google.comaf3a3b92013-02-28 23:08:28 +000095
96 fVertexLayout = GrDrawState::StageTexCoordVertexLayoutBit(kGlyphMaskStage);
reed@google.comac10a2d2010-12-22 21:39:39 +000097}
98
tomhudson@google.com375ff852012-06-29 18:37:57 +000099GrTextContext::~GrTextContext() {
100 this->flushGlyphs();
101 if (fDrawTarget) {
102 fDrawTarget->drawState()->disableStages();
103 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000104}
105
tomhudson@google.com375ff852012-06-29 18:37:57 +0000106void GrTextContext::flush() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 this->flushGlyphs();
108}
109
tomhudson@google.com375ff852012-06-29 18:37:57 +0000110void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
reed@google.comac10a2d2010-12-22 21:39:39 +0000111 GrFixed vx, GrFixed vy,
112 GrFontScaler* scaler) {
113 if (NULL == fStrike) {
114 fStrike = fContext->getFontCache()->getStrike(scaler);
115 }
116
117 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
118 if (NULL == glyph || glyph->fBounds.isEmpty()) {
119 return;
120 }
121
bsalomon@google.com81712882012-11-01 17:12:34 +0000122 vx += SkIntToFixed(glyph->fBounds.fLeft);
123 vy += SkIntToFixed(glyph->fBounds.fTop);
reed@google.comac10a2d2010-12-22 21:39:39 +0000124
125 // keep them as ints until we've done the clip-test
126 GrFixed width = glyph->fBounds.width();
127 GrFixed height = glyph->fBounds.height();
128
129 // check if we clipped out
130 if (true || NULL == glyph->fAtlas) {
131 int x = vx >> 16;
132 int y = vy >> 16;
133 if (fClipRect.quickReject(x, y, x + width, y + height)) {
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000134// SkCLZ(3); // so we can set a break-point in the debugger
reed@google.comac10a2d2010-12-22 21:39:39 +0000135 return;
136 }
137 }
138
139 if (NULL == glyph->fAtlas) {
140 if (fStrike->getGlyphAtlas(glyph, scaler)) {
141 goto HAS_ATLAS;
142 }
reed@google.com0ebe81a2011-04-04 20:06:59 +0000143
144 // before we purge the cache, we must flush any accumulated draws
145 this->flushGlyphs();
bsalomon@google.com193395c2012-03-30 17:35:12 +0000146 fContext->flush();
reed@google.com313e4032010-12-22 22:16:59 +0000147
reed@google.comac10a2d2010-12-22 21:39:39 +0000148 // try to purge
149 fContext->getFontCache()->purgeExceptFor(fStrike);
150 if (fStrike->getGlyphAtlas(glyph, scaler)) {
151 goto HAS_ATLAS;
152 }
153
reed@google.comac10a2d2010-12-22 21:39:39 +0000154 if (NULL == glyph->fPath) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000155 SkPath* path = SkNEW(SkPath);
reed@google.comac10a2d2010-12-22 21:39:39 +0000156 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
157 // flag the glyph as being dead?
158 delete path;
159 return;
160 }
161 glyph->fPath = path;
162 }
reed@google.com07f3ee12011-05-16 17:21:57 +0000163
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000164 GrContext::AutoMatrix am;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000165 SkMatrix translate;
bsalomon@google.com81712882012-11-01 17:12:34 +0000166 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
167 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000168 GrPaint tmpPaint(fPaint);
169 am.setPreConcat(fContext, translate, &tmpPaint);
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000170 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
171 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
reed@google.comac10a2d2010-12-22 21:39:39 +0000172 return;
173 }
174
175HAS_ATLAS:
176 GrAssert(glyph->fAtlas);
177
bsalomon@google.com85983282013-02-07 22:00:29 +0000178 // now promote them to fixed (TODO: Rethink using fixed pt).
bsalomon@google.com81712882012-11-01 17:12:34 +0000179 width = SkIntToFixed(width);
180 height = SkIntToFixed(height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000181
182 GrTexture* texture = glyph->fAtlas->texture();
tomhudson@google.com375ff852012-06-29 18:37:57 +0000183 GrAssert(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000184
tomhudson@google.com375ff852012-06-29 18:37:57 +0000185 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
186 this->flushGlyphs();
187 fCurrTexture = texture;
188 fCurrTexture->ref();
189 }
190
191 if (NULL == fVertices) {
robertphillips@google.comaf3a3b92013-02-28 23:08:28 +0000192 // If we need to reserve vertices allow the draw target to suggest
tomhudson@google.com375ff852012-06-29 18:37:57 +0000193 // a number of verts to reserve and whether to perform a flush.
194 fMaxVertices = kMinRequestedVerts;
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000195 bool flush = false;
196 fDrawTarget = fContext->getTextTarget(fPaint);
197 if (NULL != fDrawTarget) {
robertphillips@google.comaf3a3b92013-02-28 23:08:28 +0000198 fDrawTarget->drawState()->setVertexLayout(fVertexLayout);
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000199 flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
skia.committer@gmail.comae683922013-02-06 07:01:54 +0000200 }
tomhudson@google.com375ff852012-06-29 18:37:57 +0000201 if (flush) {
202 this->flushGlyphs();
203 fContext->flush();
bsalomon@google.comf3a7bc72013-02-05 21:32:06 +0000204 // flushGlyphs() will reset fDrawTarget to NULL.
205 fDrawTarget = fContext->getTextTarget(fPaint);
robertphillips@google.comaf3a3b92013-02-28 23:08:28 +0000206 fDrawTarget->drawState()->setVertexLayout(fVertexLayout);
tomhudson@google.com375ff852012-06-29 18:37:57 +0000207 }
tomhudson@google.comcb325ce2012-07-11 14:41:19 +0000208 fMaxVertices = kDefaultRequestedVerts;
209 // ignore return, no point in flushing again.
bsalomon@google.comf3a7bc72013-02-05 21:32:06 +0000210 fDrawTarget->geometryHints(&fMaxVertices, NULL);
tomhudson@google.com375ff852012-06-29 18:37:57 +0000211
212 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
213 if (fMaxVertices < kMinRequestedVerts) {
214 fMaxVertices = kDefaultRequestedVerts;
215 } else if (fMaxVertices > maxQuadVertices) {
216 // don't exceed the limit of the index buffer
217 fMaxVertices = maxQuadVertices;
218 }
219 bool success = fDrawTarget->reserveVertexAndIndexSpace(
tomhudson@google.com375ff852012-06-29 18:37:57 +0000220 fMaxVertices,
221 0,
222 GrTCast<void**>(&fVertices),
223 NULL);
224 GrAlwaysAssert(success);
225 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000226
bsalomon@google.com81712882012-11-01 17:12:34 +0000227 GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
228 GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
reed@google.comac10a2d2010-12-22 21:39:39 +0000229
bsalomon@google.com85983282013-02-07 22:00:29 +0000230 fVertices[2*fCurrVertex].setRectFan(SkFixedToFloat(vx),
231 SkFixedToFloat(vy),
232 SkFixedToFloat(vx + width),
233 SkFixedToFloat(vy + height),
234 2 * sizeof(SkPoint));
235 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
236 SkFixedToFloat(texture->normalizeFixedY(ty)),
237 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
238 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
239 2 * sizeof(SkPoint));
reed@google.comac10a2d2010-12-22 21:39:39 +0000240 fCurrVertex += 4;
241}