blob: bf27584f26c4309dfe5261c314c413298c39ef4d [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"
joshualitt5478d422014-11-14 16:00:38 -080010#include "GrDefaultGeoProcFactory.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000011#include "GrDrawTarget.h"
jvanverth787cdf92014-12-04 10:46:50 -080012#include "GrFontCache.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000013#include "GrFontScaler.h"
14#include "GrIndexBuffer.h"
egdanield58a0ba2014-06-11 10:30:05 -070015#include "GrStrokeInfo.h"
bsalomonafbf2d62014-09-30 12:18:44 -070016#include "GrTexturePriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000017
jvanverthaab626c2014-10-16 08:04:39 -070018#include "SkAutoKern.h"
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
egdaniel309e3462014-12-09 10:35:58 -080030#include "effects/GrBitmapTextGeoProc.h"
joshualitt5478d422014-11-14 16:00:38 -080031#include "effects/GrSimpleTextureEffect.h"
32
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000033SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
34 "Dump the contents of the font cache before every purge.");
35
bsalomon594069f2014-06-06 06:16:34 -070036namespace {
egdanieled3af662014-10-31 06:55:45 -070037static const size_t kLCDTextVASize = 2 * sizeof(SkPoint);
38
39// position + local coord
egdanieled3af662014-10-31 06:55:45 -070040static const size_t kColorTextVASize = 2 * sizeof(SkPoint);
egdaniel7b3d5ee2014-08-28 05:41:14 -070041
egdanieled3af662014-10-31 06:55:45 -070042static const size_t kGrayTextVASize = 2 * sizeof(SkPoint) + sizeof(GrColor);
egdaniel7b3d5ee2014-08-28 05:41:14 -070043
jvanverth73f10532014-10-23 11:57:12 -070044static const int kVerticesPerGlyph = 4;
45static const int kIndicesPerGlyph = 6;
bsalomon594069f2014-06-06 06:16:34 -070046};
47
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000048GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000049 const SkDeviceProperties& properties)
Mike Klein6a25bd02014-08-29 10:03:59 -040050 : GrTextContext(context, properties) {
51 fStrike = NULL;
52
53 fCurrTexture = NULL;
Mike Klein6a25bd02014-08-29 10:03:59 -040054 fEffectTextureUniqueID = SK_InvalidUniqueID;
55
56 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -070057 fCurrVertex = 0;
58 fAllocVertexCount = 0;
59 fTotalVertexCount = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -040060
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000061 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000062}
63
jvanverth8c27a182014-10-14 08:45:50 -070064GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context,
65 const SkDeviceProperties& props) {
66 return SkNEW_ARGS(GrBitmapTextContext, (context, props));
67}
68
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000069bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
70 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
71}
72
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000073inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
74 GrTextContext::init(paint, skPaint);
75
76 fStrike = NULL;
77
Mike Klein6a25bd02014-08-29 10:03:59 -040078 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -070079 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -040080
81 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -070082 fAllocVertexCount = 0;
83 fTotalVertexCount = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000084}
85
jvanverthaab626c2014-10-16 08:04:39 -070086void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
joshualitt9853cce2014-11-17 14:22:48 -080087 const char text[], size_t byteLength,
88 SkScalar x, SkScalar y) {
jvanverthaab626c2014-10-16 08:04:39 -070089 SkASSERT(byteLength == 0 || text != NULL);
90
91 // nothing to draw
92 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
93 return;
94 }
95
96 this->init(paint, skPaint);
97
98 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
99
100 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
101 SkGlyphCache* cache = autoCache.getCache();
102 GrFontScaler* fontScaler = GetGrFontScaler(cache);
103
104 // transform our starting point
105 {
106 SkPoint loc;
107 fContext->getMatrix().mapXY(x, y, &loc);
108 x = loc.fX;
109 y = loc.fY;
110 }
111
112 // need to measure first
jvanverth73f10532014-10-23 11:57:12 -0700113 int numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700114 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
jvanverth73f10532014-10-23 11:57:12 -0700115 SkVector stopVector;
116 numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
jvanverthaab626c2014-10-16 08:04:39 -0700117
jvanverth73f10532014-10-23 11:57:12 -0700118 SkScalar stopX = stopVector.fX;
119 SkScalar stopY = stopVector.fY;
jvanverthaab626c2014-10-16 08:04:39 -0700120
121 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
122 stopX = SkScalarHalf(stopX);
123 stopY = SkScalarHalf(stopY);
124 }
125 x -= stopX;
126 y -= stopY;
jvanverth73f10532014-10-23 11:57:12 -0700127 } else {
128 numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
jvanverthaab626c2014-10-16 08:04:39 -0700129 }
jvanverth73f10532014-10-23 11:57:12 -0700130 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700131
132 const char* stop = text + byteLength;
133
134 SkAutoKern autokern;
135
136 SkFixed fxMask = ~0;
137 SkFixed fyMask = ~0;
138 SkFixed halfSampleX, halfSampleY;
139 if (cache->isSubpixel()) {
140 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
141 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
142 if (kX_SkAxisAlignment == baseline) {
143 fyMask = 0;
144 halfSampleY = SK_FixedHalf;
145 } else if (kY_SkAxisAlignment == baseline) {
146 fxMask = 0;
147 halfSampleX = SK_FixedHalf;
148 }
149 } else {
150 halfSampleX = halfSampleY = SK_FixedHalf;
151 }
152
153 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
154 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
155
156 GrContext::AutoMatrix autoMatrix;
157 autoMatrix.setIdentity(fContext, &fPaint);
158
159 while (text < stop) {
160 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
161
162 fx += autokern.adjust(glyph);
163
164 if (glyph.fWidth) {
165 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
166 glyph.getSubXFixed(),
167 glyph.getSubYFixed()),
168 SkFixedFloorToFixed(fx),
169 SkFixedFloorToFixed(fy),
170 fontScaler);
171 }
172
173 fx += glyph.fAdvanceX;
174 fy += glyph.fAdvanceY;
175 }
176
177 this->finish();
178}
179
jvanverth8c27a182014-10-14 08:45:50 -0700180void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
joshualitt9853cce2014-11-17 14:22:48 -0800181 const char text[], size_t byteLength,
182 const SkScalar pos[], int scalarsPerPosition,
183 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000184 SkASSERT(byteLength == 0 || text != NULL);
185 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
186
187 // nothing to draw
188 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
189 return;
190 }
191
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000192 this->init(paint, skPaint);
193
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000194 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
195
196 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
197 SkGlyphCache* cache = autoCache.getCache();
198 GrFontScaler* fontScaler = GetGrFontScaler(cache);
199
200 // store original matrix before we reset, so we can use it to transform positions
201 SkMatrix ctm = fContext->getMatrix();
202 GrContext::AutoMatrix autoMatrix;
203 autoMatrix.setIdentity(fContext, &fPaint);
204
jvanverth73f10532014-10-23 11:57:12 -0700205 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
206 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
207
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000208 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700209 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
fmalita05c4a432014-09-29 06:29:53 -0700210 SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000211 SkFixed halfSampleX = 0, halfSampleY = 0;
212
213 if (cache->isSubpixel()) {
214 // maybe we should skip the rounding if linearText is set
215 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
216
217 SkFixed fxMask = ~0;
218 SkFixed fyMask = ~0;
219 if (kX_SkAxisAlignment == baseline) {
220 fyMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000221 halfSampleY = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000222 } else if (kY_SkAxisAlignment == baseline) {
223 fxMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000224 halfSampleX = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000225 }
226
227 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
228 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700229 SkPoint tmsLoc;
230 tmsProc(pos, &tmsLoc);
231 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
232 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000233
234 const SkGlyph& glyph = glyphCacheProc(cache, &text,
235 fx & fxMask, fy & fyMask);
236
237 if (glyph.fWidth) {
jvanverth0fedb192014-10-08 09:07:27 -0700238 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
239 glyph.getSubXFixed(),
240 glyph.getSubYFixed()),
241 SkFixedFloorToFixed(fx),
242 SkFixedFloorToFixed(fy),
243 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000244 }
245 pos += scalarsPerPosition;
246 }
247 } else {
248 while (text < stop) {
249 const char* currentText = text;
250 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
251
252 if (metricGlyph.fWidth) {
253 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
254 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700255 SkPoint tmsLoc;
256 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000257 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700258 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000259
260 SkFixed fx = fixedLoc.fX + halfSampleX;
261 SkFixed fy = fixedLoc.fY + halfSampleY;
262
263 // have to call again, now that we've been "aligned"
264 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
265 fx & fxMask, fy & fyMask);
266 // the assumption is that the metrics haven't changed
267 SkASSERT(prevAdvX == glyph.fAdvanceX);
268 SkASSERT(prevAdvY == glyph.fAdvanceY);
269 SkASSERT(glyph.fWidth);
270
jvanverth0fedb192014-10-08 09:07:27 -0700271 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
272 glyph.getSubXFixed(),
273 glyph.getSubYFixed()),
274 SkFixedFloorToFixed(fx),
275 SkFixedFloorToFixed(fy),
276 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000277 }
278 pos += scalarsPerPosition;
279 }
280 }
281 } else { // not subpixel
282
283 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
284 while (text < stop) {
285 // the last 2 parameters are ignored
286 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
287
288 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700289 SkPoint tmsLoc;
290 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000291
kkinnunencb9a2c82014-06-12 23:06:28 -0700292 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
293 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700294 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
295 glyph.getSubXFixed(),
296 glyph.getSubYFixed()),
297 SkFixedFloorToFixed(fx),
298 SkFixedFloorToFixed(fy),
299 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000300 }
301 pos += scalarsPerPosition;
302 }
303 } else {
304 while (text < stop) {
305 // the last 2 parameters are ignored
306 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
307
308 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700309 SkPoint tmsLoc;
310 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000311
312 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700313 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000314
315 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
316 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700317 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
318 glyph.getSubXFixed(),
319 glyph.getSubYFixed()),
320 SkFixedFloorToFixed(fx),
321 SkFixedFloorToFixed(fy),
322 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000323 }
324 pos += scalarsPerPosition;
325 }
326 }
327 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000328
329 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000330}
331
joshualitt9853cce2014-11-17 14:22:48 -0800332static size_t get_vertex_stride(GrMaskFormat maskFormat) {
333 switch (maskFormat) {
334 case kA8_GrMaskFormat:
335 return kGrayTextVASize;
336 case kARGB_GrMaskFormat:
337 return kColorTextVASize;
338 default:
339 return kLCDTextVASize;
340 }
341}
342
joshualitt9853cce2014-11-17 14:22:48 -0800343static void* alloc_vertices(GrDrawTarget* drawTarget,
344 int numVertices,
345 GrMaskFormat maskFormat) {
jvanverth73f10532014-10-23 11:57:12 -0700346 if (numVertices <= 0) {
347 return NULL;
348 }
349
350 // set up attributes
jvanverth73f10532014-10-23 11:57:12 -0700351 void* vertices = NULL;
352 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
joshualitt9853cce2014-11-17 14:22:48 -0800353 get_vertex_stride(maskFormat),
jvanverth73f10532014-10-23 11:57:12 -0700354 0,
355 &vertices,
356 NULL);
357 GrAlwaysAssert(success);
358 return vertices;
359}
360
jvanverth787cdf92014-12-04 10:46:50 -0800361inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scaler) {
362 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
363 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
364 return true;
365 }
366
367 // try to clear out an unused plot before we flush
368 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
369 fStrike->addGlyphToAtlas(glyph, scaler)) {
370 return true;
371 }
372
373 if (c_DumpFontCache) {
374#ifdef SK_DEVELOPER
375 fContext->getFontCache()->dump();
376#endif
377 }
378
379 // before we purge the cache, we must flush any accumulated draws
380 this->flush();
381 fContext->flush();
382
383 // we should have an unused plot now
384 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
385 fStrike->addGlyphToAtlas(glyph, scaler)) {
386 return true;
387 }
388
389 // we should never get here
390 SkASSERT(false);
391 }
392
393 return false;
394}
395
jvanverth0fedb192014-10-08 09:07:27 -0700396void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
397 SkFixed vx, SkFixed vy,
398 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400399 if (NULL == fDrawTarget) {
400 return;
401 }
402
403 if (NULL == fStrike) {
404 fStrike = fContext->getFontCache()->getStrike(scaler, false);
405 }
406
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000407 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
408 if (NULL == glyph || glyph->fBounds.isEmpty()) {
409 return;
410 }
411
412 vx += SkIntToFixed(glyph->fBounds.fLeft);
413 vy += SkIntToFixed(glyph->fBounds.fTop);
414
415 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000416 SkFixed width = glyph->fBounds.width();
417 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000418
419 // check if we clipped out
420 if (true || NULL == glyph->fPlot) {
421 int x = vx >> 16;
422 int y = vy >> 16;
423 if (fClipRect.quickReject(x, y, x + width, y + height)) {
424// SkCLZ(3); // so we can set a break-point in the debugger
425 return;
426 }
427 }
428
jvanverth787cdf92014-12-04 10:46:50 -0800429 if (NULL == glyph->fPlot && !uploadGlyph(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000430 if (NULL == glyph->fPath) {
431 SkPath* path = SkNEW(SkPath);
432 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
433 // flag the glyph as being dead?
434 delete path;
435 return;
436 }
437 glyph->fPath = path;
438 }
439
bsalomonec87dc62014-10-14 10:52:00 -0700440 // flush any accumulated draws before drawing this glyph as a path.
441 this->flush();
442
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000443 GrContext::AutoMatrix am;
444 SkMatrix translate;
445 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
446 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
447 GrPaint tmpPaint(fPaint);
448 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700449 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
450 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth73f10532014-10-23 11:57:12 -0700451
452 // remove this glyph from the vertices we need to allocate
453 fTotalVertexCount -= kVerticesPerGlyph;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000454 return;
455 }
456
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000457 SkASSERT(glyph->fPlot);
458 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
459 glyph->fPlot->setDrawToken(drawToken);
460
461 // now promote them to fixed (TODO: Rethink using fixed pt).
462 width = SkIntToFixed(width);
463 height = SkIntToFixed(height);
464
jvanverth294c3262014-10-10 11:36:12 -0700465 // the current texture/maskformat must match what the glyph needs
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000466 GrTexture* texture = glyph->fPlot->texture();
467 SkASSERT(texture);
468
jvanverth73f10532014-10-23 11:57:12 -0700469 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
jvanverth0fedb192014-10-08 09:07:27 -0700470 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400471 fCurrTexture = texture;
472 fCurrTexture->ref();
jvanverth294c3262014-10-10 11:36:12 -0700473 fCurrMaskFormat = glyph->fMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400474 }
475
Mike Klein6a25bd02014-08-29 10:03:59 -0400476 if (NULL == fVertices) {
jvanverth73f10532014-10-23 11:57:12 -0700477 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
478 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
egdanieled3af662014-10-31 06:55:45 -0700479 fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
Mike Klein6a25bd02014-08-29 10:03:59 -0400480 }
481
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000482 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
483 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000484
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000485 SkRect r;
486 r.fLeft = SkFixedToFloat(vx);
487 r.fTop = SkFixedToFloat(vy);
488 r.fRight = SkFixedToFloat(vx + width);
489 r.fBottom = SkFixedToFloat(vy + height);
490
reed10d03272014-10-01 09:24:12 -0700491 fVertexBounds.joinNonEmptyArg(r);
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000492
joshualitt9853cce2014-11-17 14:22:48 -0800493 size_t vertSize = get_vertex_stride(fCurrMaskFormat);
bsalomon594069f2014-06-06 06:16:34 -0700494
495 SkPoint* positions = reinterpret_cast<SkPoint*>(
496 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
497 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
498
499 // The texture coords are last in both the with and without color vertex layouts.
500 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
501 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
bsalomonafbf2d62014-09-30 12:18:44 -0700502 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
503 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
504 SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
505 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
bsalomon594069f2014-06-06 06:16:34 -0700506 vertSize);
egdanieled3af662014-10-31 06:55:45 -0700507 if (kA8_GrMaskFormat == fCurrMaskFormat) {
bsalomon594069f2014-06-06 06:16:34 -0700508 // color comes after position.
509 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
510 for (int i = 0; i < 4; ++i) {
511 *colors = fPaint.getColor();
512 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
513 }
514 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000515 fCurrVertex += 4;
516}
jvanverth0fedb192014-10-08 09:07:27 -0700517
jvanverth0fedb192014-10-08 09:07:27 -0700518void GrBitmapTextContext::flush() {
519 if (NULL == fDrawTarget) {
520 return;
521 }
522
jvanverth0fedb192014-10-08 09:07:27 -0700523 if (fCurrVertex > 0) {
joshualitt780b11e2014-11-18 09:40:40 -0800524 GrDrawState drawState;
525 drawState.setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
526
jvanverth0fedb192014-10-08 09:07:27 -0700527 // setup our sampler state for our text texture/atlas
528 SkASSERT(SkIsAlign4(fCurrVertex));
529 SkASSERT(fCurrTexture);
jvanverth0fedb192014-10-08 09:07:27 -0700530
jvanverth0fedb192014-10-08 09:07:27 -0700531 SkASSERT(fStrike);
joshualitt2e3b3e32014-12-09 13:31:14 -0800532 GrColor color = fPaint.getColor();
jvanverth294c3262014-10-10 11:36:12 -0700533 switch (fCurrMaskFormat) {
jvanverth0fedb192014-10-08 09:07:27 -0700534 // Color bitmap text
joshualitt2e3b3e32014-12-09 13:31:14 -0800535 case kARGB_GrMaskFormat: {
536 int a = fSkPaint.getAlpha();
537 color = SkColorSetARGB(a, a, a, a);
jvanverth0fedb192014-10-08 09:07:27 -0700538 break;
joshualitt2e3b3e32014-12-09 13:31:14 -0800539 }
jvanverth0fedb192014-10-08 09:07:27 -0700540 // LCD text
jvanverth0fedb192014-10-08 09:07:27 -0700541 case kA565_GrMaskFormat: {
egdaniel378092f2014-12-03 10:40:13 -0800542 // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
543 // processor if the xp can support it. For now we will simply assume that if
544 // fUseLCDText is true, then we have a known color output.
545 if (!drawState.getXPFactory()->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
tfarina38406c82014-10-31 07:11:12 -0700546 SkDebugf("LCD Text will not draw correctly.\n");
jvanverth0fedb192014-10-08 09:07:27 -0700547 }
jvanverth0fedb192014-10-08 09:07:27 -0700548 break;
549 }
550 // Grayscale/BW text
551 case kA8_GrMaskFormat:
jvanverth0fedb192014-10-08 09:07:27 -0700552 break;
553 default:
jvanverth294c3262014-10-10 11:36:12 -0700554 SkFAIL("Unexpected mask format.");
jvanverth0fedb192014-10-08 09:07:27 -0700555 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800556
557 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
558 // TODO cache these GPs
559 if (kARGB_GrMaskFormat == fCurrMaskFormat) {
560 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
561 if (textureUniqueID != fEffectTextureUniqueID ||
joshualitt56995b52014-12-11 15:44:02 -0800562 fCachedGeometryProcessor->color() != color) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800563 uint32_t flags = GrDefaultGeoProcFactory::kLocalCoord_GPType;
564 fCachedGeometryProcessor.reset(GrDefaultGeoProcFactory::Create(color, flags));
565 fCachedTextureProcessor.reset(GrSimpleTextureEffect::Create(fCurrTexture,
566 SkMatrix::I(),
567 params));
568 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800569 drawState.addColorProcessor(fCachedTextureProcessor.get());
570 } else {
571 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
572 if (textureUniqueID != fEffectTextureUniqueID ||
joshualitt56995b52014-12-11 15:44:02 -0800573 fCachedGeometryProcessor->color() != color) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800574 bool hasColor = kA8_GrMaskFormat == fCurrMaskFormat;
joshualitt56995b52014-12-11 15:44:02 -0800575 bool opaqueVertexColors = GrColorIsOpaque(fPaint.getColor());
joshualitt2e3b3e32014-12-09 13:31:14 -0800576 fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color,
joshualitt56995b52014-12-11 15:44:02 -0800577 fCurrTexture,
578 params,
579 hasColor,
580 opaqueVertexColors));
joshualitt2e3b3e32014-12-09 13:31:14 -0800581 fEffectTextureUniqueID = textureUniqueID;
582 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800583 }
584
jvanverth73f10532014-10-23 11:57:12 -0700585 int nGlyphs = fCurrVertex / kVerticesPerGlyph;
jvanverth0fedb192014-10-08 09:07:27 -0700586 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
joshualitt9853cce2014-11-17 14:22:48 -0800587 fDrawTarget->drawIndexedInstances(&drawState,
joshualitt56995b52014-12-11 15:44:02 -0800588 fCachedGeometryProcessor.get(),
joshualitt9853cce2014-11-17 14:22:48 -0800589 kTriangles_GrPrimitiveType,
jvanverth0fedb192014-10-08 09:07:27 -0700590 nGlyphs,
joshualitt9853cce2014-11-17 14:22:48 -0800591 kVerticesPerGlyph,
592 kIndicesPerGlyph,
593 &fVertexBounds);
jvanverth0fedb192014-10-08 09:07:27 -0700594
595 fDrawTarget->resetVertexSource();
596 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -0700597 fAllocVertexCount = 0;
598 // reset to be those that are left
599 fTotalVertexCount -= fCurrVertex;
jvanverth0fedb192014-10-08 09:07:27 -0700600 fCurrVertex = 0;
601 fVertexBounds.setLargestInverted();
602 SkSafeSetNull(fCurrTexture);
603 }
604}
605
606inline void GrBitmapTextContext::finish() {
607 this->flush();
jvanverth73f10532014-10-23 11:57:12 -0700608 fTotalVertexCount = 0;
jvanverth0fedb192014-10-08 09:07:27 -0700609
610 GrTextContext::finish();
611}
612