blob: c9cdf2c23f926430d1d06854808cd095d64c287e [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"
bsalomonafbf2d62014-09-30 12:18:44 -070014#include "GrTexturePriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000015#include "GrTextStrike.h"
16#include "GrTextStrike_impl.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000017#include "effects/GrCustomCoordsTextureEffect.h"
18
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000019#include "SkAutoKern.h"
bsalomonafbf2d62014-09-30 12:18:44 -070020#include "SkColorPriv.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000021#include "SkDraw.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070022#include "SkDrawProcs.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000023#include "SkGlyphCache.h"
24#include "SkGpuDevice.h"
25#include "SkGr.h"
bsalomonafbf2d62014-09-30 12:18:44 -070026#include "SkPath.h"
27#include "SkRTConf.h"
28#include "SkStrokeRec.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070029#include "SkTextMapStateProc.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000030
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000031SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
32 "Dump the contents of the font cache before every purge.");
33
bsalomon594069f2014-06-06 06:16:34 -070034namespace {
35// position + texture coord
36extern const GrVertexAttrib gTextVertexAttribs[] = {
37 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
joshualittb0a8a372014-09-23 09:50:21 -070038 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
bsalomon594069f2014-06-06 06:16:34 -070039};
40
egdaniel7b3d5ee2014-08-28 05:41:14 -070041static const size_t kTextVASize = 2 * sizeof(SkPoint);
42
bsalomon594069f2014-06-06 06:16:34 -070043// position + color + texture coord
44extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
45 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
46 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
joshualittb0a8a372014-09-23 09:50:21 -070047 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
bsalomon594069f2014-06-06 06:16:34 -070048};
49
egdaniel7b3d5ee2014-08-28 05:41:14 -070050static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
51
bsalomon594069f2014-06-06 06:16:34 -070052};
53
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000054GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000055 const SkDeviceProperties& properties)
Mike Klein6a25bd02014-08-29 10:03:59 -040056 : GrTextContext(context, properties) {
57 fStrike = NULL;
58
59 fCurrTexture = NULL;
60 fCurrVertex = 0;
61 fEffectTextureUniqueID = SK_InvalidUniqueID;
62
63 fVertices = NULL;
64 fMaxVertices = 0;
65
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000066 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000067}
68
69GrBitmapTextContext::~GrBitmapTextContext() {
70 this->flushGlyphs();
71}
72
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000073bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
74 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
75}
76
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000077static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
78 unsigned r = SkColorGetR(c);
79 unsigned g = SkColorGetG(c);
80 unsigned b = SkColorGetB(c);
81 return GrColorPackRGBA(r, g, b, 0xff);
82}
83
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000084void GrBitmapTextContext::flushGlyphs() {
85 if (NULL == fDrawTarget) {
86 return;
87 }
88
89 GrDrawState* drawState = fDrawTarget->drawState();
90 GrDrawState::AutoRestoreEffects are(drawState);
91 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
92
93 if (fCurrVertex > 0) {
94 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000095 SkASSERT(SkIsAlign4(fCurrVertex));
Mike Klein6a25bd02014-08-29 10:03:59 -040096 SkASSERT(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000097 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
98
Mike Klein6a25bd02014-08-29 10:03:59 -040099 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
bsalomon8b2fac42014-06-19 14:13:45 -0700100
bsalomon1c63bf62014-07-22 13:09:46 -0700101 if (textureUniqueID != fEffectTextureUniqueID) {
joshualittb0a8a372014-09-23 09:50:21 -0700102 fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
103 params));
bsalomon1c63bf62014-07-22 13:09:46 -0700104 fEffectTextureUniqueID = textureUniqueID;
bsalomon8b2fac42014-06-19 14:13:45 -0700105 }
106
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000107 // This effect could be stored with one of the cache objects (atlas?)
joshualittb0a8a372014-09-23 09:50:21 -0700108 drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
bsalomon49f085d2014-09-05 13:34:00 -0700109 SkASSERT(fStrike);
bsalomon594069f2014-06-06 06:16:34 -0700110 switch (fStrike->getMaskFormat()) {
111 // Color bitmap text
112 case kARGB_GrMaskFormat:
113 SkASSERT(!drawState->hasColorVertexAttribute());
114 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
115 drawState->setColor(0xffffffff);
116 break;
117 // LCD text
118 case kA888_GrMaskFormat:
119 case kA565_GrMaskFormat: {
120 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
121 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
122 fPaint.numColorStages()) {
123 GrPrintf("LCD Text will not draw correctly.\n");
124 }
125 SkASSERT(!drawState->hasColorVertexAttribute());
126 // We don't use the GrPaint's color in this case because it's been premultiplied by
127 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
128 // the mask texture color. The end result is that we get
129 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
130 int a = SkColorGetA(fSkPaint.getColor());
131 // paintAlpha
132 drawState->setColor(SkColorSetARGB(a, a, a, a));
133 // paintColor
134 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
135 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
136 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000137 }
bsalomon594069f2014-06-06 06:16:34 -0700138 // Grayscale/BW text
139 case kA8_GrMaskFormat:
140 // set back to normal in case we took LCD path previously.
141 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
bsalomon594069f2014-06-06 06:16:34 -0700142 // We're using per-vertex color.
143 SkASSERT(drawState->hasColorVertexAttribute());
bsalomon594069f2014-06-06 06:16:34 -0700144 break;
145 default:
146 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000147 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000148 int nGlyphs = fCurrVertex / 4;
149 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
150 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
151 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000152 4, 6, &fVertexBounds);
Mike Klein6a25bd02014-08-29 10:03:59 -0400153
154 fDrawTarget->resetVertexSource();
155 fVertices = NULL;
156 fMaxVertices = 0;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000157 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000158 fVertexBounds.setLargestInverted();
Mike Klein6a25bd02014-08-29 10:03:59 -0400159 SkSafeSetNull(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000160 }
161}
162
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000163inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
164 GrTextContext::init(paint, skPaint);
165
166 fStrike = NULL;
167
Mike Klein6a25bd02014-08-29 10:03:59 -0400168 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -0700169 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -0400170
171 fVertices = NULL;
172 fMaxVertices = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000173}
174
175inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700176 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000177
178 GrTextContext::finish();
179}
180
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000181void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000182 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000183 SkScalar x, SkScalar y) {
184 SkASSERT(byteLength == 0 || text != NULL);
185
186 // nothing to draw
187 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
188 return;
189 }
190
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000191 this->init(paint, skPaint);
192
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000193 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
194
195 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
196 SkGlyphCache* cache = autoCache.getCache();
197 GrFontScaler* fontScaler = GetGrFontScaler(cache);
Mike Klein6a25bd02014-08-29 10:03:59 -0400198
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000199 // transform our starting point
200 {
201 SkPoint loc;
202 fContext->getMatrix().mapXY(x, y, &loc);
203 x = loc.fX;
204 y = loc.fY;
205 }
206
207 // need to measure first
208 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
209 SkVector stop;
210
211 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
212
213 SkScalar stopX = stop.fX;
214 SkScalar stopY = stop.fY;
215
216 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
217 stopX = SkScalarHalf(stopX);
218 stopY = SkScalarHalf(stopY);
219 }
220 x -= stopX;
221 y -= stopY;
222 }
223
224 const char* stop = text + byteLength;
225
Mike Klein6a25bd02014-08-29 10:03:59 -0400226 SkAutoKern autokern;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000227
228 SkFixed fxMask = ~0;
229 SkFixed fyMask = ~0;
230 SkFixed halfSampleX, halfSampleY;
231 if (cache->isSubpixel()) {
232 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
233 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
234 if (kX_SkAxisAlignment == baseline) {
235 fyMask = 0;
236 halfSampleY = SK_FixedHalf;
237 } else if (kY_SkAxisAlignment == baseline) {
238 fxMask = 0;
239 halfSampleX = SK_FixedHalf;
240 }
241 } else {
242 halfSampleX = halfSampleY = SK_FixedHalf;
243 }
244
245 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
246 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000247
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000248 GrContext::AutoMatrix autoMatrix;
249 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000250
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000251 while (text < stop) {
252 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
253
254 fx += autokern.adjust(glyph);
255
256 if (glyph.fWidth) {
257 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
258 glyph.getSubXFixed(),
259 glyph.getSubYFixed()),
260 SkFixedFloorToFixed(fx),
261 SkFixedFloorToFixed(fy),
262 fontScaler);
263 }
264
265 fx += glyph.fAdvanceX;
266 fy += glyph.fAdvanceY;
267 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000268
269 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000270}
271
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000272void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000273 const char text[], size_t byteLength,
fmalita05c4a432014-09-29 06:29:53 -0700274 const SkScalar pos[], int scalarsPerPosition,
275 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000276 SkASSERT(byteLength == 0 || text != NULL);
277 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
278
279 // nothing to draw
280 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
281 return;
282 }
283
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000284 this->init(paint, skPaint);
285
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000286 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
287
288 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
289 SkGlyphCache* cache = autoCache.getCache();
290 GrFontScaler* fontScaler = GetGrFontScaler(cache);
291
292 // store original matrix before we reset, so we can use it to transform positions
293 SkMatrix ctm = fContext->getMatrix();
294 GrContext::AutoMatrix autoMatrix;
295 autoMatrix.setIdentity(fContext, &fPaint);
296
297 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700298 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
fmalita05c4a432014-09-29 06:29:53 -0700299 SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000300 SkFixed halfSampleX = 0, halfSampleY = 0;
301
302 if (cache->isSubpixel()) {
303 // maybe we should skip the rounding if linearText is set
304 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
305
306 SkFixed fxMask = ~0;
307 SkFixed fyMask = ~0;
308 if (kX_SkAxisAlignment == baseline) {
309 fyMask = 0;
310#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
311 halfSampleY = SK_FixedHalf;
312#endif
313 } else if (kY_SkAxisAlignment == baseline) {
314 fxMask = 0;
315#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
316 halfSampleX = SK_FixedHalf;
317#endif
318 }
319
320 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
321 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700322 SkPoint tmsLoc;
323 tmsProc(pos, &tmsLoc);
324 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
325 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000326
327 const SkGlyph& glyph = glyphCacheProc(cache, &text,
328 fx & fxMask, fy & fyMask);
329
330 if (glyph.fWidth) {
331 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
332 glyph.getSubXFixed(),
333 glyph.getSubYFixed()),
334 SkFixedFloorToFixed(fx),
335 SkFixedFloorToFixed(fy),
336 fontScaler);
337 }
338 pos += scalarsPerPosition;
339 }
340 } else {
341 while (text < stop) {
342 const char* currentText = text;
343 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
344
345 if (metricGlyph.fWidth) {
346 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
347 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700348 SkPoint tmsLoc;
349 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000350 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700351 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000352
353 SkFixed fx = fixedLoc.fX + halfSampleX;
354 SkFixed fy = fixedLoc.fY + halfSampleY;
355
356 // have to call again, now that we've been "aligned"
357 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
358 fx & fxMask, fy & fyMask);
359 // the assumption is that the metrics haven't changed
360 SkASSERT(prevAdvX == glyph.fAdvanceX);
361 SkASSERT(prevAdvY == glyph.fAdvanceY);
362 SkASSERT(glyph.fWidth);
363
364 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
365 glyph.getSubXFixed(),
366 glyph.getSubYFixed()),
367 SkFixedFloorToFixed(fx),
368 SkFixedFloorToFixed(fy),
369 fontScaler);
370 }
371 pos += scalarsPerPosition;
372 }
373 }
374 } else { // not subpixel
375
376 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
377 while (text < stop) {
378 // the last 2 parameters are ignored
379 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
380
381 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700382 SkPoint tmsLoc;
383 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000384
kkinnunencb9a2c82014-06-12 23:06:28 -0700385 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
386 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000387 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
388 glyph.getSubXFixed(),
389 glyph.getSubYFixed()),
390 SkFixedFloorToFixed(fx),
391 SkFixedFloorToFixed(fy),
392 fontScaler);
393 }
394 pos += scalarsPerPosition;
395 }
396 } else {
397 while (text < stop) {
398 // the last 2 parameters are ignored
399 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
400
401 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700402 SkPoint tmsLoc;
403 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000404
405 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700406 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000407
408 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
409 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
410 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
411 glyph.getSubXFixed(),
412 glyph.getSubYFixed()),
413 SkFixedFloorToFixed(fx),
414 SkFixedFloorToFixed(fy),
415 fontScaler);
416 }
417 pos += scalarsPerPosition;
418 }
419 }
420 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000421
422 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000423}
424
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000425void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000426 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000427 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400428 if (NULL == fDrawTarget) {
429 return;
430 }
431
432 if (NULL == fStrike) {
433 fStrike = fContext->getFontCache()->getStrike(scaler, false);
434 }
435
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000436 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
437 if (NULL == glyph || glyph->fBounds.isEmpty()) {
438 return;
439 }
440
441 vx += SkIntToFixed(glyph->fBounds.fLeft);
442 vy += SkIntToFixed(glyph->fBounds.fTop);
443
444 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000445 SkFixed width = glyph->fBounds.width();
446 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000447
448 // check if we clipped out
449 if (true || NULL == glyph->fPlot) {
450 int x = vx >> 16;
451 int y = vy >> 16;
452 if (fClipRect.quickReject(x, y, x + width, y + height)) {
453// SkCLZ(3); // so we can set a break-point in the debugger
454 return;
455 }
456 }
457
458 if (NULL == glyph->fPlot) {
jvanverth681e65b2014-09-19 13:07:38 -0700459 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
460 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
461 goto HAS_ATLAS;
462 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000463
jvanverth681e65b2014-09-19 13:07:38 -0700464 // try to clear out an unused plot before we flush
465 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
466 fStrike->addGlyphToAtlas(glyph, scaler)) {
467 goto HAS_ATLAS;
468 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000469
jvanverth681e65b2014-09-19 13:07:38 -0700470 if (c_DumpFontCache) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000471#ifdef SK_DEVELOPER
jvanverth681e65b2014-09-19 13:07:38 -0700472 fContext->getFontCache()->dump();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000473#endif
jvanverth681e65b2014-09-19 13:07:38 -0700474 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000475
jvanverth681e65b2014-09-19 13:07:38 -0700476 // flush any accumulated draws to allow us to free up a plot
477 this->flushGlyphs();
478 fContext->flush();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000479
jvanverth681e65b2014-09-19 13:07:38 -0700480 // we should have an unused plot now
481 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
482 fStrike->addGlyphToAtlas(glyph, scaler)) {
483 goto HAS_ATLAS;
484 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000485 }
486
487 if (NULL == glyph->fPath) {
488 SkPath* path = SkNEW(SkPath);
489 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
490 // flag the glyph as being dead?
491 delete path;
492 return;
493 }
494 glyph->fPath = path;
495 }
496
497 GrContext::AutoMatrix am;
498 SkMatrix translate;
499 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
500 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
501 GrPaint tmpPaint(fPaint);
502 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700503 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
504 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000505 return;
506 }
507
508HAS_ATLAS:
509 SkASSERT(glyph->fPlot);
510 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
511 glyph->fPlot->setDrawToken(drawToken);
512
513 // now promote them to fixed (TODO: Rethink using fixed pt).
514 width = SkIntToFixed(width);
515 height = SkIntToFixed(height);
516
517 GrTexture* texture = glyph->fPlot->texture();
518 SkASSERT(texture);
519
Mike Klein6a25bd02014-08-29 10:03:59 -0400520 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
521 this->flushGlyphs();
522 fCurrTexture = texture;
523 fCurrTexture->ref();
524 }
525
526 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
527
528 if (NULL == fVertices) {
529 // If we need to reserve vertices allow the draw target to suggest
530 // a number of verts to reserve and whether to perform a flush.
531 fMaxVertices = kMinRequestedVerts;
532 if (useColorVerts) {
533 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
534 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
535 } else {
536 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
537 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
538 }
539 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
540 if (flush) {
541 this->flushGlyphs();
542 fContext->flush();
543 if (useColorVerts) {
544 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
545 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
546 } else {
547 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
548 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
549 }
550 }
551 fMaxVertices = kDefaultRequestedVerts;
552 // ignore return, no point in flushing again.
553 fDrawTarget->geometryHints(&fMaxVertices, NULL);
554
555 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
556 if (fMaxVertices < kMinRequestedVerts) {
557 fMaxVertices = kDefaultRequestedVerts;
558 } else if (fMaxVertices > maxQuadVertices) {
559 // don't exceed the limit of the index buffer
560 fMaxVertices = maxQuadVertices;
561 }
562 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
563 0,
564 &fVertices,
565 NULL);
566 GrAlwaysAssert(success);
567 }
568
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000569 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
570 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000571
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000572 SkRect r;
573 r.fLeft = SkFixedToFloat(vx);
574 r.fTop = SkFixedToFloat(vy);
575 r.fRight = SkFixedToFloat(vx + width);
576 r.fBottom = SkFixedToFloat(vy + height);
577
reed10d03272014-10-01 09:24:12 -0700578 fVertexBounds.joinNonEmptyArg(r);
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000579
bsalomon594069f2014-06-06 06:16:34 -0700580 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
581 (2 * sizeof(SkPoint));
582
egdaniel7b3d5ee2014-08-28 05:41:14 -0700583 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
bsalomon594069f2014-06-06 06:16:34 -0700584
585 SkPoint* positions = reinterpret_cast<SkPoint*>(
586 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
587 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
588
589 // The texture coords are last in both the with and without color vertex layouts.
590 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
591 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
bsalomonafbf2d62014-09-30 12:18:44 -0700592 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
593 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
594 SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
595 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
bsalomon594069f2014-06-06 06:16:34 -0700596 vertSize);
597 if (useColorVerts) {
bsalomon62c447d2014-08-08 08:08:50 -0700598 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
599 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
600 }
bsalomon594069f2014-06-06 06:16:34 -0700601 // color comes after position.
602 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
603 for (int i = 0; i < 4; ++i) {
604 *colors = fPaint.getColor();
605 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
606 }
607 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000608 fCurrVertex += 4;
609}