blob: 94b2770b23c6c90c02d67bfd519cd3d26ccda60e [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
joshualitt5531d512014-12-17 15:50:11 -080069bool GrBitmapTextContext::canDraw(const SkPaint& paint, const SkMatrix& viewMatrix) {
70 return !SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix);
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000071}
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,
joshualitt5531d512014-12-17 15:50:11 -080087 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -080088 const char text[], size_t byteLength,
89 SkScalar x, SkScalar y) {
jvanverthaab626c2014-10-16 08:04:39 -070090 SkASSERT(byteLength == 0 || text != NULL);
91
92 // nothing to draw
93 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
94 return;
95 }
96
97 this->init(paint, skPaint);
98
99 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
100
joshualitt5531d512014-12-17 15:50:11 -0800101 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix);
jvanverthaab626c2014-10-16 08:04:39 -0700102 SkGlyphCache* cache = autoCache.getCache();
103 GrFontScaler* fontScaler = GetGrFontScaler(cache);
104
105 // transform our starting point
106 {
107 SkPoint loc;
joshualitt5531d512014-12-17 15:50:11 -0800108 viewMatrix.mapXY(x, y, &loc);
jvanverthaab626c2014-10-16 08:04:39 -0700109 x = loc.fX;
110 y = loc.fY;
111 }
112
113 // need to measure first
jvanverth73f10532014-10-23 11:57:12 -0700114 int numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700115 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
jvanverth73f10532014-10-23 11:57:12 -0700116 SkVector stopVector;
117 numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
jvanverthaab626c2014-10-16 08:04:39 -0700118
jvanverth73f10532014-10-23 11:57:12 -0700119 SkScalar stopX = stopVector.fX;
120 SkScalar stopY = stopVector.fY;
jvanverthaab626c2014-10-16 08:04:39 -0700121
122 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
123 stopX = SkScalarHalf(stopX);
124 stopY = SkScalarHalf(stopY);
125 }
126 x -= stopX;
127 y -= stopY;
jvanverth73f10532014-10-23 11:57:12 -0700128 } else {
129 numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
jvanverthaab626c2014-10-16 08:04:39 -0700130 }
jvanverth73f10532014-10-23 11:57:12 -0700131 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700132
133 const char* stop = text + byteLength;
134
135 SkAutoKern autokern;
136
137 SkFixed fxMask = ~0;
138 SkFixed fyMask = ~0;
139 SkFixed halfSampleX, halfSampleY;
140 if (cache->isSubpixel()) {
141 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
joshualitt5531d512014-12-17 15:50:11 -0800142 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
jvanverthaab626c2014-10-16 08:04:39 -0700143 if (kX_SkAxisAlignment == baseline) {
144 fyMask = 0;
145 halfSampleY = SK_FixedHalf;
146 } else if (kY_SkAxisAlignment == baseline) {
147 fxMask = 0;
148 halfSampleX = SK_FixedHalf;
149 }
150 } else {
151 halfSampleX = halfSampleY = SK_FixedHalf;
152 }
153
154 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
155 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
156
joshualitt73483d92014-12-23 07:58:02 -0800157 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for
158 // performance reasons we just invert here instead
159 if (!viewMatrix.invert(&fLocalMatrix)) {
160 SkDebugf("Cannot invert viewmatrix\n");
joshualitt5531d512014-12-17 15:50:11 -0800161 }
jvanverthaab626c2014-10-16 08:04:39 -0700162
163 while (text < stop) {
164 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
165
166 fx += autokern.adjust(glyph);
167
168 if (glyph.fWidth) {
169 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
170 glyph.getSubXFixed(),
171 glyph.getSubYFixed()),
172 SkFixedFloorToFixed(fx),
173 SkFixedFloorToFixed(fy),
174 fontScaler);
175 }
176
177 fx += glyph.fAdvanceX;
178 fy += glyph.fAdvanceY;
179 }
180
181 this->finish();
182}
183
jvanverth8c27a182014-10-14 08:45:50 -0700184void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
joshualitt5531d512014-12-17 15:50:11 -0800185 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800186 const char text[], size_t byteLength,
187 const SkScalar pos[], int scalarsPerPosition,
188 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000189 SkASSERT(byteLength == 0 || text != NULL);
190 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
191
192 // nothing to draw
193 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
194 return;
195 }
196
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000197 this->init(paint, skPaint);
198
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000199 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
200
joshualitt5531d512014-12-17 15:50:11 -0800201 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000202 SkGlyphCache* cache = autoCache.getCache();
203 GrFontScaler* fontScaler = GetGrFontScaler(cache);
204
joshualitt73483d92014-12-23 07:58:02 -0800205 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for
206 // performance reasons we just invert here instead
207 if (!viewMatrix.invert(&fLocalMatrix)) {
joshualitt5531d512014-12-17 15:50:11 -0800208 SkDebugf("Cannot invert viewmatrix\n");
209 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000210
jvanverth73f10532014-10-23 11:57:12 -0700211 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
212 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
213
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000214 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700215 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
joshualitt73483d92014-12-23 07:58:02 -0800216 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000217 SkFixed halfSampleX = 0, halfSampleY = 0;
218
219 if (cache->isSubpixel()) {
220 // maybe we should skip the rounding if linearText is set
joshualitt73483d92014-12-23 07:58:02 -0800221 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000222
223 SkFixed fxMask = ~0;
224 SkFixed fyMask = ~0;
225 if (kX_SkAxisAlignment == baseline) {
226 fyMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000227 halfSampleY = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000228 } else if (kY_SkAxisAlignment == baseline) {
229 fxMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000230 halfSampleX = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000231 }
232
233 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
234 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700235 SkPoint tmsLoc;
236 tmsProc(pos, &tmsLoc);
237 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
238 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000239
240 const SkGlyph& glyph = glyphCacheProc(cache, &text,
241 fx & fxMask, fy & fyMask);
242
243 if (glyph.fWidth) {
jvanverth0fedb192014-10-08 09:07:27 -0700244 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
245 glyph.getSubXFixed(),
246 glyph.getSubYFixed()),
247 SkFixedFloorToFixed(fx),
248 SkFixedFloorToFixed(fy),
249 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000250 }
251 pos += scalarsPerPosition;
252 }
253 } else {
254 while (text < stop) {
255 const char* currentText = text;
256 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
257
258 if (metricGlyph.fWidth) {
259 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
260 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700261 SkPoint tmsLoc;
262 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000263 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700264 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000265
266 SkFixed fx = fixedLoc.fX + halfSampleX;
267 SkFixed fy = fixedLoc.fY + halfSampleY;
268
269 // have to call again, now that we've been "aligned"
270 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
271 fx & fxMask, fy & fyMask);
272 // the assumption is that the metrics haven't changed
273 SkASSERT(prevAdvX == glyph.fAdvanceX);
274 SkASSERT(prevAdvY == glyph.fAdvanceY);
275 SkASSERT(glyph.fWidth);
276
jvanverth0fedb192014-10-08 09:07:27 -0700277 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
278 glyph.getSubXFixed(),
279 glyph.getSubYFixed()),
280 SkFixedFloorToFixed(fx),
281 SkFixedFloorToFixed(fy),
282 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000283 }
284 pos += scalarsPerPosition;
285 }
286 }
287 } else { // not subpixel
288
289 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
290 while (text < stop) {
291 // the last 2 parameters are ignored
292 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
293
294 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700295 SkPoint tmsLoc;
296 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000297
kkinnunencb9a2c82014-06-12 23:06:28 -0700298 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
299 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700300 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
301 glyph.getSubXFixed(),
302 glyph.getSubYFixed()),
303 SkFixedFloorToFixed(fx),
304 SkFixedFloorToFixed(fy),
305 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000306 }
307 pos += scalarsPerPosition;
308 }
309 } else {
310 while (text < stop) {
311 // the last 2 parameters are ignored
312 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
313
314 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700315 SkPoint tmsLoc;
316 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000317
318 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700319 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000320
321 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
322 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700323 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
324 glyph.getSubXFixed(),
325 glyph.getSubYFixed()),
326 SkFixedFloorToFixed(fx),
327 SkFixedFloorToFixed(fy),
328 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000329 }
330 pos += scalarsPerPosition;
331 }
332 }
333 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000334
335 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000336}
337
joshualitt9853cce2014-11-17 14:22:48 -0800338static size_t get_vertex_stride(GrMaskFormat maskFormat) {
339 switch (maskFormat) {
340 case kA8_GrMaskFormat:
341 return kGrayTextVASize;
342 case kARGB_GrMaskFormat:
343 return kColorTextVASize;
344 default:
345 return kLCDTextVASize;
346 }
347}
348
joshualitt9853cce2014-11-17 14:22:48 -0800349static void* alloc_vertices(GrDrawTarget* drawTarget,
350 int numVertices,
351 GrMaskFormat maskFormat) {
jvanverth73f10532014-10-23 11:57:12 -0700352 if (numVertices <= 0) {
353 return NULL;
354 }
355
356 // set up attributes
jvanverth73f10532014-10-23 11:57:12 -0700357 void* vertices = NULL;
358 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
joshualitt9853cce2014-11-17 14:22:48 -0800359 get_vertex_stride(maskFormat),
jvanverth73f10532014-10-23 11:57:12 -0700360 0,
361 &vertices,
362 NULL);
363 GrAlwaysAssert(success);
364 return vertices;
365}
366
jvanverth787cdf92014-12-04 10:46:50 -0800367inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scaler) {
368 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
369 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
370 return true;
371 }
372
373 // try to clear out an unused plot before we flush
374 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
375 fStrike->addGlyphToAtlas(glyph, scaler)) {
376 return true;
377 }
378
379 if (c_DumpFontCache) {
380#ifdef SK_DEVELOPER
381 fContext->getFontCache()->dump();
382#endif
383 }
384
385 // before we purge the cache, we must flush any accumulated draws
386 this->flush();
387 fContext->flush();
388
389 // we should have an unused plot now
390 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
391 fStrike->addGlyphToAtlas(glyph, scaler)) {
392 return true;
393 }
394
395 // we should never get here
396 SkASSERT(false);
397 }
398
399 return false;
400}
401
jvanverth0fedb192014-10-08 09:07:27 -0700402void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
403 SkFixed vx, SkFixed vy,
404 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400405 if (NULL == fDrawTarget) {
406 return;
407 }
408
409 if (NULL == fStrike) {
410 fStrike = fContext->getFontCache()->getStrike(scaler, false);
411 }
412
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000413 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
414 if (NULL == glyph || glyph->fBounds.isEmpty()) {
415 return;
416 }
417
418 vx += SkIntToFixed(glyph->fBounds.fLeft);
419 vy += SkIntToFixed(glyph->fBounds.fTop);
420
421 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000422 SkFixed width = glyph->fBounds.width();
423 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000424
425 // check if we clipped out
426 if (true || NULL == glyph->fPlot) {
427 int x = vx >> 16;
428 int y = vy >> 16;
429 if (fClipRect.quickReject(x, y, x + width, y + height)) {
430// SkCLZ(3); // so we can set a break-point in the debugger
431 return;
432 }
433 }
434
joshualittc2625822014-12-18 16:40:54 -0800435 // If the glyph is too large we fall back to paths
jvanverth787cdf92014-12-04 10:46:50 -0800436 if (NULL == glyph->fPlot && !uploadGlyph(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000437 if (NULL == glyph->fPath) {
438 SkPath* path = SkNEW(SkPath);
439 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
440 // flag the glyph as being dead?
441 delete path;
442 return;
443 }
444 glyph->fPath = path;
445 }
446
bsalomonec87dc62014-10-14 10:52:00 -0700447 // flush any accumulated draws before drawing this glyph as a path.
448 this->flush();
449
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000450 SkMatrix translate;
451 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
452 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
joshualittc2625822014-12-18 16:40:54 -0800453 SkPath tmpPath(*glyph->fPath);
454 tmpPath.transform(translate);
egdanield58a0ba2014-06-11 10:30:05 -0700455 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
joshualittc2625822014-12-18 16:40:54 -0800456 fContext->drawPath(fPaint, SkMatrix::I(), tmpPath, strokeInfo);
jvanverth73f10532014-10-23 11:57:12 -0700457
458 // remove this glyph from the vertices we need to allocate
459 fTotalVertexCount -= kVerticesPerGlyph;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000460 return;
461 }
462
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000463 SkASSERT(glyph->fPlot);
464 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
465 glyph->fPlot->setDrawToken(drawToken);
466
467 // now promote them to fixed (TODO: Rethink using fixed pt).
468 width = SkIntToFixed(width);
469 height = SkIntToFixed(height);
470
jvanverth294c3262014-10-10 11:36:12 -0700471 // the current texture/maskformat must match what the glyph needs
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000472 GrTexture* texture = glyph->fPlot->texture();
473 SkASSERT(texture);
474
jvanverth73f10532014-10-23 11:57:12 -0700475 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
jvanverth0fedb192014-10-08 09:07:27 -0700476 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400477 fCurrTexture = texture;
478 fCurrTexture->ref();
jvanverth294c3262014-10-10 11:36:12 -0700479 fCurrMaskFormat = glyph->fMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400480 }
481
Mike Klein6a25bd02014-08-29 10:03:59 -0400482 if (NULL == fVertices) {
jvanverth73f10532014-10-23 11:57:12 -0700483 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
484 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
egdanieled3af662014-10-31 06:55:45 -0700485 fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
Mike Klein6a25bd02014-08-29 10:03:59 -0400486 }
487
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000488 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
489 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000490
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000491 SkRect r;
492 r.fLeft = SkFixedToFloat(vx);
493 r.fTop = SkFixedToFloat(vy);
494 r.fRight = SkFixedToFloat(vx + width);
495 r.fBottom = SkFixedToFloat(vy + height);
496
reed10d03272014-10-01 09:24:12 -0700497 fVertexBounds.joinNonEmptyArg(r);
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000498
joshualitt9853cce2014-11-17 14:22:48 -0800499 size_t vertSize = get_vertex_stride(fCurrMaskFormat);
bsalomon594069f2014-06-06 06:16:34 -0700500
501 SkPoint* positions = reinterpret_cast<SkPoint*>(
502 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
503 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
504
505 // The texture coords are last in both the with and without color vertex layouts.
506 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
507 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
bsalomonafbf2d62014-09-30 12:18:44 -0700508 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
509 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
510 SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
511 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
bsalomon594069f2014-06-06 06:16:34 -0700512 vertSize);
egdanieled3af662014-10-31 06:55:45 -0700513 if (kA8_GrMaskFormat == fCurrMaskFormat) {
bsalomon594069f2014-06-06 06:16:34 -0700514 // color comes after position.
515 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
516 for (int i = 0; i < 4; ++i) {
517 *colors = fPaint.getColor();
518 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
519 }
520 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000521 fCurrVertex += 4;
522}
jvanverth0fedb192014-10-08 09:07:27 -0700523
jvanverth0fedb192014-10-08 09:07:27 -0700524void GrBitmapTextContext::flush() {
525 if (NULL == fDrawTarget) {
526 return;
527 }
528
jvanverth0fedb192014-10-08 09:07:27 -0700529 if (fCurrVertex > 0) {
joshualitt780b11e2014-11-18 09:40:40 -0800530 GrDrawState drawState;
531 drawState.setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
532
jvanverth0fedb192014-10-08 09:07:27 -0700533 // setup our sampler state for our text texture/atlas
534 SkASSERT(SkIsAlign4(fCurrVertex));
535 SkASSERT(fCurrTexture);
jvanverth0fedb192014-10-08 09:07:27 -0700536
jvanverth0fedb192014-10-08 09:07:27 -0700537 SkASSERT(fStrike);
joshualitt2e3b3e32014-12-09 13:31:14 -0800538 GrColor color = fPaint.getColor();
jvanverth294c3262014-10-10 11:36:12 -0700539 switch (fCurrMaskFormat) {
jvanverth0fedb192014-10-08 09:07:27 -0700540 // Color bitmap text
joshualitt2e3b3e32014-12-09 13:31:14 -0800541 case kARGB_GrMaskFormat: {
542 int a = fSkPaint.getAlpha();
543 color = SkColorSetARGB(a, a, a, a);
jvanverth0fedb192014-10-08 09:07:27 -0700544 break;
joshualitt2e3b3e32014-12-09 13:31:14 -0800545 }
jvanverth0fedb192014-10-08 09:07:27 -0700546 // LCD text
jvanverth0fedb192014-10-08 09:07:27 -0700547 case kA565_GrMaskFormat: {
egdaniel378092f2014-12-03 10:40:13 -0800548 // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
549 // processor if the xp can support it. For now we will simply assume that if
550 // fUseLCDText is true, then we have a known color output.
551 if (!drawState.getXPFactory()->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
tfarina38406c82014-10-31 07:11:12 -0700552 SkDebugf("LCD Text will not draw correctly.\n");
jvanverth0fedb192014-10-08 09:07:27 -0700553 }
jvanverth0fedb192014-10-08 09:07:27 -0700554 break;
555 }
556 // Grayscale/BW text
557 case kA8_GrMaskFormat:
jvanverth0fedb192014-10-08 09:07:27 -0700558 break;
559 default:
jvanverth294c3262014-10-10 11:36:12 -0700560 SkFAIL("Unexpected mask format.");
jvanverth0fedb192014-10-08 09:07:27 -0700561 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800562
563 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
joshualitt2e3b3e32014-12-09 13:31:14 -0800564 if (kARGB_GrMaskFormat == fCurrMaskFormat) {
565 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
566 if (textureUniqueID != fEffectTextureUniqueID ||
joshualitt56995b52014-12-11 15:44:02 -0800567 fCachedGeometryProcessor->color() != color) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800568 uint32_t flags = GrDefaultGeoProcFactory::kLocalCoord_GPType;
569 fCachedGeometryProcessor.reset(GrDefaultGeoProcFactory::Create(color, flags));
570 fCachedTextureProcessor.reset(GrSimpleTextureEffect::Create(fCurrTexture,
571 SkMatrix::I(),
572 params));
joshualitt8fc6c2d2014-12-22 15:27:05 -0800573 fEffectTextureUniqueID = textureUniqueID;
joshualitt2e3b3e32014-12-09 13:31:14 -0800574 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800575 drawState.addColorProcessor(fCachedTextureProcessor.get());
576 } else {
577 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
578 if (textureUniqueID != fEffectTextureUniqueID ||
joshualitt8fc6c2d2014-12-22 15:27:05 -0800579 fCachedGeometryProcessor->color() != color ||
580 !fCachedGeometryProcessor->localMatrix().cheapEqualTo(fLocalMatrix)) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800581 bool hasColor = kA8_GrMaskFormat == fCurrMaskFormat;
joshualitt56995b52014-12-11 15:44:02 -0800582 bool opaqueVertexColors = GrColorIsOpaque(fPaint.getColor());
joshualitt2e3b3e32014-12-09 13:31:14 -0800583 fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color,
joshualitt56995b52014-12-11 15:44:02 -0800584 fCurrTexture,
585 params,
586 hasColor,
joshualitt8fc6c2d2014-12-22 15:27:05 -0800587 opaqueVertexColors,
588 fLocalMatrix));
joshualitt2e3b3e32014-12-09 13:31:14 -0800589 fEffectTextureUniqueID = textureUniqueID;
590 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800591 }
592
jvanverth73f10532014-10-23 11:57:12 -0700593 int nGlyphs = fCurrVertex / kVerticesPerGlyph;
jvanverth0fedb192014-10-08 09:07:27 -0700594 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
joshualitt9853cce2014-11-17 14:22:48 -0800595 fDrawTarget->drawIndexedInstances(&drawState,
joshualitt56995b52014-12-11 15:44:02 -0800596 fCachedGeometryProcessor.get(),
joshualitt9853cce2014-11-17 14:22:48 -0800597 kTriangles_GrPrimitiveType,
jvanverth0fedb192014-10-08 09:07:27 -0700598 nGlyphs,
joshualitt9853cce2014-11-17 14:22:48 -0800599 kVerticesPerGlyph,
600 kIndicesPerGlyph,
601 &fVertexBounds);
jvanverth0fedb192014-10-08 09:07:27 -0700602
603 fDrawTarget->resetVertexSource();
604 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -0700605 fAllocVertexCount = 0;
606 // reset to be those that are left
607 fTotalVertexCount -= fCurrVertex;
jvanverth0fedb192014-10-08 09:07:27 -0700608 fCurrVertex = 0;
609 fVertexBounds.setLargestInverted();
610 SkSafeSetNull(fCurrTexture);
611 }
612}
613
614inline void GrBitmapTextContext::finish() {
615 this->flush();
jvanverth73f10532014-10-23 11:57:12 -0700616 fTotalVertexCount = 0;
jvanverth0fedb192014-10-08 09:07:27 -0700617
618 GrTextContext::finish();
619}
620