blob: 4f6a1af7b26b1f6967015e5d7da35ca66e258342 [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
43// position + color + texture coord
44extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
45 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
46 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
47 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
48};
49
50};
51
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000052GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000053 const SkDeviceProperties& properties)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000054 : GrTextContext(context, properties) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000055 fStrike = NULL;
56
57 fCurrTexture = NULL;
58 fCurrVertex = 0;
59
60 fVertices = NULL;
61 fMaxVertices = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000062
63 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000064}
65
66GrBitmapTextContext::~GrBitmapTextContext() {
67 this->flushGlyphs();
68}
69
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000070bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
71 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
72}
73
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000074static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
75 unsigned r = SkColorGetR(c);
76 unsigned g = SkColorGetG(c);
77 unsigned b = SkColorGetB(c);
78 return GrColorPackRGBA(r, g, b, 0xff);
79}
80
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000081void GrBitmapTextContext::flushGlyphs() {
82 if (NULL == fDrawTarget) {
83 return;
84 }
85
86 GrDrawState* drawState = fDrawTarget->drawState();
87 GrDrawState::AutoRestoreEffects are(drawState);
88 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
89
90 if (fCurrVertex > 0) {
91 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000092 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000093 SkASSERT(fCurrTexture);
94 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
95
96 // This effect could be stored with one of the cache objects (atlas?)
bsalomon594069f2014-06-06 06:16:34 -070097 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
98 kGlyphCoordsNoColorAttributeIndex;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000099 drawState->addCoverageEffect(
100 GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
bsalomon594069f2014-06-06 06:16:34 -0700101 coordsIdx)->unref();
102 SkASSERT(NULL != fStrike);
103 switch (fStrike->getMaskFormat()) {
104 // Color bitmap text
105 case kARGB_GrMaskFormat:
106 SkASSERT(!drawState->hasColorVertexAttribute());
107 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
108 drawState->setColor(0xffffffff);
109 break;
110 // LCD text
111 case kA888_GrMaskFormat:
112 case kA565_GrMaskFormat: {
113 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
114 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
115 fPaint.numColorStages()) {
116 GrPrintf("LCD Text will not draw correctly.\n");
117 }
118 SkASSERT(!drawState->hasColorVertexAttribute());
119 // We don't use the GrPaint's color in this case because it's been premultiplied by
120 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
121 // the mask texture color. The end result is that we get
122 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
123 int a = SkColorGetA(fSkPaint.getColor());
124 // paintAlpha
125 drawState->setColor(SkColorSetARGB(a, a, a, a));
126 // paintColor
127 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
128 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
129 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000130 }
bsalomon594069f2014-06-06 06:16:34 -0700131 // Grayscale/BW text
132 case kA8_GrMaskFormat:
133 // set back to normal in case we took LCD path previously.
134 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
135 //drawState->setColor(fPaint.getColor());
136 // We're using per-vertex color.
137 SkASSERT(drawState->hasColorVertexAttribute());
138 drawState->setColor(0xFFFFFFFF);
139 break;
140 default:
141 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000142 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000143 int nGlyphs = fCurrVertex / 4;
144 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
145 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
146 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000147 4, 6, &fVertexBounds);
commit-bot@chromium.org42a89572013-10-28 15:13:50 +0000148
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000149 fDrawTarget->resetVertexSource();
150 fVertices = NULL;
151 fMaxVertices = 0;
152 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000153 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000154 SkSafeSetNull(fCurrTexture);
155 }
156}
157
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000158inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
159 GrTextContext::init(paint, skPaint);
160
161 fStrike = NULL;
162
163 fCurrTexture = NULL;
164 fCurrVertex = 0;
165
166 fVertices = NULL;
167 fMaxVertices = 0;
168}
169
170inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700171 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000172
173 GrTextContext::finish();
174}
175
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000176void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000177 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000178 SkScalar x, SkScalar y) {
179 SkASSERT(byteLength == 0 || text != NULL);
180
181 // nothing to draw
182 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
183 return;
184 }
185
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000186 this->init(paint, skPaint);
187
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000188 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
189
190 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
191 SkGlyphCache* cache = autoCache.getCache();
192 GrFontScaler* fontScaler = GetGrFontScaler(cache);
193
194 // transform our starting point
195 {
196 SkPoint loc;
197 fContext->getMatrix().mapXY(x, y, &loc);
198 x = loc.fX;
199 y = loc.fY;
200 }
201
202 // need to measure first
203 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
204 SkVector stop;
205
206 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
207
208 SkScalar stopX = stop.fX;
209 SkScalar stopY = stop.fY;
210
211 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
212 stopX = SkScalarHalf(stopX);
213 stopY = SkScalarHalf(stopY);
214 }
215 x -= stopX;
216 y -= stopY;
217 }
218
219 const char* stop = text + byteLength;
220
221 SkAutoKern autokern;
222
223 SkFixed fxMask = ~0;
224 SkFixed fyMask = ~0;
225 SkFixed halfSampleX, halfSampleY;
226 if (cache->isSubpixel()) {
227 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
228 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
229 if (kX_SkAxisAlignment == baseline) {
230 fyMask = 0;
231 halfSampleY = SK_FixedHalf;
232 } else if (kY_SkAxisAlignment == baseline) {
233 fxMask = 0;
234 halfSampleX = SK_FixedHalf;
235 }
236 } else {
237 halfSampleX = halfSampleY = SK_FixedHalf;
238 }
239
240 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
241 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000242
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000243 GrContext::AutoMatrix autoMatrix;
244 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000245
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000246 while (text < stop) {
247 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
248
249 fx += autokern.adjust(glyph);
250
251 if (glyph.fWidth) {
252 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
253 glyph.getSubXFixed(),
254 glyph.getSubYFixed()),
255 SkFixedFloorToFixed(fx),
256 SkFixedFloorToFixed(fy),
257 fontScaler);
258 }
259
260 fx += glyph.fAdvanceX;
261 fy += glyph.fAdvanceY;
262 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000263
264 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000265}
266
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000267void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000268 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000269 const SkScalar pos[], SkScalar constY,
270 int scalarsPerPosition) {
271 SkASSERT(byteLength == 0 || text != NULL);
272 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
273
274 // nothing to draw
275 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
276 return;
277 }
278
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000279 this->init(paint, skPaint);
280
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000281 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
282
283 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
284 SkGlyphCache* cache = autoCache.getCache();
285 GrFontScaler* fontScaler = GetGrFontScaler(cache);
286
287 // store original matrix before we reset, so we can use it to transform positions
288 SkMatrix ctm = fContext->getMatrix();
289 GrContext::AutoMatrix autoMatrix;
290 autoMatrix.setIdentity(fContext, &fPaint);
291
292 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700293 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
294 SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000295 SkFixed halfSampleX = 0, halfSampleY = 0;
296
297 if (cache->isSubpixel()) {
298 // maybe we should skip the rounding if linearText is set
299 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
300
301 SkFixed fxMask = ~0;
302 SkFixed fyMask = ~0;
303 if (kX_SkAxisAlignment == baseline) {
304 fyMask = 0;
305#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
306 halfSampleY = SK_FixedHalf;
307#endif
308 } else if (kY_SkAxisAlignment == baseline) {
309 fxMask = 0;
310#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
311 halfSampleX = SK_FixedHalf;
312#endif
313 }
314
315 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
316 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700317 SkPoint tmsLoc;
318 tmsProc(pos, &tmsLoc);
319 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
320 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000321
322 const SkGlyph& glyph = glyphCacheProc(cache, &text,
323 fx & fxMask, fy & fyMask);
324
325 if (glyph.fWidth) {
326 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
327 glyph.getSubXFixed(),
328 glyph.getSubYFixed()),
329 SkFixedFloorToFixed(fx),
330 SkFixedFloorToFixed(fy),
331 fontScaler);
332 }
333 pos += scalarsPerPosition;
334 }
335 } else {
336 while (text < stop) {
337 const char* currentText = text;
338 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
339
340 if (metricGlyph.fWidth) {
341 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
342 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700343 SkPoint tmsLoc;
344 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000345 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700346 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000347
348 SkFixed fx = fixedLoc.fX + halfSampleX;
349 SkFixed fy = fixedLoc.fY + halfSampleY;
350
351 // have to call again, now that we've been "aligned"
352 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
353 fx & fxMask, fy & fyMask);
354 // the assumption is that the metrics haven't changed
355 SkASSERT(prevAdvX == glyph.fAdvanceX);
356 SkASSERT(prevAdvY == glyph.fAdvanceY);
357 SkASSERT(glyph.fWidth);
358
359 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
360 glyph.getSubXFixed(),
361 glyph.getSubYFixed()),
362 SkFixedFloorToFixed(fx),
363 SkFixedFloorToFixed(fy),
364 fontScaler);
365 }
366 pos += scalarsPerPosition;
367 }
368 }
369 } else { // not subpixel
370
371 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
372 while (text < stop) {
373 // the last 2 parameters are ignored
374 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
375
376 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700377 SkPoint tmsLoc;
378 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000379
kkinnunencb9a2c82014-06-12 23:06:28 -0700380 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
381 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000382 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
383 glyph.getSubXFixed(),
384 glyph.getSubYFixed()),
385 SkFixedFloorToFixed(fx),
386 SkFixedFloorToFixed(fy),
387 fontScaler);
388 }
389 pos += scalarsPerPosition;
390 }
391 } else {
392 while (text < stop) {
393 // the last 2 parameters are ignored
394 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
395
396 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700397 SkPoint tmsLoc;
398 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000399
400 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700401 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000402
403 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
404 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
405 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
406 glyph.getSubXFixed(),
407 glyph.getSubYFixed()),
408 SkFixedFloorToFixed(fx),
409 SkFixedFloorToFixed(fy),
410 fontScaler);
411 }
412 pos += scalarsPerPosition;
413 }
414 }
415 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000416
417 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000418}
419
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000420void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000421 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000422 GrFontScaler* scaler) {
423 if (NULL == fDrawTarget) {
424 return;
425 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000426
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000427 if (NULL == fStrike) {
commit-bot@chromium.org75a22952013-11-21 15:09:33 +0000428 fStrike = fContext->getFontCache()->getStrike(scaler, false);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000429 }
430
431 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
432 if (NULL == glyph || glyph->fBounds.isEmpty()) {
433 return;
434 }
435
436 vx += SkIntToFixed(glyph->fBounds.fLeft);
437 vy += SkIntToFixed(glyph->fBounds.fTop);
438
439 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000440 SkFixed width = glyph->fBounds.width();
441 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000442
443 // check if we clipped out
444 if (true || NULL == glyph->fPlot) {
445 int x = vx >> 16;
446 int y = vy >> 16;
447 if (fClipRect.quickReject(x, y, x + width, y + height)) {
448// SkCLZ(3); // so we can set a break-point in the debugger
449 return;
450 }
451 }
452
453 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000454 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000455 goto HAS_ATLAS;
456 }
457
458 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000459 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
460 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000461 goto HAS_ATLAS;
462 }
463
464 if (c_DumpFontCache) {
465#ifdef SK_DEVELOPER
466 fContext->getFontCache()->dump();
467#endif
468 }
469
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000470 // flush any accumulated draws to allow us to free up a plot
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000471 this->flushGlyphs();
472 fContext->flush();
473
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000474 // we should have an unused plot now
475 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
476 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000477 goto HAS_ATLAS;
478 }
479
480 if (NULL == glyph->fPath) {
481 SkPath* path = SkNEW(SkPath);
482 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
483 // flag the glyph as being dead?
484 delete path;
485 return;
486 }
487 glyph->fPath = path;
488 }
489
490 GrContext::AutoMatrix am;
491 SkMatrix translate;
492 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
493 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
494 GrPaint tmpPaint(fPaint);
495 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700496 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
497 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000498 return;
499 }
500
501HAS_ATLAS:
502 SkASSERT(glyph->fPlot);
503 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
504 glyph->fPlot->setDrawToken(drawToken);
505
506 // now promote them to fixed (TODO: Rethink using fixed pt).
507 width = SkIntToFixed(width);
508 height = SkIntToFixed(height);
509
510 GrTexture* texture = glyph->fPlot->texture();
511 SkASSERT(texture);
512
513 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
514 this->flushGlyphs();
515 fCurrTexture = texture;
516 fCurrTexture->ref();
517 }
518
bsalomon594069f2014-06-06 06:16:34 -0700519 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
520
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000521 if (NULL == fVertices) {
522 // If we need to reserve vertices allow the draw target to suggest
523 // a number of verts to reserve and whether to perform a flush.
524 fMaxVertices = kMinRequestedVerts;
bsalomon594069f2014-06-06 06:16:34 -0700525 if (useColorVerts) {
526 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
527 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
528 } else {
529 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
530 SK_ARRAY_COUNT(gTextVertexAttribs));
531 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000532 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
533 if (flush) {
534 this->flushGlyphs();
535 fContext->flush();
bsalomon594069f2014-06-06 06:16:34 -0700536 if (useColorVerts) {
537 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
538 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
539 } else {
540 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
541 SK_ARRAY_COUNT(gTextVertexAttribs));
542 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000543 }
544 fMaxVertices = kDefaultRequestedVerts;
545 // ignore return, no point in flushing again.
546 fDrawTarget->geometryHints(&fMaxVertices, NULL);
547
548 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
549 if (fMaxVertices < kMinRequestedVerts) {
550 fMaxVertices = kDefaultRequestedVerts;
551 } else if (fMaxVertices > maxQuadVertices) {
552 // don't exceed the limit of the index buffer
553 fMaxVertices = maxQuadVertices;
554 }
555 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
556 0,
bsalomon594069f2014-06-06 06:16:34 -0700557 &fVertices,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000558 NULL);
559 GrAlwaysAssert(success);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000560 }
561
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000562 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
563 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000564
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000565 SkRect r;
566 r.fLeft = SkFixedToFloat(vx);
567 r.fTop = SkFixedToFloat(vy);
568 r.fRight = SkFixedToFloat(vx + width);
569 r.fBottom = SkFixedToFloat(vy + height);
570
571 fVertexBounds.growToInclude(r);
572
bsalomon594069f2014-06-06 06:16:34 -0700573 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
574 (2 * sizeof(SkPoint));
575
576 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
577
578 SkPoint* positions = reinterpret_cast<SkPoint*>(
579 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
580 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
581
582 // The texture coords are last in both the with and without color vertex layouts.
583 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
584 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
585 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
586 SkFixedToFloat(texture->normalizeFixedY(ty)),
587 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
588 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
589 vertSize);
590 if (useColorVerts) {
591 // color comes after position.
592 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
593 for (int i = 0; i < 4; ++i) {
594 *colors = fPaint.getColor();
595 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
596 }
597 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000598 fCurrVertex += 4;
599}