blob: d06df1c16bcce17ee33f8462e9512b2a2aef8b6e [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
joshualitt570d2f82015-02-25 13:19:48 -080073inline void GrBitmapTextContext::init(GrRenderTarget* rt, const GrClip& clip,
74 const GrPaint& paint, const SkPaint& skPaint) {
75 GrTextContext::init(rt, clip, paint, skPaint);
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000076
77 fStrike = NULL;
78
Mike Klein6a25bd02014-08-29 10:03:59 -040079 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -070080 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -040081
82 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -070083 fAllocVertexCount = 0;
84 fTotalVertexCount = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000085}
86
joshualitt570d2f82015-02-25 13:19:48 -080087void GrBitmapTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
88 const GrPaint& paint, const SkPaint& skPaint,
joshualitt5531d512014-12-17 15:50:11 -080089 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -080090 const char text[], size_t byteLength,
91 SkScalar x, SkScalar y) {
jvanverthaab626c2014-10-16 08:04:39 -070092 SkASSERT(byteLength == 0 || text != NULL);
93
94 // nothing to draw
95 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
96 return;
97 }
98
joshualitt570d2f82015-02-25 13:19:48 -080099 this->init(rt, clip, paint, skPaint);
jvanverthaab626c2014-10-16 08:04:39 -0700100
101 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
102
joshualitt5531d512014-12-17 15:50:11 -0800103 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix);
jvanverthaab626c2014-10-16 08:04:39 -0700104 SkGlyphCache* cache = autoCache.getCache();
105 GrFontScaler* fontScaler = GetGrFontScaler(cache);
106
107 // transform our starting point
108 {
109 SkPoint loc;
joshualitt5531d512014-12-17 15:50:11 -0800110 viewMatrix.mapXY(x, y, &loc);
jvanverthaab626c2014-10-16 08:04:39 -0700111 x = loc.fX;
112 y = loc.fY;
113 }
114
115 // need to measure first
jvanverth73f10532014-10-23 11:57:12 -0700116 int numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700117 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
jvanverth73f10532014-10-23 11:57:12 -0700118 SkVector stopVector;
119 numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
jvanverthaab626c2014-10-16 08:04:39 -0700120
jvanverth73f10532014-10-23 11:57:12 -0700121 SkScalar stopX = stopVector.fX;
122 SkScalar stopY = stopVector.fY;
jvanverthaab626c2014-10-16 08:04:39 -0700123
124 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
125 stopX = SkScalarHalf(stopX);
126 stopY = SkScalarHalf(stopY);
127 }
128 x -= stopX;
129 y -= stopY;
jvanverth73f10532014-10-23 11:57:12 -0700130 } else {
131 numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
jvanverthaab626c2014-10-16 08:04:39 -0700132 }
jvanverth73f10532014-10-23 11:57:12 -0700133 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700134
135 const char* stop = text + byteLength;
136
137 SkAutoKern autokern;
138
139 SkFixed fxMask = ~0;
140 SkFixed fyMask = ~0;
141 SkFixed halfSampleX, halfSampleY;
142 if (cache->isSubpixel()) {
herbb69d0e02015-02-25 06:47:06 -0800143 halfSampleX = halfSampleY = SkGlyph::kSubpixelRound;
joshualitt5531d512014-12-17 15:50:11 -0800144 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
jvanverthaab626c2014-10-16 08:04:39 -0700145 if (kX_SkAxisAlignment == baseline) {
146 fyMask = 0;
147 halfSampleY = SK_FixedHalf;
148 } else if (kY_SkAxisAlignment == baseline) {
149 fxMask = 0;
150 halfSampleX = SK_FixedHalf;
151 }
152 } else {
153 halfSampleX = halfSampleY = SK_FixedHalf;
154 }
155
156 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
157 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
158
joshualitt73483d92014-12-23 07:58:02 -0800159 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for
160 // performance reasons we just invert here instead
161 if (!viewMatrix.invert(&fLocalMatrix)) {
joshualitt787bb482015-01-02 10:54:26 -0800162 SkDebugf("Cannot invert viewmatrix\n");
163 return;
joshualitt5531d512014-12-17 15:50:11 -0800164 }
jvanverthaab626c2014-10-16 08:04:39 -0700165
166 while (text < stop) {
167 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
168
169 fx += autokern.adjust(glyph);
170
171 if (glyph.fWidth) {
172 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
173 glyph.getSubXFixed(),
174 glyph.getSubYFixed()),
175 SkFixedFloorToFixed(fx),
176 SkFixedFloorToFixed(fy),
177 fontScaler);
178 }
179
180 fx += glyph.fAdvanceX;
181 fy += glyph.fAdvanceY;
182 }
183
184 this->finish();
185}
186
joshualitt570d2f82015-02-25 13:19:48 -0800187void GrBitmapTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
188 const GrPaint& paint, const SkPaint& skPaint,
joshualitt5531d512014-12-17 15:50:11 -0800189 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800190 const char text[], size_t byteLength,
191 const SkScalar pos[], int scalarsPerPosition,
192 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000193 SkASSERT(byteLength == 0 || text != NULL);
194 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
195
196 // nothing to draw
197 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
198 return;
199 }
200
joshualitt570d2f82015-02-25 13:19:48 -0800201 this->init(rt, clip, paint, skPaint);
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000202
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000203 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
204
joshualitt5531d512014-12-17 15:50:11 -0800205 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000206 SkGlyphCache* cache = autoCache.getCache();
207 GrFontScaler* fontScaler = GetGrFontScaler(cache);
208
joshualitt73483d92014-12-23 07:58:02 -0800209 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for
210 // performance reasons we just invert here instead
211 if (!viewMatrix.invert(&fLocalMatrix)) {
joshualitt787bb482015-01-02 10:54:26 -0800212 SkDebugf("Cannot invert viewmatrix\n");
213 return;
joshualitt5531d512014-12-17 15:50:11 -0800214 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000215
jvanverth73f10532014-10-23 11:57:12 -0700216 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
217 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
218
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000219 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700220 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
joshualitt73483d92014-12-23 07:58:02 -0800221 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000222 SkFixed halfSampleX = 0, halfSampleY = 0;
223
224 if (cache->isSubpixel()) {
225 // maybe we should skip the rounding if linearText is set
joshualitt73483d92014-12-23 07:58:02 -0800226 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000227
228 SkFixed fxMask = ~0;
229 SkFixed fyMask = ~0;
230 if (kX_SkAxisAlignment == baseline) {
231 fyMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000232 halfSampleY = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000233 } else if (kY_SkAxisAlignment == baseline) {
234 fxMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000235 halfSampleX = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000236 }
237
238 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
239 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700240 SkPoint tmsLoc;
241 tmsProc(pos, &tmsLoc);
242 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
243 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000244
245 const SkGlyph& glyph = glyphCacheProc(cache, &text,
246 fx & fxMask, fy & fyMask);
247
248 if (glyph.fWidth) {
jvanverth0fedb192014-10-08 09:07:27 -0700249 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
250 glyph.getSubXFixed(),
251 glyph.getSubYFixed()),
252 SkFixedFloorToFixed(fx),
253 SkFixedFloorToFixed(fy),
254 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000255 }
256 pos += scalarsPerPosition;
257 }
258 } else {
259 while (text < stop) {
260 const char* currentText = text;
261 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
262
263 if (metricGlyph.fWidth) {
264 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
265 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700266 SkPoint tmsLoc;
267 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000268 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700269 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000270
271 SkFixed fx = fixedLoc.fX + halfSampleX;
272 SkFixed fy = fixedLoc.fY + halfSampleY;
273
274 // have to call again, now that we've been "aligned"
275 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
276 fx & fxMask, fy & fyMask);
277 // the assumption is that the metrics haven't changed
278 SkASSERT(prevAdvX == glyph.fAdvanceX);
279 SkASSERT(prevAdvY == glyph.fAdvanceY);
280 SkASSERT(glyph.fWidth);
281
jvanverth0fedb192014-10-08 09:07:27 -0700282 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
283 glyph.getSubXFixed(),
284 glyph.getSubYFixed()),
285 SkFixedFloorToFixed(fx),
286 SkFixedFloorToFixed(fy),
287 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000288 }
289 pos += scalarsPerPosition;
290 }
291 }
292 } else { // not subpixel
293
294 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
295 while (text < stop) {
296 // the last 2 parameters are ignored
297 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
298
299 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700300 SkPoint tmsLoc;
301 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000302
kkinnunencb9a2c82014-06-12 23:06:28 -0700303 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
304 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700305 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
306 glyph.getSubXFixed(),
307 glyph.getSubYFixed()),
308 SkFixedFloorToFixed(fx),
309 SkFixedFloorToFixed(fy),
310 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000311 }
312 pos += scalarsPerPosition;
313 }
314 } else {
315 while (text < stop) {
316 // the last 2 parameters are ignored
317 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
318
319 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700320 SkPoint tmsLoc;
321 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000322
323 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700324 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000325
326 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
327 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700328 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
329 glyph.getSubXFixed(),
330 glyph.getSubYFixed()),
331 SkFixedFloorToFixed(fx),
332 SkFixedFloorToFixed(fy),
333 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000334 }
335 pos += scalarsPerPosition;
336 }
337 }
338 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000339
340 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000341}
342
joshualitt9853cce2014-11-17 14:22:48 -0800343static size_t get_vertex_stride(GrMaskFormat maskFormat) {
344 switch (maskFormat) {
345 case kA8_GrMaskFormat:
346 return kGrayTextVASize;
347 case kARGB_GrMaskFormat:
348 return kColorTextVASize;
349 default:
350 return kLCDTextVASize;
351 }
352}
353
joshualitt9853cce2014-11-17 14:22:48 -0800354static void* alloc_vertices(GrDrawTarget* drawTarget,
355 int numVertices,
356 GrMaskFormat maskFormat) {
jvanverth73f10532014-10-23 11:57:12 -0700357 if (numVertices <= 0) {
358 return NULL;
359 }
360
361 // set up attributes
jvanverth73f10532014-10-23 11:57:12 -0700362 void* vertices = NULL;
363 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
joshualitt9853cce2014-11-17 14:22:48 -0800364 get_vertex_stride(maskFormat),
jvanverth73f10532014-10-23 11:57:12 -0700365 0,
366 &vertices,
367 NULL);
368 GrAlwaysAssert(success);
369 return vertices;
370}
371
jvanverth787cdf92014-12-04 10:46:50 -0800372inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scaler) {
373 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
374 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
375 return true;
376 }
377
378 // try to clear out an unused plot before we flush
379 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
380 fStrike->addGlyphToAtlas(glyph, scaler)) {
381 return true;
382 }
383
384 if (c_DumpFontCache) {
385#ifdef SK_DEVELOPER
386 fContext->getFontCache()->dump();
387#endif
388 }
389
390 // before we purge the cache, we must flush any accumulated draws
391 this->flush();
392 fContext->flush();
393
394 // we should have an unused plot now
395 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
396 fStrike->addGlyphToAtlas(glyph, scaler)) {
397 return true;
398 }
399
400 // we should never get here
401 SkASSERT(false);
402 }
403
404 return false;
405}
406
jvanverth0fedb192014-10-08 09:07:27 -0700407void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
408 SkFixed vx, SkFixed vy,
409 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400410 if (NULL == fDrawTarget) {
411 return;
412 }
413
414 if (NULL == fStrike) {
415 fStrike = fContext->getFontCache()->getStrike(scaler, false);
416 }
417
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000418 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
419 if (NULL == glyph || glyph->fBounds.isEmpty()) {
420 return;
421 }
422
423 vx += SkIntToFixed(glyph->fBounds.fLeft);
424 vy += SkIntToFixed(glyph->fBounds.fTop);
425
426 // keep them as ints until we've done the clip-test
jvanverth5a105ff2015-02-18 11:36:35 -0800427 int width = glyph->fBounds.width();
428 int height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000429
430 // check if we clipped out
qiankun.miao06fb35f2015-01-29 18:36:52 -0800431 int x = vx >> 16;
432 int y = vy >> 16;
433 if (fClipRect.quickReject(x, y, x + width, y + height)) {
434 return;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000435 }
436
joshualittc2625822014-12-18 16:40:54 -0800437 // If the glyph is too large we fall back to paths
jvanverth787cdf92014-12-04 10:46:50 -0800438 if (NULL == glyph->fPlot && !uploadGlyph(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000439 if (NULL == glyph->fPath) {
440 SkPath* path = SkNEW(SkPath);
441 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
442 // flag the glyph as being dead?
443 delete path;
444 return;
445 }
446 glyph->fPath = path;
447 }
448
bsalomonec87dc62014-10-14 10:52:00 -0700449 // flush any accumulated draws before drawing this glyph as a path.
450 this->flush();
451
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000452 SkMatrix translate;
453 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
454 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
joshualittc2625822014-12-18 16:40:54 -0800455 SkPath tmpPath(*glyph->fPath);
456 tmpPath.transform(translate);
egdanield58a0ba2014-06-11 10:30:05 -0700457 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
joshualitt570d2f82015-02-25 13:19:48 -0800458 fContext->drawPath(fRenderTarget, fClip, fPaint, SkMatrix::I(), tmpPath, strokeInfo);
jvanverth73f10532014-10-23 11:57:12 -0700459
460 // remove this glyph from the vertices we need to allocate
461 fTotalVertexCount -= kVerticesPerGlyph;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000462 return;
463 }
464
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000465 SkASSERT(glyph->fPlot);
466 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
467 glyph->fPlot->setDrawToken(drawToken);
468
jvanverth294c3262014-10-10 11:36:12 -0700469 // the current texture/maskformat must match what the glyph needs
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000470 GrTexture* texture = glyph->fPlot->texture();
471 SkASSERT(texture);
472
jvanverth73f10532014-10-23 11:57:12 -0700473 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
jvanverth0fedb192014-10-08 09:07:27 -0700474 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400475 fCurrTexture = texture;
476 fCurrTexture->ref();
jvanverth294c3262014-10-10 11:36:12 -0700477 fCurrMaskFormat = glyph->fMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400478 }
479
Mike Klein6a25bd02014-08-29 10:03:59 -0400480 if (NULL == fVertices) {
jvanverth73f10532014-10-23 11:57:12 -0700481 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
482 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
egdanieled3af662014-10-31 06:55:45 -0700483 fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
Mike Klein6a25bd02014-08-29 10:03:59 -0400484 }
485
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000486 SkRect r;
487 r.fLeft = SkFixedToFloat(vx);
488 r.fTop = SkFixedToFloat(vy);
jvanverth5a105ff2015-02-18 11:36:35 -0800489 r.fRight = r.fLeft + width;
490 r.fBottom = r.fTop + height;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000491
reed10d03272014-10-01 09:24:12 -0700492 fVertexBounds.joinNonEmptyArg(r);
jvanverth5a105ff2015-02-18 11:36:35 -0800493
494 int u0 = glyph->fAtlasLocation.fX;
495 int v0 = glyph->fAtlasLocation.fY;
496 int u1 = u0 + width;
497 int v1 = v0 + height;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000498
joshualitt9853cce2014-11-17 14:22:48 -0800499 size_t vertSize = get_vertex_stride(fCurrMaskFormat);
jvanverth5a105ff2015-02-18 11:36:35 -0800500 intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex;
bsalomon594069f2014-06-06 06:16:34 -0700501
jvanverth5a105ff2015-02-18 11:36:35 -0800502 // V0
503 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
504 position->set(r.fLeft, r.fTop);
reede4ef1ca2015-02-17 18:38:38 -0800505 if (kA8_GrMaskFormat == fCurrMaskFormat) {
jvanverth5a105ff2015-02-18 11:36:35 -0800506 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
507 *color = fPaint.getColor();
reede4ef1ca2015-02-17 18:38:38 -0800508 }
jvanverth5a105ff2015-02-18 11:36:35 -0800509 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize -
510 sizeof(SkIPoint16));
511 textureCoords->set(u0, v0);
512 vertex += vertSize;
513
514 // V1
515 position = reinterpret_cast<SkPoint*>(vertex);
516 position->set(r.fLeft, r.fBottom);
517 if (kA8_GrMaskFormat == fCurrMaskFormat) {
518 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
519 *color = fPaint.getColor();
520 }
521 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16));
522 textureCoords->set(u0, v1);
523 vertex += vertSize;
524
525 // V2
526 position = reinterpret_cast<SkPoint*>(vertex);
527 position->set(r.fRight, r.fBottom);
528 if (kA8_GrMaskFormat == fCurrMaskFormat) {
529 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
530 *color = fPaint.getColor();
531 }
532 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16));
533 textureCoords->set(u1, v1);
534 vertex += vertSize;
535
536 // V3
537 position = reinterpret_cast<SkPoint*>(vertex);
538 position->set(r.fRight, r.fTop);
539 if (kA8_GrMaskFormat == fCurrMaskFormat) {
540 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
541 *color = fPaint.getColor();
542 }
543 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16));
544 textureCoords->set(u1, v0);
545
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000546 fCurrVertex += 4;
547}
jvanverth0fedb192014-10-08 09:07:27 -0700548
jvanverth0fedb192014-10-08 09:07:27 -0700549void GrBitmapTextContext::flush() {
550 if (NULL == fDrawTarget) {
551 return;
552 }
553
jvanverth0fedb192014-10-08 09:07:27 -0700554 if (fCurrVertex > 0) {
egdaniel8dd688b2015-01-22 10:16:09 -0800555 GrPipelineBuilder pipelineBuilder;
joshualitt44701df2015-02-23 14:44:57 -0800556 pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip);
joshualitt780b11e2014-11-18 09:40:40 -0800557
jvanverth0fedb192014-10-08 09:07:27 -0700558 // setup our sampler state for our text texture/atlas
559 SkASSERT(SkIsAlign4(fCurrVertex));
560 SkASSERT(fCurrTexture);
jvanverth0fedb192014-10-08 09:07:27 -0700561
jvanverth0fedb192014-10-08 09:07:27 -0700562 SkASSERT(fStrike);
joshualitt2e3b3e32014-12-09 13:31:14 -0800563 GrColor color = fPaint.getColor();
jvanverth294c3262014-10-10 11:36:12 -0700564 switch (fCurrMaskFormat) {
jvanverth0fedb192014-10-08 09:07:27 -0700565 // Color bitmap text
joshualitt2e3b3e32014-12-09 13:31:14 -0800566 case kARGB_GrMaskFormat: {
567 int a = fSkPaint.getAlpha();
568 color = SkColorSetARGB(a, a, a, a);
jvanverth0fedb192014-10-08 09:07:27 -0700569 break;
joshualitt2e3b3e32014-12-09 13:31:14 -0800570 }
jvanverth0fedb192014-10-08 09:07:27 -0700571 // LCD text
jvanverth0fedb192014-10-08 09:07:27 -0700572 case kA565_GrMaskFormat: {
egdaniel378092f2014-12-03 10:40:13 -0800573 // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
574 // processor if the xp can support it. For now we will simply assume that if
575 // fUseLCDText is true, then we have a known color output.
egdaniel8dd688b2015-01-22 10:16:09 -0800576 const GrXPFactory* xpFactory = pipelineBuilder.getXPFactory();
577 if (!xpFactory->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
tfarina38406c82014-10-31 07:11:12 -0700578 SkDebugf("LCD Text will not draw correctly.\n");
jvanverth0fedb192014-10-08 09:07:27 -0700579 }
jvanverth0fedb192014-10-08 09:07:27 -0700580 break;
581 }
582 // Grayscale/BW text
583 case kA8_GrMaskFormat:
jvanverth0fedb192014-10-08 09:07:27 -0700584 break;
585 default:
jvanverth294c3262014-10-10 11:36:12 -0700586 SkFAIL("Unexpected mask format.");
jvanverth0fedb192014-10-08 09:07:27 -0700587 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800588
589 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
joshualitt02b05012015-02-11 06:56:30 -0800590 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
591 if (textureUniqueID != fEffectTextureUniqueID ||
592 fCachedGeometryProcessor->color() != color ||
593 !fCachedGeometryProcessor->localMatrix().cheapEqualTo(fLocalMatrix)) {
594 // This will be ignored in the non A8 case
595 bool opaqueVertexColors = GrColorIsOpaque(fPaint.getColor());
596 fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color,
597 fCurrTexture,
598 params,
599 fCurrMaskFormat,
600 opaqueVertexColors,
601 fLocalMatrix));
602 fEffectTextureUniqueID = textureUniqueID;
joshualitt2e3b3e32014-12-09 13:31:14 -0800603 }
604
jvanverth73f10532014-10-23 11:57:12 -0700605 int nGlyphs = fCurrVertex / kVerticesPerGlyph;
jvanverth0fedb192014-10-08 09:07:27 -0700606 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
egdaniel8dd688b2015-01-22 10:16:09 -0800607 fDrawTarget->drawIndexedInstances(&pipelineBuilder,
joshualitt56995b52014-12-11 15:44:02 -0800608 fCachedGeometryProcessor.get(),
joshualitt9853cce2014-11-17 14:22:48 -0800609 kTriangles_GrPrimitiveType,
jvanverth0fedb192014-10-08 09:07:27 -0700610 nGlyphs,
joshualitt9853cce2014-11-17 14:22:48 -0800611 kVerticesPerGlyph,
612 kIndicesPerGlyph,
613 &fVertexBounds);
jvanverth0fedb192014-10-08 09:07:27 -0700614
615 fDrawTarget->resetVertexSource();
616 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -0700617 fAllocVertexCount = 0;
618 // reset to be those that are left
619 fTotalVertexCount -= fCurrVertex;
jvanverth0fedb192014-10-08 09:07:27 -0700620 fCurrVertex = 0;
621 fVertexBounds.setLargestInverted();
622 SkSafeSetNull(fCurrTexture);
623 }
624}
625
626inline void GrBitmapTextContext::finish() {
627 this->flush();
jvanverth73f10532014-10-23 11:57:12 -0700628 fTotalVertexCount = 0;
jvanverth0fedb192014-10-08 09:07:27 -0700629
630 GrTextContext::finish();
631}
632