blob: 6599d4ea473a719b2edbe8459047b494e31d10f1 [file] [log] [blame]
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrBitmapTextContext.h"
9#include "GrAtlas.h"
10#include "GrDrawTarget.h"
11#include "GrFontScaler.h"
12#include "GrIndexBuffer.h"
egdanield58a0ba2014-06-11 10:30:05 -070013#include "GrStrokeInfo.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000014#include "GrTextStrike.h"
15#include "GrTextStrike_impl.h"
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000016#include "SkColorPriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000017#include "SkPath.h"
18#include "SkRTConf.h"
19#include "SkStrokeRec.h"
20#include "effects/GrCustomCoordsTextureEffect.h"
21
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000022#include "SkAutoKern.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000023#include "SkDraw.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070024#include "SkDrawProcs.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000025#include "SkGlyphCache.h"
26#include "SkGpuDevice.h"
27#include "SkGr.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070028#include "SkTextMapStateProc.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000029
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000030SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
31 "Dump the contents of the font cache before every purge.");
32
bsalomon594069f2014-06-06 06:16:34 -070033static const int kGlyphCoordsNoColorAttributeIndex = 1;
34static const int kGlyphCoordsWithColorAttributeIndex = 2;
35
36namespace {
37// position + texture coord
38extern const GrVertexAttrib gTextVertexAttribs[] = {
39 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
40 {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
41};
42
egdaniel7b3d5ee2014-08-28 05:41:14 -070043static const size_t kTextVASize = 2 * sizeof(SkPoint);
44
bsalomon594069f2014-06-06 06:16:34 -070045// position + color + texture coord
46extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
47 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
48 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
49 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
50};
51
egdaniel7b3d5ee2014-08-28 05:41:14 -070052static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
53
bsalomon594069f2014-06-06 06:16:34 -070054};
55
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000056GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000057 const SkDeviceProperties& properties)
Mike Klein6a25bd02014-08-29 10:03:59 -040058 : GrTextContext(context, properties) {
59 fStrike = NULL;
60
61 fCurrTexture = NULL;
62 fCurrVertex = 0;
63 fEffectTextureUniqueID = SK_InvalidUniqueID;
64
65 fVertices = NULL;
66 fMaxVertices = 0;
67
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000068 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000069}
70
71GrBitmapTextContext::~GrBitmapTextContext() {
72 this->flushGlyphs();
73}
74
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000075bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
76 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
77}
78
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000079static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
80 unsigned r = SkColorGetR(c);
81 unsigned g = SkColorGetG(c);
82 unsigned b = SkColorGetB(c);
83 return GrColorPackRGBA(r, g, b, 0xff);
84}
85
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000086void GrBitmapTextContext::flushGlyphs() {
87 if (NULL == fDrawTarget) {
88 return;
89 }
90
91 GrDrawState* drawState = fDrawTarget->drawState();
92 GrDrawState::AutoRestoreEffects are(drawState);
93 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
94
95 if (fCurrVertex > 0) {
96 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000097 SkASSERT(SkIsAlign4(fCurrVertex));
Mike Klein6a25bd02014-08-29 10:03:59 -040098 SkASSERT(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000099 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
100
Mike Klein6a25bd02014-08-29 10:03:59 -0400101 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
bsalomon8b2fac42014-06-19 14:13:45 -0700102
bsalomon1c63bf62014-07-22 13:09:46 -0700103 if (textureUniqueID != fEffectTextureUniqueID) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400104 fCachedEffect.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture, params));
bsalomon1c63bf62014-07-22 13:09:46 -0700105 fEffectTextureUniqueID = textureUniqueID;
bsalomon8b2fac42014-06-19 14:13:45 -0700106 }
107
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000108 // This effect could be stored with one of the cache objects (atlas?)
bsalomon594069f2014-06-06 06:16:34 -0700109 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
110 kGlyphCoordsNoColorAttributeIndex;
bsalomon8b2fac42014-06-19 14:13:45 -0700111 drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
bsalomon594069f2014-06-06 06:16:34 -0700112 SkASSERT(NULL != fStrike);
113 switch (fStrike->getMaskFormat()) {
114 // Color bitmap text
115 case kARGB_GrMaskFormat:
116 SkASSERT(!drawState->hasColorVertexAttribute());
117 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
118 drawState->setColor(0xffffffff);
119 break;
120 // LCD text
121 case kA888_GrMaskFormat:
122 case kA565_GrMaskFormat: {
123 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
124 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
125 fPaint.numColorStages()) {
126 GrPrintf("LCD Text will not draw correctly.\n");
127 }
128 SkASSERT(!drawState->hasColorVertexAttribute());
129 // We don't use the GrPaint's color in this case because it's been premultiplied by
130 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
131 // the mask texture color. The end result is that we get
132 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
133 int a = SkColorGetA(fSkPaint.getColor());
134 // paintAlpha
135 drawState->setColor(SkColorSetARGB(a, a, a, a));
136 // paintColor
137 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
138 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
139 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000140 }
bsalomon594069f2014-06-06 06:16:34 -0700141 // Grayscale/BW text
142 case kA8_GrMaskFormat:
143 // set back to normal in case we took LCD path previously.
144 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
bsalomon594069f2014-06-06 06:16:34 -0700145 // We're using per-vertex color.
146 SkASSERT(drawState->hasColorVertexAttribute());
bsalomon594069f2014-06-06 06:16:34 -0700147 break;
148 default:
149 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000150 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000151 int nGlyphs = fCurrVertex / 4;
152 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
153 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
154 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000155 4, 6, &fVertexBounds);
Mike Klein6a25bd02014-08-29 10:03:59 -0400156
157 fDrawTarget->resetVertexSource();
158 fVertices = NULL;
159 fMaxVertices = 0;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000160 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000161 fVertexBounds.setLargestInverted();
Mike Klein6a25bd02014-08-29 10:03:59 -0400162 SkSafeSetNull(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000163 }
164}
165
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000166inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
167 GrTextContext::init(paint, skPaint);
168
169 fStrike = NULL;
170
Mike Klein6a25bd02014-08-29 10:03:59 -0400171 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -0700172 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -0400173
174 fVertices = NULL;
175 fMaxVertices = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000176}
177
178inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700179 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000180
181 GrTextContext::finish();
182}
183
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000184void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000185 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000186 SkScalar x, SkScalar y) {
187 SkASSERT(byteLength == 0 || text != NULL);
188
189 // nothing to draw
190 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
191 return;
192 }
193
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000194 this->init(paint, skPaint);
195
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000196 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
197
198 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
199 SkGlyphCache* cache = autoCache.getCache();
200 GrFontScaler* fontScaler = GetGrFontScaler(cache);
Mike Klein6a25bd02014-08-29 10:03:59 -0400201
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000202 // transform our starting point
203 {
204 SkPoint loc;
205 fContext->getMatrix().mapXY(x, y, &loc);
206 x = loc.fX;
207 y = loc.fY;
208 }
209
210 // need to measure first
211 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
212 SkVector stop;
213
214 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
215
216 SkScalar stopX = stop.fX;
217 SkScalar stopY = stop.fY;
218
219 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
220 stopX = SkScalarHalf(stopX);
221 stopY = SkScalarHalf(stopY);
222 }
223 x -= stopX;
224 y -= stopY;
225 }
226
227 const char* stop = text + byteLength;
228
Mike Klein6a25bd02014-08-29 10:03:59 -0400229 SkAutoKern autokern;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000230
231 SkFixed fxMask = ~0;
232 SkFixed fyMask = ~0;
233 SkFixed halfSampleX, halfSampleY;
234 if (cache->isSubpixel()) {
235 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
236 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
237 if (kX_SkAxisAlignment == baseline) {
238 fyMask = 0;
239 halfSampleY = SK_FixedHalf;
240 } else if (kY_SkAxisAlignment == baseline) {
241 fxMask = 0;
242 halfSampleX = SK_FixedHalf;
243 }
244 } else {
245 halfSampleX = halfSampleY = SK_FixedHalf;
246 }
247
248 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
249 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000250
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000251 GrContext::AutoMatrix autoMatrix;
252 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000253
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000254 while (text < stop) {
255 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
256
257 fx += autokern.adjust(glyph);
258
259 if (glyph.fWidth) {
260 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
261 glyph.getSubXFixed(),
262 glyph.getSubYFixed()),
263 SkFixedFloorToFixed(fx),
264 SkFixedFloorToFixed(fy),
265 fontScaler);
266 }
267
268 fx += glyph.fAdvanceX;
269 fy += glyph.fAdvanceY;
270 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000271
272 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000273}
274
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000275void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000276 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000277 const SkScalar pos[], SkScalar constY,
278 int scalarsPerPosition) {
279 SkASSERT(byteLength == 0 || text != NULL);
280 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
281
282 // nothing to draw
283 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
284 return;
285 }
286
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000287 this->init(paint, skPaint);
288
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000289 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
290
291 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
292 SkGlyphCache* cache = autoCache.getCache();
293 GrFontScaler* fontScaler = GetGrFontScaler(cache);
294
295 // store original matrix before we reset, so we can use it to transform positions
296 SkMatrix ctm = fContext->getMatrix();
297 GrContext::AutoMatrix autoMatrix;
298 autoMatrix.setIdentity(fContext, &fPaint);
299
300 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700301 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
302 SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000303 SkFixed halfSampleX = 0, halfSampleY = 0;
304
305 if (cache->isSubpixel()) {
306 // maybe we should skip the rounding if linearText is set
307 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
308
309 SkFixed fxMask = ~0;
310 SkFixed fyMask = ~0;
311 if (kX_SkAxisAlignment == baseline) {
312 fyMask = 0;
313#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
314 halfSampleY = SK_FixedHalf;
315#endif
316 } else if (kY_SkAxisAlignment == baseline) {
317 fxMask = 0;
318#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
319 halfSampleX = SK_FixedHalf;
320#endif
321 }
322
323 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
324 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700325 SkPoint tmsLoc;
326 tmsProc(pos, &tmsLoc);
327 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
328 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000329
330 const SkGlyph& glyph = glyphCacheProc(cache, &text,
331 fx & fxMask, fy & fyMask);
332
333 if (glyph.fWidth) {
334 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
335 glyph.getSubXFixed(),
336 glyph.getSubYFixed()),
337 SkFixedFloorToFixed(fx),
338 SkFixedFloorToFixed(fy),
339 fontScaler);
340 }
341 pos += scalarsPerPosition;
342 }
343 } else {
344 while (text < stop) {
345 const char* currentText = text;
346 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
347
348 if (metricGlyph.fWidth) {
349 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
350 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700351 SkPoint tmsLoc;
352 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000353 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700354 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000355
356 SkFixed fx = fixedLoc.fX + halfSampleX;
357 SkFixed fy = fixedLoc.fY + halfSampleY;
358
359 // have to call again, now that we've been "aligned"
360 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
361 fx & fxMask, fy & fyMask);
362 // the assumption is that the metrics haven't changed
363 SkASSERT(prevAdvX == glyph.fAdvanceX);
364 SkASSERT(prevAdvY == glyph.fAdvanceY);
365 SkASSERT(glyph.fWidth);
366
367 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
368 glyph.getSubXFixed(),
369 glyph.getSubYFixed()),
370 SkFixedFloorToFixed(fx),
371 SkFixedFloorToFixed(fy),
372 fontScaler);
373 }
374 pos += scalarsPerPosition;
375 }
376 }
377 } else { // not subpixel
378
379 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
380 while (text < stop) {
381 // the last 2 parameters are ignored
382 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
383
384 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700385 SkPoint tmsLoc;
386 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000387
kkinnunencb9a2c82014-06-12 23:06:28 -0700388 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
389 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000390 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
391 glyph.getSubXFixed(),
392 glyph.getSubYFixed()),
393 SkFixedFloorToFixed(fx),
394 SkFixedFloorToFixed(fy),
395 fontScaler);
396 }
397 pos += scalarsPerPosition;
398 }
399 } else {
400 while (text < stop) {
401 // the last 2 parameters are ignored
402 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
403
404 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700405 SkPoint tmsLoc;
406 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000407
408 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700409 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000410
411 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
412 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
413 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
414 glyph.getSubXFixed(),
415 glyph.getSubYFixed()),
416 SkFixedFloorToFixed(fx),
417 SkFixedFloorToFixed(fy),
418 fontScaler);
419 }
420 pos += scalarsPerPosition;
421 }
422 }
423 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000424
425 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000426}
427
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000428void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000429 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000430 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400431 if (NULL == fDrawTarget) {
432 return;
433 }
434
435 if (NULL == fStrike) {
436 fStrike = fContext->getFontCache()->getStrike(scaler, false);
437 }
438
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000439 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
440 if (NULL == glyph || glyph->fBounds.isEmpty()) {
441 return;
442 }
443
444 vx += SkIntToFixed(glyph->fBounds.fLeft);
445 vy += SkIntToFixed(glyph->fBounds.fTop);
446
447 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000448 SkFixed width = glyph->fBounds.width();
449 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000450
451 // check if we clipped out
452 if (true || NULL == glyph->fPlot) {
453 int x = vx >> 16;
454 int y = vy >> 16;
455 if (fClipRect.quickReject(x, y, x + width, y + height)) {
456// SkCLZ(3); // so we can set a break-point in the debugger
457 return;
458 }
459 }
460
461 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000462 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000463 goto HAS_ATLAS;
464 }
465
466 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000467 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
468 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000469 goto HAS_ATLAS;
470 }
471
472 if (c_DumpFontCache) {
473#ifdef SK_DEVELOPER
474 fContext->getFontCache()->dump();
475#endif
476 }
477
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000478 // flush any accumulated draws to allow us to free up a plot
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000479 this->flushGlyphs();
480 fContext->flush();
481
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000482 // we should have an unused plot now
483 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
484 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000485 goto HAS_ATLAS;
486 }
487
488 if (NULL == glyph->fPath) {
489 SkPath* path = SkNEW(SkPath);
490 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
491 // flag the glyph as being dead?
492 delete path;
493 return;
494 }
495 glyph->fPath = path;
496 }
497
498 GrContext::AutoMatrix am;
499 SkMatrix translate;
500 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
501 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
502 GrPaint tmpPaint(fPaint);
503 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700504 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
505 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000506 return;
507 }
508
509HAS_ATLAS:
510 SkASSERT(glyph->fPlot);
511 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
512 glyph->fPlot->setDrawToken(drawToken);
513
514 // now promote them to fixed (TODO: Rethink using fixed pt).
515 width = SkIntToFixed(width);
516 height = SkIntToFixed(height);
517
518 GrTexture* texture = glyph->fPlot->texture();
519 SkASSERT(texture);
520
Mike Klein6a25bd02014-08-29 10:03:59 -0400521 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
522 this->flushGlyphs();
523 fCurrTexture = texture;
524 fCurrTexture->ref();
525 }
526
527 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
528
529 if (NULL == fVertices) {
530 // If we need to reserve vertices allow the draw target to suggest
531 // a number of verts to reserve and whether to perform a flush.
532 fMaxVertices = kMinRequestedVerts;
533 if (useColorVerts) {
534 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
535 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
536 } else {
537 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
538 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
539 }
540 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
541 if (flush) {
542 this->flushGlyphs();
543 fContext->flush();
544 if (useColorVerts) {
545 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
546 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
547 } else {
548 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
549 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
550 }
551 }
552 fMaxVertices = kDefaultRequestedVerts;
553 // ignore return, no point in flushing again.
554 fDrawTarget->geometryHints(&fMaxVertices, NULL);
555
556 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
557 if (fMaxVertices < kMinRequestedVerts) {
558 fMaxVertices = kDefaultRequestedVerts;
559 } else if (fMaxVertices > maxQuadVertices) {
560 // don't exceed the limit of the index buffer
561 fMaxVertices = maxQuadVertices;
562 }
563 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
564 0,
565 &fVertices,
566 NULL);
567 GrAlwaysAssert(success);
568 }
569
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000570 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
571 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000572
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000573 SkRect r;
574 r.fLeft = SkFixedToFloat(vx);
575 r.fTop = SkFixedToFloat(vy);
576 r.fRight = SkFixedToFloat(vx + width);
577 r.fBottom = SkFixedToFloat(vy + height);
578
579 fVertexBounds.growToInclude(r);
580
bsalomon594069f2014-06-06 06:16:34 -0700581 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
582 (2 * sizeof(SkPoint));
583
egdaniel7b3d5ee2014-08-28 05:41:14 -0700584 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
bsalomon594069f2014-06-06 06:16:34 -0700585
586 SkPoint* positions = reinterpret_cast<SkPoint*>(
587 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
588 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
589
590 // The texture coords are last in both the with and without color vertex layouts.
591 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
592 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
593 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
594 SkFixedToFloat(texture->normalizeFixedY(ty)),
595 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
596 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
597 vertSize);
598 if (useColorVerts) {
bsalomon62c447d2014-08-08 08:08:50 -0700599 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
600 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
601 }
bsalomon594069f2014-06-06 06:16:34 -0700602 // color comes after position.
603 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
604 for (int i = 0; i < 4; ++i) {
605 *colors = fPaint.getColor();
606 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
607 }
608 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000609 fCurrVertex += 4;
610}