blob: 21afc61d845e236097059ee1de7d0e342de0fccf [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 {
jvanverth5a105ff2015-02-18 11:36:35 -080037static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
egdanieled3af662014-10-31 06:55:45 -070038
39// position + local coord
jvanverth5a105ff2015-02-18 11:36:35 -080040static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
egdaniel7b3d5ee2014-08-28 05:41:14 -070041
jvanverth5a105ff2015-02-18 11:36:35 -080042static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
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)) {
joshualitt787bb482015-01-02 10:54:26 -0800160 SkDebugf("Cannot invert viewmatrix\n");
161 return;
joshualitt5531d512014-12-17 15:50:11 -0800162 }
jvanverthaab626c2014-10-16 08:04:39 -0700163
164 while (text < stop) {
165 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
166
167 fx += autokern.adjust(glyph);
168
169 if (glyph.fWidth) {
170 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
171 glyph.getSubXFixed(),
172 glyph.getSubYFixed()),
173 SkFixedFloorToFixed(fx),
174 SkFixedFloorToFixed(fy),
175 fontScaler);
176 }
177
178 fx += glyph.fAdvanceX;
179 fy += glyph.fAdvanceY;
180 }
181
182 this->finish();
183}
184
jvanverth8c27a182014-10-14 08:45:50 -0700185void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
joshualitt5531d512014-12-17 15:50:11 -0800186 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800187 const char text[], size_t byteLength,
188 const SkScalar pos[], int scalarsPerPosition,
189 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000190 SkASSERT(byteLength == 0 || text != NULL);
191 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
192
193 // nothing to draw
194 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
195 return;
196 }
197
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000198 this->init(paint, skPaint);
199
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000200 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
201
joshualitt5531d512014-12-17 15:50:11 -0800202 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000203 SkGlyphCache* cache = autoCache.getCache();
204 GrFontScaler* fontScaler = GetGrFontScaler(cache);
205
joshualitt73483d92014-12-23 07:58:02 -0800206 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for
207 // performance reasons we just invert here instead
208 if (!viewMatrix.invert(&fLocalMatrix)) {
joshualitt787bb482015-01-02 10:54:26 -0800209 SkDebugf("Cannot invert viewmatrix\n");
210 return;
joshualitt5531d512014-12-17 15:50:11 -0800211 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000212
jvanverth73f10532014-10-23 11:57:12 -0700213 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
214 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
215
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000216 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700217 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
joshualitt73483d92014-12-23 07:58:02 -0800218 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000219 SkFixed halfSampleX = 0, halfSampleY = 0;
220
221 if (cache->isSubpixel()) {
222 // maybe we should skip the rounding if linearText is set
joshualitt73483d92014-12-23 07:58:02 -0800223 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000224
225 SkFixed fxMask = ~0;
226 SkFixed fyMask = ~0;
227 if (kX_SkAxisAlignment == baseline) {
228 fyMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000229 halfSampleY = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000230 } else if (kY_SkAxisAlignment == baseline) {
231 fxMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000232 halfSampleX = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000233 }
234
235 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
236 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700237 SkPoint tmsLoc;
238 tmsProc(pos, &tmsLoc);
239 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
240 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000241
242 const SkGlyph& glyph = glyphCacheProc(cache, &text,
243 fx & fxMask, fy & fyMask);
244
245 if (glyph.fWidth) {
jvanverth0fedb192014-10-08 09:07:27 -0700246 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
247 glyph.getSubXFixed(),
248 glyph.getSubYFixed()),
249 SkFixedFloorToFixed(fx),
250 SkFixedFloorToFixed(fy),
251 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000252 }
253 pos += scalarsPerPosition;
254 }
255 } else {
256 while (text < stop) {
257 const char* currentText = text;
258 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
259
260 if (metricGlyph.fWidth) {
261 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
262 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700263 SkPoint tmsLoc;
264 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000265 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700266 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000267
268 SkFixed fx = fixedLoc.fX + halfSampleX;
269 SkFixed fy = fixedLoc.fY + halfSampleY;
270
271 // have to call again, now that we've been "aligned"
272 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
273 fx & fxMask, fy & fyMask);
274 // the assumption is that the metrics haven't changed
275 SkASSERT(prevAdvX == glyph.fAdvanceX);
276 SkASSERT(prevAdvY == glyph.fAdvanceY);
277 SkASSERT(glyph.fWidth);
278
jvanverth0fedb192014-10-08 09:07:27 -0700279 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
280 glyph.getSubXFixed(),
281 glyph.getSubYFixed()),
282 SkFixedFloorToFixed(fx),
283 SkFixedFloorToFixed(fy),
284 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000285 }
286 pos += scalarsPerPosition;
287 }
288 }
289 } else { // not subpixel
290
291 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
292 while (text < stop) {
293 // the last 2 parameters are ignored
294 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
295
296 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700297 SkPoint tmsLoc;
298 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000299
kkinnunencb9a2c82014-06-12 23:06:28 -0700300 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
301 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700302 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
303 glyph.getSubXFixed(),
304 glyph.getSubYFixed()),
305 SkFixedFloorToFixed(fx),
306 SkFixedFloorToFixed(fy),
307 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000308 }
309 pos += scalarsPerPosition;
310 }
311 } else {
312 while (text < stop) {
313 // the last 2 parameters are ignored
314 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
315
316 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700317 SkPoint tmsLoc;
318 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000319
320 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700321 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000322
323 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
324 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700325 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
326 glyph.getSubXFixed(),
327 glyph.getSubYFixed()),
328 SkFixedFloorToFixed(fx),
329 SkFixedFloorToFixed(fy),
330 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000331 }
332 pos += scalarsPerPosition;
333 }
334 }
335 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000336
337 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000338}
339
joshualitt9853cce2014-11-17 14:22:48 -0800340static size_t get_vertex_stride(GrMaskFormat maskFormat) {
341 switch (maskFormat) {
342 case kA8_GrMaskFormat:
343 return kGrayTextVASize;
344 case kARGB_GrMaskFormat:
345 return kColorTextVASize;
346 default:
347 return kLCDTextVASize;
348 }
349}
350
joshualitt9853cce2014-11-17 14:22:48 -0800351static void* alloc_vertices(GrDrawTarget* drawTarget,
352 int numVertices,
353 GrMaskFormat maskFormat) {
jvanverth73f10532014-10-23 11:57:12 -0700354 if (numVertices <= 0) {
355 return NULL;
356 }
357
358 // set up attributes
jvanverth73f10532014-10-23 11:57:12 -0700359 void* vertices = NULL;
360 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
joshualitt9853cce2014-11-17 14:22:48 -0800361 get_vertex_stride(maskFormat),
jvanverth73f10532014-10-23 11:57:12 -0700362 0,
363 &vertices,
364 NULL);
365 GrAlwaysAssert(success);
366 return vertices;
367}
368
jvanverth787cdf92014-12-04 10:46:50 -0800369inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scaler) {
370 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
371 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
372 return true;
373 }
374
375 // try to clear out an unused plot before we flush
376 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
377 fStrike->addGlyphToAtlas(glyph, scaler)) {
378 return true;
379 }
380
381 if (c_DumpFontCache) {
382#ifdef SK_DEVELOPER
383 fContext->getFontCache()->dump();
384#endif
385 }
386
387 // before we purge the cache, we must flush any accumulated draws
388 this->flush();
389 fContext->flush();
390
391 // we should have an unused plot now
392 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
393 fStrike->addGlyphToAtlas(glyph, scaler)) {
394 return true;
395 }
396
397 // we should never get here
398 SkASSERT(false);
399 }
400
401 return false;
402}
403
jvanverth0fedb192014-10-08 09:07:27 -0700404void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
405 SkFixed vx, SkFixed vy,
406 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400407 if (NULL == fDrawTarget) {
408 return;
409 }
410
411 if (NULL == fStrike) {
412 fStrike = fContext->getFontCache()->getStrike(scaler, false);
413 }
414
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000415 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
416 if (NULL == glyph || glyph->fBounds.isEmpty()) {
417 return;
418 }
419
420 vx += SkIntToFixed(glyph->fBounds.fLeft);
421 vy += SkIntToFixed(glyph->fBounds.fTop);
422
423 // keep them as ints until we've done the clip-test
jvanverth5a105ff2015-02-18 11:36:35 -0800424 int width = glyph->fBounds.width();
425 int height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000426
427 // check if we clipped out
qiankun.miao06fb35f2015-01-29 18:36:52 -0800428 int x = vx >> 16;
429 int y = vy >> 16;
430 if (fClipRect.quickReject(x, y, x + width, y + height)) {
431 return;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000432 }
433
joshualittc2625822014-12-18 16:40:54 -0800434 // If the glyph is too large we fall back to paths
jvanverth787cdf92014-12-04 10:46:50 -0800435 if (NULL == glyph->fPlot && !uploadGlyph(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000436 if (NULL == glyph->fPath) {
437 SkPath* path = SkNEW(SkPath);
438 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
439 // flag the glyph as being dead?
440 delete path;
441 return;
442 }
443 glyph->fPath = path;
444 }
445
bsalomonec87dc62014-10-14 10:52:00 -0700446 // flush any accumulated draws before drawing this glyph as a path.
447 this->flush();
448
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000449 SkMatrix translate;
450 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
451 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
joshualittc2625822014-12-18 16:40:54 -0800452 SkPath tmpPath(*glyph->fPath);
453 tmpPath.transform(translate);
egdanield58a0ba2014-06-11 10:30:05 -0700454 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
joshualittc2625822014-12-18 16:40:54 -0800455 fContext->drawPath(fPaint, SkMatrix::I(), tmpPath, strokeInfo);
jvanverth73f10532014-10-23 11:57:12 -0700456
457 // remove this glyph from the vertices we need to allocate
458 fTotalVertexCount -= kVerticesPerGlyph;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000459 return;
460 }
461
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000462 SkASSERT(glyph->fPlot);
463 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
464 glyph->fPlot->setDrawToken(drawToken);
465
jvanverth294c3262014-10-10 11:36:12 -0700466 // the current texture/maskformat must match what the glyph needs
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000467 GrTexture* texture = glyph->fPlot->texture();
468 SkASSERT(texture);
469
jvanverth73f10532014-10-23 11:57:12 -0700470 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
jvanverth0fedb192014-10-08 09:07:27 -0700471 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400472 fCurrTexture = texture;
473 fCurrTexture->ref();
jvanverth294c3262014-10-10 11:36:12 -0700474 fCurrMaskFormat = glyph->fMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400475 }
476
Mike Klein6a25bd02014-08-29 10:03:59 -0400477 if (NULL == fVertices) {
jvanverth73f10532014-10-23 11:57:12 -0700478 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
479 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
egdanieled3af662014-10-31 06:55:45 -0700480 fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
Mike Klein6a25bd02014-08-29 10:03:59 -0400481 }
482
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000483 SkRect r;
484 r.fLeft = SkFixedToFloat(vx);
485 r.fTop = SkFixedToFloat(vy);
jvanverth5a105ff2015-02-18 11:36:35 -0800486 r.fRight = r.fLeft + width;
487 r.fBottom = r.fTop + height;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000488
reed10d03272014-10-01 09:24:12 -0700489 fVertexBounds.joinNonEmptyArg(r);
jvanverth5a105ff2015-02-18 11:36:35 -0800490
491 int u0 = glyph->fAtlasLocation.fX;
492 int v0 = glyph->fAtlasLocation.fY;
493 int u1 = u0 + width;
494 int v1 = v0 + height;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000495
joshualitt9853cce2014-11-17 14:22:48 -0800496 size_t vertSize = get_vertex_stride(fCurrMaskFormat);
jvanverth5a105ff2015-02-18 11:36:35 -0800497 intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex;
bsalomon594069f2014-06-06 06:16:34 -0700498
jvanverth5a105ff2015-02-18 11:36:35 -0800499 // V0
500 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
501 position->set(r.fLeft, r.fTop);
reede4ef1ca2015-02-17 18:38:38 -0800502 if (kA8_GrMaskFormat == fCurrMaskFormat) {
jvanverth5a105ff2015-02-18 11:36:35 -0800503 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
504 *color = fPaint.getColor();
reede4ef1ca2015-02-17 18:38:38 -0800505 }
jvanverth5a105ff2015-02-18 11:36:35 -0800506 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize -
507 sizeof(SkIPoint16));
508 textureCoords->set(u0, v0);
509 vertex += vertSize;
510
511 // V1
512 position = reinterpret_cast<SkPoint*>(vertex);
513 position->set(r.fLeft, r.fBottom);
514 if (kA8_GrMaskFormat == fCurrMaskFormat) {
515 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
516 *color = fPaint.getColor();
517 }
518 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16));
519 textureCoords->set(u0, v1);
520 vertex += vertSize;
521
522 // V2
523 position = reinterpret_cast<SkPoint*>(vertex);
524 position->set(r.fRight, r.fBottom);
525 if (kA8_GrMaskFormat == fCurrMaskFormat) {
526 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
527 *color = fPaint.getColor();
528 }
529 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16));
530 textureCoords->set(u1, v1);
531 vertex += vertSize;
532
533 // V3
534 position = reinterpret_cast<SkPoint*>(vertex);
535 position->set(r.fRight, r.fTop);
536 if (kA8_GrMaskFormat == fCurrMaskFormat) {
537 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
538 *color = fPaint.getColor();
539 }
540 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16));
541 textureCoords->set(u1, v0);
542
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000543 fCurrVertex += 4;
544}
jvanverth0fedb192014-10-08 09:07:27 -0700545
jvanverth0fedb192014-10-08 09:07:27 -0700546void GrBitmapTextContext::flush() {
547 if (NULL == fDrawTarget) {
548 return;
549 }
550
jvanverth0fedb192014-10-08 09:07:27 -0700551 if (fCurrVertex > 0) {
egdaniel8dd688b2015-01-22 10:16:09 -0800552 GrPipelineBuilder pipelineBuilder;
553 pipelineBuilder.setFromPaint(fPaint, fContext->getRenderTarget());
joshualitt780b11e2014-11-18 09:40:40 -0800554
jvanverth0fedb192014-10-08 09:07:27 -0700555 // setup our sampler state for our text texture/atlas
556 SkASSERT(SkIsAlign4(fCurrVertex));
557 SkASSERT(fCurrTexture);
jvanverth0fedb192014-10-08 09:07:27 -0700558
jvanverth0fedb192014-10-08 09:07:27 -0700559 SkASSERT(fStrike);
joshualitt2e3b3e32014-12-09 13:31:14 -0800560 GrColor color = fPaint.getColor();
jvanverth294c3262014-10-10 11:36:12 -0700561 switch (fCurrMaskFormat) {
jvanverth0fedb192014-10-08 09:07:27 -0700562 // Color bitmap text
joshualitt2e3b3e32014-12-09 13:31:14 -0800563 case kARGB_GrMaskFormat: {
564 int a = fSkPaint.getAlpha();
565 color = SkColorSetARGB(a, a, a, a);
jvanverth0fedb192014-10-08 09:07:27 -0700566 break;
joshualitt2e3b3e32014-12-09 13:31:14 -0800567 }
jvanverth0fedb192014-10-08 09:07:27 -0700568 // LCD text
jvanverth0fedb192014-10-08 09:07:27 -0700569 case kA565_GrMaskFormat: {
egdaniel378092f2014-12-03 10:40:13 -0800570 // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
571 // processor if the xp can support it. For now we will simply assume that if
572 // fUseLCDText is true, then we have a known color output.
egdaniel8dd688b2015-01-22 10:16:09 -0800573 const GrXPFactory* xpFactory = pipelineBuilder.getXPFactory();
574 if (!xpFactory->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
tfarina38406c82014-10-31 07:11:12 -0700575 SkDebugf("LCD Text will not draw correctly.\n");
jvanverth0fedb192014-10-08 09:07:27 -0700576 }
jvanverth0fedb192014-10-08 09:07:27 -0700577 break;
578 }
579 // Grayscale/BW text
580 case kA8_GrMaskFormat:
jvanverth0fedb192014-10-08 09:07:27 -0700581 break;
582 default:
jvanverth294c3262014-10-10 11:36:12 -0700583 SkFAIL("Unexpected mask format.");
jvanverth0fedb192014-10-08 09:07:27 -0700584 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800585
586 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
joshualitt02b05012015-02-11 06:56:30 -0800587 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
588 if (textureUniqueID != fEffectTextureUniqueID ||
589 fCachedGeometryProcessor->color() != color ||
590 !fCachedGeometryProcessor->localMatrix().cheapEqualTo(fLocalMatrix)) {
591 // This will be ignored in the non A8 case
592 bool opaqueVertexColors = GrColorIsOpaque(fPaint.getColor());
593 fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color,
594 fCurrTexture,
595 params,
596 fCurrMaskFormat,
597 opaqueVertexColors,
598 fLocalMatrix));
599 fEffectTextureUniqueID = textureUniqueID;
joshualitt2e3b3e32014-12-09 13:31:14 -0800600 }
601
jvanverth73f10532014-10-23 11:57:12 -0700602 int nGlyphs = fCurrVertex / kVerticesPerGlyph;
jvanverth0fedb192014-10-08 09:07:27 -0700603 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
egdaniel8dd688b2015-01-22 10:16:09 -0800604 fDrawTarget->drawIndexedInstances(&pipelineBuilder,
joshualitt56995b52014-12-11 15:44:02 -0800605 fCachedGeometryProcessor.get(),
joshualitt9853cce2014-11-17 14:22:48 -0800606 kTriangles_GrPrimitiveType,
jvanverth0fedb192014-10-08 09:07:27 -0700607 nGlyphs,
joshualitt9853cce2014-11-17 14:22:48 -0800608 kVerticesPerGlyph,
609 kIndicesPerGlyph,
610 &fVertexBounds);
jvanverth0fedb192014-10-08 09:07:27 -0700611
612 fDrawTarget->resetVertexSource();
613 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -0700614 fAllocVertexCount = 0;
615 // reset to be those that are left
616 fTotalVertexCount -= fCurrVertex;
jvanverth0fedb192014-10-08 09:07:27 -0700617 fCurrVertex = 0;
618 fVertexBounds.setLargestInverted();
619 SkSafeSetNull(fCurrTexture);
620 }
621}
622
623inline void GrBitmapTextContext::finish() {
624 this->flush();
jvanverth73f10532014-10-23 11:57:12 -0700625 fTotalVertexCount = 0;
jvanverth0fedb192014-10-08 09:07:27 -0700626
627 GrTextContext::finish();
628}
629