blob: a1196dc494c02bc273bcd413c03b095d1819a657 [file] [log] [blame]
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +00001/*
2 * Copyright 2013 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.
6 */
7
8#include "GrBitmapTextContext.h"
9#include "GrAtlas.h"
10#include "GrDrawTarget.h"
11#include "GrFontScaler.h"
12#include "GrIndexBuffer.h"
egdanield58a0ba2014-06-11 10:30:05 -070013#include "GrStrokeInfo.h"
bsalomonafbf2d62014-09-30 12:18:44 -070014#include "GrTexturePriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000015#include "GrTextStrike.h"
16#include "GrTextStrike_impl.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000017#include "effects/GrCustomCoordsTextureEffect.h"
18
bsalomonafbf2d62014-09-30 12:18:44 -070019#include "SkColorPriv.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000020#include "SkDraw.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070021#include "SkDrawProcs.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000022#include "SkGlyphCache.h"
23#include "SkGpuDevice.h"
24#include "SkGr.h"
bsalomonafbf2d62014-09-30 12:18:44 -070025#include "SkPath.h"
26#include "SkRTConf.h"
27#include "SkStrokeRec.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070028#include "SkTextMapStateProc.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000029
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000030SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
31 "Dump the contents of the font cache before every purge.");
32
bsalomon594069f2014-06-06 06:16:34 -070033namespace {
34// position + texture coord
35extern const GrVertexAttrib gTextVertexAttribs[] = {
36 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
joshualittb0a8a372014-09-23 09:50:21 -070037 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
bsalomon594069f2014-06-06 06:16:34 -070038};
39
egdaniel7b3d5ee2014-08-28 05:41:14 -070040static const size_t kTextVASize = 2 * sizeof(SkPoint);
41
bsalomon594069f2014-06-06 06:16:34 -070042// position + color + texture coord
43extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
44 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
45 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
joshualittb0a8a372014-09-23 09:50:21 -070046 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
bsalomon594069f2014-06-06 06:16:34 -070047};
48
egdaniel7b3d5ee2014-08-28 05:41:14 -070049static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
50
bsalomon594069f2014-06-06 06:16:34 -070051};
52
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000053GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000054 const SkDeviceProperties& properties)
Mike Klein6a25bd02014-08-29 10:03:59 -040055 : GrTextContext(context, properties) {
56 fStrike = NULL;
57
58 fCurrTexture = NULL;
59 fCurrVertex = 0;
60 fEffectTextureUniqueID = SK_InvalidUniqueID;
61
62 fVertices = NULL;
63 fMaxVertices = 0;
64
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000065 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000066}
67
jvanverth8c27a182014-10-14 08:45:50 -070068GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context,
69 const SkDeviceProperties& props) {
70 return SkNEW_ARGS(GrBitmapTextContext, (context, props));
71}
72
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000073GrBitmapTextContext::~GrBitmapTextContext() {
jvanverth0fedb192014-10-08 09:07:27 -070074 this->flush();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000075}
76
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000077bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
78 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
79}
80
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000081inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
82 GrTextContext::init(paint, skPaint);
83
84 fStrike = NULL;
85
Mike Klein6a25bd02014-08-29 10:03:59 -040086 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -070087 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -040088
89 fVertices = NULL;
90 fMaxVertices = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000091}
92
jvanverth8c27a182014-10-14 08:45:50 -070093void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000094 const char text[], size_t byteLength,
fmalita05c4a432014-09-29 06:29:53 -070095 const SkScalar pos[], int scalarsPerPosition,
96 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000097 SkASSERT(byteLength == 0 || text != NULL);
98 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
99
100 // nothing to draw
101 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
102 return;
103 }
104
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000105 this->init(paint, skPaint);
106
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000107 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
108
109 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
110 SkGlyphCache* cache = autoCache.getCache();
111 GrFontScaler* fontScaler = GetGrFontScaler(cache);
112
113 // store original matrix before we reset, so we can use it to transform positions
114 SkMatrix ctm = fContext->getMatrix();
115 GrContext::AutoMatrix autoMatrix;
116 autoMatrix.setIdentity(fContext, &fPaint);
117
118 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700119 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
fmalita05c4a432014-09-29 06:29:53 -0700120 SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000121 SkFixed halfSampleX = 0, halfSampleY = 0;
122
123 if (cache->isSubpixel()) {
124 // maybe we should skip the rounding if linearText is set
125 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
126
127 SkFixed fxMask = ~0;
128 SkFixed fyMask = ~0;
129 if (kX_SkAxisAlignment == baseline) {
130 fyMask = 0;
131#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
132 halfSampleY = SK_FixedHalf;
133#endif
134 } else if (kY_SkAxisAlignment == baseline) {
135 fxMask = 0;
136#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
137 halfSampleX = SK_FixedHalf;
138#endif
139 }
140
141 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
142 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700143 SkPoint tmsLoc;
144 tmsProc(pos, &tmsLoc);
145 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
146 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000147
148 const SkGlyph& glyph = glyphCacheProc(cache, &text,
149 fx & fxMask, fy & fyMask);
150
151 if (glyph.fWidth) {
jvanverth0fedb192014-10-08 09:07:27 -0700152 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
153 glyph.getSubXFixed(),
154 glyph.getSubYFixed()),
155 SkFixedFloorToFixed(fx),
156 SkFixedFloorToFixed(fy),
157 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000158 }
159 pos += scalarsPerPosition;
160 }
161 } else {
162 while (text < stop) {
163 const char* currentText = text;
164 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
165
166 if (metricGlyph.fWidth) {
167 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
168 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700169 SkPoint tmsLoc;
170 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000171 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700172 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000173
174 SkFixed fx = fixedLoc.fX + halfSampleX;
175 SkFixed fy = fixedLoc.fY + halfSampleY;
176
177 // have to call again, now that we've been "aligned"
178 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
179 fx & fxMask, fy & fyMask);
180 // the assumption is that the metrics haven't changed
181 SkASSERT(prevAdvX == glyph.fAdvanceX);
182 SkASSERT(prevAdvY == glyph.fAdvanceY);
183 SkASSERT(glyph.fWidth);
184
jvanverth0fedb192014-10-08 09:07:27 -0700185 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
186 glyph.getSubXFixed(),
187 glyph.getSubYFixed()),
188 SkFixedFloorToFixed(fx),
189 SkFixedFloorToFixed(fy),
190 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000191 }
192 pos += scalarsPerPosition;
193 }
194 }
195 } else { // not subpixel
196
197 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
198 while (text < stop) {
199 // the last 2 parameters are ignored
200 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
201
202 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700203 SkPoint tmsLoc;
204 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000205
kkinnunencb9a2c82014-06-12 23:06:28 -0700206 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
207 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700208 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
209 glyph.getSubXFixed(),
210 glyph.getSubYFixed()),
211 SkFixedFloorToFixed(fx),
212 SkFixedFloorToFixed(fy),
213 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000214 }
215 pos += scalarsPerPosition;
216 }
217 } else {
218 while (text < stop) {
219 // the last 2 parameters are ignored
220 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
221
222 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700223 SkPoint tmsLoc;
224 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000225
226 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700227 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000228
229 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
230 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700231 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
232 glyph.getSubXFixed(),
233 glyph.getSubYFixed()),
234 SkFixedFloorToFixed(fx),
235 SkFixedFloorToFixed(fy),
236 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000237 }
238 pos += scalarsPerPosition;
239 }
240 }
241 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000242
243 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000244}
245
jvanverth0fedb192014-10-08 09:07:27 -0700246void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
247 SkFixed vx, SkFixed vy,
248 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400249 if (NULL == fDrawTarget) {
250 return;
251 }
252
253 if (NULL == fStrike) {
254 fStrike = fContext->getFontCache()->getStrike(scaler, false);
255 }
256
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000257 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
258 if (NULL == glyph || glyph->fBounds.isEmpty()) {
259 return;
260 }
261
262 vx += SkIntToFixed(glyph->fBounds.fLeft);
263 vy += SkIntToFixed(glyph->fBounds.fTop);
264
265 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000266 SkFixed width = glyph->fBounds.width();
267 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000268
269 // check if we clipped out
270 if (true || NULL == glyph->fPlot) {
271 int x = vx >> 16;
272 int y = vy >> 16;
273 if (fClipRect.quickReject(x, y, x + width, y + height)) {
274// SkCLZ(3); // so we can set a break-point in the debugger
275 return;
276 }
277 }
278
279 if (NULL == glyph->fPlot) {
jvanverth681e65b2014-09-19 13:07:38 -0700280 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
281 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
282 goto HAS_ATLAS;
283 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000284
jvanverth681e65b2014-09-19 13:07:38 -0700285 // try to clear out an unused plot before we flush
jvanverth294c3262014-10-10 11:36:12 -0700286 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
jvanverth681e65b2014-09-19 13:07:38 -0700287 fStrike->addGlyphToAtlas(glyph, scaler)) {
288 goto HAS_ATLAS;
289 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000290
jvanverth681e65b2014-09-19 13:07:38 -0700291 if (c_DumpFontCache) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000292#ifdef SK_DEVELOPER
jvanverth681e65b2014-09-19 13:07:38 -0700293 fContext->getFontCache()->dump();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000294#endif
jvanverth681e65b2014-09-19 13:07:38 -0700295 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000296
jvanverth681e65b2014-09-19 13:07:38 -0700297 // flush any accumulated draws to allow us to free up a plot
jvanverth0fedb192014-10-08 09:07:27 -0700298 this->flush();
jvanverth681e65b2014-09-19 13:07:38 -0700299 fContext->flush();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000300
jvanverth681e65b2014-09-19 13:07:38 -0700301 // we should have an unused plot now
jvanverth294c3262014-10-10 11:36:12 -0700302 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
jvanverth681e65b2014-09-19 13:07:38 -0700303 fStrike->addGlyphToAtlas(glyph, scaler)) {
304 goto HAS_ATLAS;
305 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000306 }
307
308 if (NULL == glyph->fPath) {
309 SkPath* path = SkNEW(SkPath);
310 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
311 // flag the glyph as being dead?
312 delete path;
313 return;
314 }
315 glyph->fPath = path;
316 }
317
bsalomonec87dc62014-10-14 10:52:00 -0700318 // flush any accumulated draws before drawing this glyph as a path.
319 this->flush();
320
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000321 GrContext::AutoMatrix am;
322 SkMatrix translate;
323 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
324 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
325 GrPaint tmpPaint(fPaint);
326 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700327 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
328 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000329 return;
330 }
331
332HAS_ATLAS:
333 SkASSERT(glyph->fPlot);
334 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
335 glyph->fPlot->setDrawToken(drawToken);
336
337 // now promote them to fixed (TODO: Rethink using fixed pt).
338 width = SkIntToFixed(width);
339 height = SkIntToFixed(height);
340
jvanverth294c3262014-10-10 11:36:12 -0700341 // the current texture/maskformat must match what the glyph needs
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000342 GrTexture* texture = glyph->fPlot->texture();
343 SkASSERT(texture);
344
Mike Klein6a25bd02014-08-29 10:03:59 -0400345 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
jvanverth0fedb192014-10-08 09:07:27 -0700346 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400347 fCurrTexture = texture;
348 fCurrTexture->ref();
jvanverth294c3262014-10-10 11:36:12 -0700349 fCurrMaskFormat = glyph->fMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400350 }
351
jvanverth294c3262014-10-10 11:36:12 -0700352 bool useColorVerts = kA8_GrMaskFormat == fCurrMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400353
354 if (NULL == fVertices) {
355 // If we need to reserve vertices allow the draw target to suggest
356 // a number of verts to reserve and whether to perform a flush.
357 fMaxVertices = kMinRequestedVerts;
358 if (useColorVerts) {
359 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
360 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
361 } else {
362 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
363 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
364 }
365 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
366 if (flush) {
jvanverth0fedb192014-10-08 09:07:27 -0700367 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400368 fContext->flush();
369 if (useColorVerts) {
370 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
371 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
372 } else {
373 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
374 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
375 }
376 }
377 fMaxVertices = kDefaultRequestedVerts;
378 // ignore return, no point in flushing again.
379 fDrawTarget->geometryHints(&fMaxVertices, NULL);
380
381 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
382 if (fMaxVertices < kMinRequestedVerts) {
383 fMaxVertices = kDefaultRequestedVerts;
384 } else if (fMaxVertices > maxQuadVertices) {
385 // don't exceed the limit of the index buffer
386 fMaxVertices = maxQuadVertices;
387 }
388 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
389 0,
390 &fVertices,
391 NULL);
392 GrAlwaysAssert(success);
393 }
394
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000395 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
396 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000397
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000398 SkRect r;
399 r.fLeft = SkFixedToFloat(vx);
400 r.fTop = SkFixedToFloat(vy);
401 r.fRight = SkFixedToFloat(vx + width);
402 r.fBottom = SkFixedToFloat(vy + height);
403
reed10d03272014-10-01 09:24:12 -0700404 fVertexBounds.joinNonEmptyArg(r);
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000405
bsalomon594069f2014-06-06 06:16:34 -0700406 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
407 (2 * sizeof(SkPoint));
408
egdaniel7b3d5ee2014-08-28 05:41:14 -0700409 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
bsalomon594069f2014-06-06 06:16:34 -0700410
411 SkPoint* positions = reinterpret_cast<SkPoint*>(
412 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
413 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
414
415 // The texture coords are last in both the with and without color vertex layouts.
416 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
417 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
bsalomonafbf2d62014-09-30 12:18:44 -0700418 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
419 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
420 SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
421 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
bsalomon594069f2014-06-06 06:16:34 -0700422 vertSize);
423 if (useColorVerts) {
bsalomon62c447d2014-08-08 08:08:50 -0700424 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
425 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
426 }
bsalomon594069f2014-06-06 06:16:34 -0700427 // color comes after position.
428 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
429 for (int i = 0; i < 4; ++i) {
430 *colors = fPaint.getColor();
431 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
432 }
433 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000434 fCurrVertex += 4;
435}
jvanverth0fedb192014-10-08 09:07:27 -0700436
437static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
438 unsigned r = SkColorGetR(c);
439 unsigned g = SkColorGetG(c);
440 unsigned b = SkColorGetB(c);
441 return GrColorPackRGBA(r, g, b, 0xff);
442}
443
444void GrBitmapTextContext::flush() {
445 if (NULL == fDrawTarget) {
446 return;
447 }
448
449 GrDrawState* drawState = fDrawTarget->drawState();
450 GrDrawState::AutoRestoreEffects are(drawState);
451 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
452
453 if (fCurrVertex > 0) {
454 // setup our sampler state for our text texture/atlas
455 SkASSERT(SkIsAlign4(fCurrVertex));
456 SkASSERT(fCurrTexture);
457 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
458
459 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
460
461 if (textureUniqueID != fEffectTextureUniqueID) {
462 fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
463 params));
464 fEffectTextureUniqueID = textureUniqueID;
465 }
466
467 // This effect could be stored with one of the cache objects (atlas?)
468 drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
469 SkASSERT(fStrike);
jvanverth294c3262014-10-10 11:36:12 -0700470 switch (fCurrMaskFormat) {
jvanverth0fedb192014-10-08 09:07:27 -0700471 // Color bitmap text
472 case kARGB_GrMaskFormat:
473 SkASSERT(!drawState->hasColorVertexAttribute());
474 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
jvanverth294c3262014-10-10 11:36:12 -0700475 drawState->setAlpha(fSkPaint.getAlpha());
jvanverth0fedb192014-10-08 09:07:27 -0700476 break;
477 // LCD text
478 case kA888_GrMaskFormat:
479 case kA565_GrMaskFormat: {
480 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
481 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
482 fPaint.numColorStages()) {
483 GrPrintf("LCD Text will not draw correctly.\n");
484 }
485 SkASSERT(!drawState->hasColorVertexAttribute());
486 // We don't use the GrPaint's color in this case because it's been premultiplied by
487 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
488 // the mask texture color. The end result is that we get
489 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
490 int a = SkColorGetA(fSkPaint.getColor());
491 // paintAlpha
492 drawState->setColor(SkColorSetARGB(a, a, a, a));
493 // paintColor
494 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
495 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
496 break;
497 }
498 // Grayscale/BW text
499 case kA8_GrMaskFormat:
500 // set back to normal in case we took LCD path previously.
501 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
502 // We're using per-vertex color.
503 SkASSERT(drawState->hasColorVertexAttribute());
504 break;
505 default:
jvanverth294c3262014-10-10 11:36:12 -0700506 SkFAIL("Unexpected mask format.");
jvanverth0fedb192014-10-08 09:07:27 -0700507 }
508 int nGlyphs = fCurrVertex / 4;
509 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
510 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
511 nGlyphs,
512 4, 6, &fVertexBounds);
513
514 fDrawTarget->resetVertexSource();
515 fVertices = NULL;
516 fMaxVertices = 0;
517 fCurrVertex = 0;
518 fVertexBounds.setLargestInverted();
519 SkSafeSetNull(fCurrTexture);
520 }
521}
522
523inline void GrBitmapTextContext::finish() {
524 this->flush();
525
526 GrTextContext::finish();
527}
528