blob: 696077dd95d364d7e5f8bfafe5f03d1e80504e7c [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) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000091 fContext->getFontCache()->updateTextures();
92
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000093 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000094 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000095 SkASSERT(fCurrTexture);
96 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
97
98 // This effect could be stored with one of the cache objects (atlas?)
bsalomon594069f2014-06-06 06:16:34 -070099 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
100 kGlyphCoordsNoColorAttributeIndex;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000101 drawState->addCoverageEffect(
102 GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
bsalomon594069f2014-06-06 06:16:34 -0700103 coordsIdx)->unref();
104 SkASSERT(NULL != fStrike);
105 switch (fStrike->getMaskFormat()) {
106 // Color bitmap text
107 case kARGB_GrMaskFormat:
108 SkASSERT(!drawState->hasColorVertexAttribute());
109 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
110 drawState->setColor(0xffffffff);
111 break;
112 // LCD text
113 case kA888_GrMaskFormat:
114 case kA565_GrMaskFormat: {
115 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
116 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
117 fPaint.numColorStages()) {
118 GrPrintf("LCD Text will not draw correctly.\n");
119 }
120 SkASSERT(!drawState->hasColorVertexAttribute());
121 // We don't use the GrPaint's color in this case because it's been premultiplied by
122 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
123 // the mask texture color. The end result is that we get
124 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
125 int a = SkColorGetA(fSkPaint.getColor());
126 // paintAlpha
127 drawState->setColor(SkColorSetARGB(a, a, a, a));
128 // paintColor
129 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
130 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
131 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000132 }
bsalomon594069f2014-06-06 06:16:34 -0700133 // Grayscale/BW text
134 case kA8_GrMaskFormat:
135 // set back to normal in case we took LCD path previously.
136 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
137 //drawState->setColor(fPaint.getColor());
138 // We're using per-vertex color.
139 SkASSERT(drawState->hasColorVertexAttribute());
140 drawState->setColor(0xFFFFFFFF);
141 break;
142 default:
143 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000144 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000145 int nGlyphs = fCurrVertex / 4;
146 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
147 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
148 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000149 4, 6, &fVertexBounds);
commit-bot@chromium.org42a89572013-10-28 15:13:50 +0000150
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000151 fDrawTarget->resetVertexSource();
152 fVertices = NULL;
153 fMaxVertices = 0;
154 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000155 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000156 SkSafeSetNull(fCurrTexture);
157 }
158}
159
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000160inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
161 GrTextContext::init(paint, skPaint);
162
163 fStrike = NULL;
164
165 fCurrTexture = NULL;
166 fCurrVertex = 0;
167
168 fVertices = NULL;
169 fMaxVertices = 0;
170}
171
172inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700173 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000174
175 GrTextContext::finish();
176}
177
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000178void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000179 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000180 SkScalar x, SkScalar y) {
181 SkASSERT(byteLength == 0 || text != NULL);
182
183 // nothing to draw
184 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
185 return;
186 }
187
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000188 this->init(paint, skPaint);
189
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000190 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
191
192 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
193 SkGlyphCache* cache = autoCache.getCache();
194 GrFontScaler* fontScaler = GetGrFontScaler(cache);
195
196 // transform our starting point
197 {
198 SkPoint loc;
199 fContext->getMatrix().mapXY(x, y, &loc);
200 x = loc.fX;
201 y = loc.fY;
202 }
203
204 // need to measure first
205 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
206 SkVector stop;
207
208 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
209
210 SkScalar stopX = stop.fX;
211 SkScalar stopY = stop.fY;
212
213 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
214 stopX = SkScalarHalf(stopX);
215 stopY = SkScalarHalf(stopY);
216 }
217 x -= stopX;
218 y -= stopY;
219 }
220
221 const char* stop = text + byteLength;
222
223 SkAutoKern autokern;
224
225 SkFixed fxMask = ~0;
226 SkFixed fyMask = ~0;
227 SkFixed halfSampleX, halfSampleY;
228 if (cache->isSubpixel()) {
229 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
230 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
231 if (kX_SkAxisAlignment == baseline) {
232 fyMask = 0;
233 halfSampleY = SK_FixedHalf;
234 } else if (kY_SkAxisAlignment == baseline) {
235 fxMask = 0;
236 halfSampleX = SK_FixedHalf;
237 }
238 } else {
239 halfSampleX = halfSampleY = SK_FixedHalf;
240 }
241
242 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
243 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000244
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000245 GrContext::AutoMatrix autoMatrix;
246 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000247
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000248 while (text < stop) {
249 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
250
251 fx += autokern.adjust(glyph);
252
253 if (glyph.fWidth) {
254 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
255 glyph.getSubXFixed(),
256 glyph.getSubYFixed()),
257 SkFixedFloorToFixed(fx),
258 SkFixedFloorToFixed(fy),
259 fontScaler);
260 }
261
262 fx += glyph.fAdvanceX;
263 fy += glyph.fAdvanceY;
264 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000265
266 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000267}
268
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000269void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000270 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000271 const SkScalar pos[], SkScalar constY,
272 int scalarsPerPosition) {
273 SkASSERT(byteLength == 0 || text != NULL);
274 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
275
276 // nothing to draw
277 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
278 return;
279 }
280
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000281 this->init(paint, skPaint);
282
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000283 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
284
285 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
286 SkGlyphCache* cache = autoCache.getCache();
287 GrFontScaler* fontScaler = GetGrFontScaler(cache);
288
289 // store original matrix before we reset, so we can use it to transform positions
290 SkMatrix ctm = fContext->getMatrix();
291 GrContext::AutoMatrix autoMatrix;
292 autoMatrix.setIdentity(fContext, &fPaint);
293
294 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700295 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
296 SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000297 SkFixed halfSampleX = 0, halfSampleY = 0;
298
299 if (cache->isSubpixel()) {
300 // maybe we should skip the rounding if linearText is set
301 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
302
303 SkFixed fxMask = ~0;
304 SkFixed fyMask = ~0;
305 if (kX_SkAxisAlignment == baseline) {
306 fyMask = 0;
307#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
308 halfSampleY = SK_FixedHalf;
309#endif
310 } else if (kY_SkAxisAlignment == baseline) {
311 fxMask = 0;
312#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
313 halfSampleX = SK_FixedHalf;
314#endif
315 }
316
317 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
318 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700319 SkPoint tmsLoc;
320 tmsProc(pos, &tmsLoc);
321 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
322 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000323
324 const SkGlyph& glyph = glyphCacheProc(cache, &text,
325 fx & fxMask, fy & fyMask);
326
327 if (glyph.fWidth) {
328 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
329 glyph.getSubXFixed(),
330 glyph.getSubYFixed()),
331 SkFixedFloorToFixed(fx),
332 SkFixedFloorToFixed(fy),
333 fontScaler);
334 }
335 pos += scalarsPerPosition;
336 }
337 } else {
338 while (text < stop) {
339 const char* currentText = text;
340 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
341
342 if (metricGlyph.fWidth) {
343 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
344 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700345 SkPoint tmsLoc;
346 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000347 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700348 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000349
350 SkFixed fx = fixedLoc.fX + halfSampleX;
351 SkFixed fy = fixedLoc.fY + halfSampleY;
352
353 // have to call again, now that we've been "aligned"
354 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
355 fx & fxMask, fy & fyMask);
356 // the assumption is that the metrics haven't changed
357 SkASSERT(prevAdvX == glyph.fAdvanceX);
358 SkASSERT(prevAdvY == glyph.fAdvanceY);
359 SkASSERT(glyph.fWidth);
360
361 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
362 glyph.getSubXFixed(),
363 glyph.getSubYFixed()),
364 SkFixedFloorToFixed(fx),
365 SkFixedFloorToFixed(fy),
366 fontScaler);
367 }
368 pos += scalarsPerPosition;
369 }
370 }
371 } else { // not subpixel
372
373 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
374 while (text < stop) {
375 // the last 2 parameters are ignored
376 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
377
378 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700379 SkPoint tmsLoc;
380 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000381
kkinnunencb9a2c82014-06-12 23:06:28 -0700382 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
383 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000384 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
385 glyph.getSubXFixed(),
386 glyph.getSubYFixed()),
387 SkFixedFloorToFixed(fx),
388 SkFixedFloorToFixed(fy),
389 fontScaler);
390 }
391 pos += scalarsPerPosition;
392 }
393 } else {
394 while (text < stop) {
395 // the last 2 parameters are ignored
396 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
397
398 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700399 SkPoint tmsLoc;
400 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000401
402 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700403 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000404
405 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
406 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
407 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
408 glyph.getSubXFixed(),
409 glyph.getSubYFixed()),
410 SkFixedFloorToFixed(fx),
411 SkFixedFloorToFixed(fy),
412 fontScaler);
413 }
414 pos += scalarsPerPosition;
415 }
416 }
417 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000418
419 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000420}
421
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000422void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000423 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000424 GrFontScaler* scaler) {
425 if (NULL == fDrawTarget) {
426 return;
427 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000428
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000429 if (NULL == fStrike) {
commit-bot@chromium.org75a22952013-11-21 15:09:33 +0000430 fStrike = fContext->getFontCache()->getStrike(scaler, false);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000431 }
432
433 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
434 if (NULL == glyph || glyph->fBounds.isEmpty()) {
435 return;
436 }
437
438 vx += SkIntToFixed(glyph->fBounds.fLeft);
439 vy += SkIntToFixed(glyph->fBounds.fTop);
440
441 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000442 SkFixed width = glyph->fBounds.width();
443 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000444
445 // check if we clipped out
446 if (true || NULL == glyph->fPlot) {
447 int x = vx >> 16;
448 int y = vy >> 16;
449 if (fClipRect.quickReject(x, y, x + width, y + height)) {
450// SkCLZ(3); // so we can set a break-point in the debugger
451 return;
452 }
453 }
454
455 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000456 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000457 goto HAS_ATLAS;
458 }
459
460 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000461 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
462 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000463 goto HAS_ATLAS;
464 }
465
466 if (c_DumpFontCache) {
467#ifdef SK_DEVELOPER
468 fContext->getFontCache()->dump();
469#endif
470 }
471
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000472 // flush any accumulated draws to allow us to free up a plot
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000473 this->flushGlyphs();
474 fContext->flush();
475
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000476 // we should have an unused plot now
477 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
478 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000479 goto HAS_ATLAS;
480 }
481
482 if (NULL == glyph->fPath) {
483 SkPath* path = SkNEW(SkPath);
484 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
485 // flag the glyph as being dead?
486 delete path;
487 return;
488 }
489 glyph->fPath = path;
490 }
491
492 GrContext::AutoMatrix am;
493 SkMatrix translate;
494 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
495 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
496 GrPaint tmpPaint(fPaint);
497 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700498 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
499 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000500 return;
501 }
502
503HAS_ATLAS:
504 SkASSERT(glyph->fPlot);
505 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
506 glyph->fPlot->setDrawToken(drawToken);
507
508 // now promote them to fixed (TODO: Rethink using fixed pt).
509 width = SkIntToFixed(width);
510 height = SkIntToFixed(height);
511
512 GrTexture* texture = glyph->fPlot->texture();
513 SkASSERT(texture);
514
515 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
516 this->flushGlyphs();
517 fCurrTexture = texture;
518 fCurrTexture->ref();
519 }
520
bsalomon594069f2014-06-06 06:16:34 -0700521 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
522
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000523 if (NULL == fVertices) {
524 // If we need to reserve vertices allow the draw target to suggest
525 // a number of verts to reserve and whether to perform a flush.
526 fMaxVertices = kMinRequestedVerts;
bsalomon594069f2014-06-06 06:16:34 -0700527 if (useColorVerts) {
528 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
529 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
530 } else {
531 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
532 SK_ARRAY_COUNT(gTextVertexAttribs));
533 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000534 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
535 if (flush) {
536 this->flushGlyphs();
537 fContext->flush();
bsalomon594069f2014-06-06 06:16:34 -0700538 if (useColorVerts) {
539 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
540 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
541 } else {
542 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
543 SK_ARRAY_COUNT(gTextVertexAttribs));
544 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000545 }
546 fMaxVertices = kDefaultRequestedVerts;
547 // ignore return, no point in flushing again.
548 fDrawTarget->geometryHints(&fMaxVertices, NULL);
549
550 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
551 if (fMaxVertices < kMinRequestedVerts) {
552 fMaxVertices = kDefaultRequestedVerts;
553 } else if (fMaxVertices > maxQuadVertices) {
554 // don't exceed the limit of the index buffer
555 fMaxVertices = maxQuadVertices;
556 }
557 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
558 0,
bsalomon594069f2014-06-06 06:16:34 -0700559 &fVertices,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000560 NULL);
561 GrAlwaysAssert(success);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000562 }
563
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000564 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
565 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000566
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000567 SkRect r;
568 r.fLeft = SkFixedToFloat(vx);
569 r.fTop = SkFixedToFloat(vy);
570 r.fRight = SkFixedToFloat(vx + width);
571 r.fBottom = SkFixedToFloat(vy + height);
572
573 fVertexBounds.growToInclude(r);
574
bsalomon594069f2014-06-06 06:16:34 -0700575 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
576 (2 * sizeof(SkPoint));
577
578 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
579
580 SkPoint* positions = reinterpret_cast<SkPoint*>(
581 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
582 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
583
584 // The texture coords are last in both the with and without color vertex layouts.
585 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
586 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
587 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
588 SkFixedToFloat(texture->normalizeFixedY(ty)),
589 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
590 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
591 vertSize);
592 if (useColorVerts) {
593 // color comes after position.
594 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
595 for (int i = 0; i < 4; ++i) {
596 *colors = fPaint.getColor();
597 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
598 }
599 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000600 fCurrVertex += 4;
601}