blob: 421051752615c4f32f89281262bff40b69b69777 [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 -070033namespace {
34// position + texture coord
35extern const GrVertexAttrib gTextVertexAttribs[] = {
36 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
37 {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
38};
39
egdaniel7b3d5ee2014-08-28 05:41:14 -070040static const size_t kTextVASize = 2 * sizeof(SkPoint);
41
bsalomon594069f2014-06-06 06:16:34 -070042// position + color + texture coord
43extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
44 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
45 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
46 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
47};
48
egdaniel7b3d5ee2014-08-28 05:41:14 -070049static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
50
bsalomon594069f2014-06-06 06:16:34 -070051};
52
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000053GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000054 const SkDeviceProperties& properties)
Mike Klein6a25bd02014-08-29 10:03:59 -040055 : GrTextContext(context, properties) {
56 fStrike = NULL;
57
58 fCurrTexture = NULL;
59 fCurrVertex = 0;
60 fEffectTextureUniqueID = SK_InvalidUniqueID;
61
62 fVertices = NULL;
63 fMaxVertices = 0;
64
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000065 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000066}
67
68GrBitmapTextContext::~GrBitmapTextContext() {
69 this->flushGlyphs();
70}
71
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000072bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
73 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
74}
75
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000076static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
77 unsigned r = SkColorGetR(c);
78 unsigned g = SkColorGetG(c);
79 unsigned b = SkColorGetB(c);
80 return GrColorPackRGBA(r, g, b, 0xff);
81}
82
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000083void GrBitmapTextContext::flushGlyphs() {
84 if (NULL == fDrawTarget) {
85 return;
86 }
87
88 GrDrawState* drawState = fDrawTarget->drawState();
89 GrDrawState::AutoRestoreEffects are(drawState);
90 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
91
92 if (fCurrVertex > 0) {
93 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000094 SkASSERT(SkIsAlign4(fCurrVertex));
Mike Klein6a25bd02014-08-29 10:03:59 -040095 SkASSERT(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000096 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
97
Mike Klein6a25bd02014-08-29 10:03:59 -040098 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
bsalomon8b2fac42014-06-19 14:13:45 -070099
bsalomon1c63bf62014-07-22 13:09:46 -0700100 if (textureUniqueID != fEffectTextureUniqueID) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400101 fCachedEffect.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture, params));
bsalomon1c63bf62014-07-22 13:09:46 -0700102 fEffectTextureUniqueID = textureUniqueID;
bsalomon8b2fac42014-06-19 14:13:45 -0700103 }
104
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000105 // This effect could be stored with one of the cache objects (atlas?)
joshualitt249af152014-09-15 11:41:13 -0700106 drawState->setGeometryProcessor(fCachedEffect.get());
bsalomon49f085d2014-09-05 13:34:00 -0700107 SkASSERT(fStrike);
bsalomon594069f2014-06-06 06:16:34 -0700108 switch (fStrike->getMaskFormat()) {
109 // Color bitmap text
110 case kARGB_GrMaskFormat:
111 SkASSERT(!drawState->hasColorVertexAttribute());
112 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
113 drawState->setColor(0xffffffff);
114 break;
115 // LCD text
116 case kA888_GrMaskFormat:
117 case kA565_GrMaskFormat: {
118 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
119 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
120 fPaint.numColorStages()) {
121 GrPrintf("LCD Text will not draw correctly.\n");
122 }
123 SkASSERT(!drawState->hasColorVertexAttribute());
124 // We don't use the GrPaint's color in this case because it's been premultiplied by
125 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
126 // the mask texture color. The end result is that we get
127 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
128 int a = SkColorGetA(fSkPaint.getColor());
129 // paintAlpha
130 drawState->setColor(SkColorSetARGB(a, a, a, a));
131 // paintColor
132 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
133 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
134 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000135 }
bsalomon594069f2014-06-06 06:16:34 -0700136 // Grayscale/BW text
137 case kA8_GrMaskFormat:
138 // set back to normal in case we took LCD path previously.
139 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
bsalomon594069f2014-06-06 06:16:34 -0700140 // We're using per-vertex color.
141 SkASSERT(drawState->hasColorVertexAttribute());
bsalomon594069f2014-06-06 06:16:34 -0700142 break;
143 default:
144 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000145 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000146 int nGlyphs = fCurrVertex / 4;
147 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
148 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
149 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000150 4, 6, &fVertexBounds);
Mike Klein6a25bd02014-08-29 10:03:59 -0400151
152 fDrawTarget->resetVertexSource();
153 fVertices = NULL;
154 fMaxVertices = 0;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000155 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000156 fVertexBounds.setLargestInverted();
Mike Klein6a25bd02014-08-29 10:03:59 -0400157 SkSafeSetNull(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000158 }
159}
160
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000161inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
162 GrTextContext::init(paint, skPaint);
163
164 fStrike = NULL;
165
Mike Klein6a25bd02014-08-29 10:03:59 -0400166 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -0700167 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -0400168
169 fVertices = NULL;
170 fMaxVertices = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000171}
172
173inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700174 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000175
176 GrTextContext::finish();
177}
178
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000179void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000180 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000181 SkScalar x, SkScalar y) {
182 SkASSERT(byteLength == 0 || text != NULL);
183
184 // nothing to draw
185 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
186 return;
187 }
188
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000189 this->init(paint, skPaint);
190
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000191 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
192
193 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
194 SkGlyphCache* cache = autoCache.getCache();
195 GrFontScaler* fontScaler = GetGrFontScaler(cache);
Mike Klein6a25bd02014-08-29 10:03:59 -0400196
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000197 // transform our starting point
198 {
199 SkPoint loc;
200 fContext->getMatrix().mapXY(x, y, &loc);
201 x = loc.fX;
202 y = loc.fY;
203 }
204
205 // need to measure first
206 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
207 SkVector stop;
208
209 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
210
211 SkScalar stopX = stop.fX;
212 SkScalar stopY = stop.fY;
213
214 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
215 stopX = SkScalarHalf(stopX);
216 stopY = SkScalarHalf(stopY);
217 }
218 x -= stopX;
219 y -= stopY;
220 }
221
222 const char* stop = text + byteLength;
223
Mike Klein6a25bd02014-08-29 10:03:59 -0400224 SkAutoKern autokern;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000225
226 SkFixed fxMask = ~0;
227 SkFixed fyMask = ~0;
228 SkFixed halfSampleX, halfSampleY;
229 if (cache->isSubpixel()) {
230 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
231 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
232 if (kX_SkAxisAlignment == baseline) {
233 fyMask = 0;
234 halfSampleY = SK_FixedHalf;
235 } else if (kY_SkAxisAlignment == baseline) {
236 fxMask = 0;
237 halfSampleX = SK_FixedHalf;
238 }
239 } else {
240 halfSampleX = halfSampleY = SK_FixedHalf;
241 }
242
243 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
244 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000245
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000246 GrContext::AutoMatrix autoMatrix;
247 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000248
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000249 while (text < stop) {
250 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
251
252 fx += autokern.adjust(glyph);
253
254 if (glyph.fWidth) {
255 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
256 glyph.getSubXFixed(),
257 glyph.getSubYFixed()),
258 SkFixedFloorToFixed(fx),
259 SkFixedFloorToFixed(fy),
260 fontScaler);
261 }
262
263 fx += glyph.fAdvanceX;
264 fy += glyph.fAdvanceY;
265 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000266
267 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000268}
269
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000270void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000271 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000272 const SkScalar pos[], SkScalar constY,
273 int scalarsPerPosition) {
274 SkASSERT(byteLength == 0 || text != NULL);
275 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
276
277 // nothing to draw
278 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
279 return;
280 }
281
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000282 this->init(paint, skPaint);
283
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000284 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
285
286 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
287 SkGlyphCache* cache = autoCache.getCache();
288 GrFontScaler* fontScaler = GetGrFontScaler(cache);
289
290 // store original matrix before we reset, so we can use it to transform positions
291 SkMatrix ctm = fContext->getMatrix();
292 GrContext::AutoMatrix autoMatrix;
293 autoMatrix.setIdentity(fContext, &fPaint);
294
295 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700296 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
297 SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000298 SkFixed halfSampleX = 0, halfSampleY = 0;
299
300 if (cache->isSubpixel()) {
301 // maybe we should skip the rounding if linearText is set
302 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
303
304 SkFixed fxMask = ~0;
305 SkFixed fyMask = ~0;
306 if (kX_SkAxisAlignment == baseline) {
307 fyMask = 0;
308#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
309 halfSampleY = SK_FixedHalf;
310#endif
311 } else if (kY_SkAxisAlignment == baseline) {
312 fxMask = 0;
313#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
314 halfSampleX = SK_FixedHalf;
315#endif
316 }
317
318 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
319 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700320 SkPoint tmsLoc;
321 tmsProc(pos, &tmsLoc);
322 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
323 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000324
325 const SkGlyph& glyph = glyphCacheProc(cache, &text,
326 fx & fxMask, fy & fyMask);
327
328 if (glyph.fWidth) {
329 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
330 glyph.getSubXFixed(),
331 glyph.getSubYFixed()),
332 SkFixedFloorToFixed(fx),
333 SkFixedFloorToFixed(fy),
334 fontScaler);
335 }
336 pos += scalarsPerPosition;
337 }
338 } else {
339 while (text < stop) {
340 const char* currentText = text;
341 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
342
343 if (metricGlyph.fWidth) {
344 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
345 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700346 SkPoint tmsLoc;
347 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000348 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700349 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000350
351 SkFixed fx = fixedLoc.fX + halfSampleX;
352 SkFixed fy = fixedLoc.fY + halfSampleY;
353
354 // have to call again, now that we've been "aligned"
355 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
356 fx & fxMask, fy & fyMask);
357 // the assumption is that the metrics haven't changed
358 SkASSERT(prevAdvX == glyph.fAdvanceX);
359 SkASSERT(prevAdvY == glyph.fAdvanceY);
360 SkASSERT(glyph.fWidth);
361
362 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
363 glyph.getSubXFixed(),
364 glyph.getSubYFixed()),
365 SkFixedFloorToFixed(fx),
366 SkFixedFloorToFixed(fy),
367 fontScaler);
368 }
369 pos += scalarsPerPosition;
370 }
371 }
372 } else { // not subpixel
373
374 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
375 while (text < stop) {
376 // the last 2 parameters are ignored
377 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
378
379 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700380 SkPoint tmsLoc;
381 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000382
kkinnunencb9a2c82014-06-12 23:06:28 -0700383 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
384 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000385 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
386 glyph.getSubXFixed(),
387 glyph.getSubYFixed()),
388 SkFixedFloorToFixed(fx),
389 SkFixedFloorToFixed(fy),
390 fontScaler);
391 }
392 pos += scalarsPerPosition;
393 }
394 } else {
395 while (text < stop) {
396 // the last 2 parameters are ignored
397 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
398
399 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700400 SkPoint tmsLoc;
401 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000402
403 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700404 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000405
406 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
407 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
408 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
409 glyph.getSubXFixed(),
410 glyph.getSubYFixed()),
411 SkFixedFloorToFixed(fx),
412 SkFixedFloorToFixed(fy),
413 fontScaler);
414 }
415 pos += scalarsPerPosition;
416 }
417 }
418 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000419
420 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000421}
422
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000423void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000424 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000425 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400426 if (NULL == fDrawTarget) {
427 return;
428 }
429
430 if (NULL == fStrike) {
431 fStrike = fContext->getFontCache()->getStrike(scaler, false);
432 }
433
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000434 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
435 if (NULL == glyph || glyph->fBounds.isEmpty()) {
436 return;
437 }
438
439 vx += SkIntToFixed(glyph->fBounds.fLeft);
440 vy += SkIntToFixed(glyph->fBounds.fTop);
441
442 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000443 SkFixed width = glyph->fBounds.width();
444 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000445
446 // check if we clipped out
447 if (true || NULL == glyph->fPlot) {
448 int x = vx >> 16;
449 int y = vy >> 16;
450 if (fClipRect.quickReject(x, y, x + width, y + height)) {
451// SkCLZ(3); // so we can set a break-point in the debugger
452 return;
453 }
454 }
455
456 if (NULL == glyph->fPlot) {
jvanverth681e65b2014-09-19 13:07:38 -0700457 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
458 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
459 goto HAS_ATLAS;
460 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000461
jvanverth681e65b2014-09-19 13:07:38 -0700462 // try to clear out an unused plot before we flush
463 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
464 fStrike->addGlyphToAtlas(glyph, scaler)) {
465 goto HAS_ATLAS;
466 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000467
jvanverth681e65b2014-09-19 13:07:38 -0700468 if (c_DumpFontCache) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000469#ifdef SK_DEVELOPER
jvanverth681e65b2014-09-19 13:07:38 -0700470 fContext->getFontCache()->dump();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000471#endif
jvanverth681e65b2014-09-19 13:07:38 -0700472 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000473
jvanverth681e65b2014-09-19 13:07:38 -0700474 // flush any accumulated draws to allow us to free up a plot
475 this->flushGlyphs();
476 fContext->flush();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000477
jvanverth681e65b2014-09-19 13:07:38 -0700478 // we should have an unused plot now
479 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
480 fStrike->addGlyphToAtlas(glyph, scaler)) {
481 goto HAS_ATLAS;
482 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000483 }
484
485 if (NULL == glyph->fPath) {
486 SkPath* path = SkNEW(SkPath);
487 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
488 // flag the glyph as being dead?
489 delete path;
490 return;
491 }
492 glyph->fPath = path;
493 }
494
495 GrContext::AutoMatrix am;
496 SkMatrix translate;
497 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
498 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
499 GrPaint tmpPaint(fPaint);
500 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700501 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
502 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000503 return;
504 }
505
506HAS_ATLAS:
507 SkASSERT(glyph->fPlot);
508 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
509 glyph->fPlot->setDrawToken(drawToken);
510
511 // now promote them to fixed (TODO: Rethink using fixed pt).
512 width = SkIntToFixed(width);
513 height = SkIntToFixed(height);
514
515 GrTexture* texture = glyph->fPlot->texture();
516 SkASSERT(texture);
517
Mike Klein6a25bd02014-08-29 10:03:59 -0400518 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
519 this->flushGlyphs();
520 fCurrTexture = texture;
521 fCurrTexture->ref();
522 }
523
524 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
525
526 if (NULL == fVertices) {
527 // If we need to reserve vertices allow the draw target to suggest
528 // a number of verts to reserve and whether to perform a flush.
529 fMaxVertices = kMinRequestedVerts;
530 if (useColorVerts) {
531 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
532 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
533 } else {
534 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
535 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
536 }
537 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
538 if (flush) {
539 this->flushGlyphs();
540 fContext->flush();
541 if (useColorVerts) {
542 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
543 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
544 } else {
545 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
546 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
547 }
548 }
549 fMaxVertices = kDefaultRequestedVerts;
550 // ignore return, no point in flushing again.
551 fDrawTarget->geometryHints(&fMaxVertices, NULL);
552
553 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
554 if (fMaxVertices < kMinRequestedVerts) {
555 fMaxVertices = kDefaultRequestedVerts;
556 } else if (fMaxVertices > maxQuadVertices) {
557 // don't exceed the limit of the index buffer
558 fMaxVertices = maxQuadVertices;
559 }
560 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
561 0,
562 &fVertices,
563 NULL);
564 GrAlwaysAssert(success);
565 }
566
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000567 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
568 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000569
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000570 SkRect r;
571 r.fLeft = SkFixedToFloat(vx);
572 r.fTop = SkFixedToFloat(vy);
573 r.fRight = SkFixedToFloat(vx + width);
574 r.fBottom = SkFixedToFloat(vy + height);
575
576 fVertexBounds.growToInclude(r);
577
bsalomon594069f2014-06-06 06:16:34 -0700578 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
579 (2 * sizeof(SkPoint));
580
egdaniel7b3d5ee2014-08-28 05:41:14 -0700581 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
bsalomon594069f2014-06-06 06:16:34 -0700582
583 SkPoint* positions = reinterpret_cast<SkPoint*>(
584 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
585 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
586
587 // The texture coords are last in both the with and without color vertex layouts.
588 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
589 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
590 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
591 SkFixedToFloat(texture->normalizeFixedY(ty)),
592 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
593 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
594 vertSize);
595 if (useColorVerts) {
bsalomon62c447d2014-08-08 08:08:50 -0700596 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
597 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
598 }
bsalomon594069f2014-06-06 06:16:34 -0700599 // color comes after position.
600 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
601 for (int i = 0; i < 4; ++i) {
602 *colors = fPaint.getColor();
603 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
604 }
605 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000606 fCurrVertex += 4;
607}