blob: 0c4d324d895b49ffb5236cfa86183830082a3229 [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)
djsollen2e1a8262014-08-27 13:12:25 -070054 : GrTextContext(context, properties) {
55 fStrike = NULL;
56
57 fCurrTexture = NULL;
58 fCurrVertex = 0;
59 fEffectTextureUniqueID = SK_InvalidUniqueID;
60
61 fVertices = NULL;
62 fMaxVertices = 0;
63
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000064 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000065}
66
67GrBitmapTextContext::~GrBitmapTextContext() {
68 this->flushGlyphs();
69}
70
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000071bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
72 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
73}
74
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000075static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
76 unsigned r = SkColorGetR(c);
77 unsigned g = SkColorGetG(c);
78 unsigned b = SkColorGetB(c);
79 return GrColorPackRGBA(r, g, b, 0xff);
80}
81
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000082void GrBitmapTextContext::flushGlyphs() {
83 if (NULL == fDrawTarget) {
84 return;
85 }
86
87 GrDrawState* drawState = fDrawTarget->drawState();
88 GrDrawState::AutoRestoreEffects are(drawState);
89 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
90
91 if (fCurrVertex > 0) {
92 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000093 SkASSERT(SkIsAlign4(fCurrVertex));
djsollen2e1a8262014-08-27 13:12:25 -070094 SkASSERT(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000095 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
96
djsollen2e1a8262014-08-27 13:12:25 -070097 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
bsalomon8b2fac42014-06-19 14:13:45 -070098
bsalomon1c63bf62014-07-22 13:09:46 -070099 if (textureUniqueID != fEffectTextureUniqueID) {
djsollen2e1a8262014-08-27 13:12:25 -0700100 fCachedEffect.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture, params));
bsalomon1c63bf62014-07-22 13:09:46 -0700101 fEffectTextureUniqueID = textureUniqueID;
bsalomon8b2fac42014-06-19 14:13:45 -0700102 }
103
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000104 // This effect could be stored with one of the cache objects (atlas?)
bsalomon594069f2014-06-06 06:16:34 -0700105 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
106 kGlyphCoordsNoColorAttributeIndex;
bsalomon8b2fac42014-06-19 14:13:45 -0700107 drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
bsalomon594069f2014-06-06 06:16:34 -0700108 SkASSERT(NULL != fStrike);
109 switch (fStrike->getMaskFormat()) {
110 // Color bitmap text
111 case kARGB_GrMaskFormat:
112 SkASSERT(!drawState->hasColorVertexAttribute());
113 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
114 drawState->setColor(0xffffffff);
115 break;
116 // LCD text
117 case kA888_GrMaskFormat:
118 case kA565_GrMaskFormat: {
119 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
120 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
121 fPaint.numColorStages()) {
122 GrPrintf("LCD Text will not draw correctly.\n");
123 }
124 SkASSERT(!drawState->hasColorVertexAttribute());
125 // We don't use the GrPaint's color in this case because it's been premultiplied by
126 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
127 // the mask texture color. The end result is that we get
128 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
129 int a = SkColorGetA(fSkPaint.getColor());
130 // paintAlpha
131 drawState->setColor(SkColorSetARGB(a, a, a, a));
132 // paintColor
133 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
134 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
135 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000136 }
bsalomon594069f2014-06-06 06:16:34 -0700137 // Grayscale/BW text
138 case kA8_GrMaskFormat:
139 // set back to normal in case we took LCD path previously.
140 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
bsalomon594069f2014-06-06 06:16:34 -0700141 // We're using per-vertex color.
142 SkASSERT(drawState->hasColorVertexAttribute());
bsalomon594069f2014-06-06 06:16:34 -0700143 break;
144 default:
145 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000146 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000147 int nGlyphs = fCurrVertex / 4;
148 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
149 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
150 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000151 4, 6, &fVertexBounds);
djsollen2e1a8262014-08-27 13:12:25 -0700152
153 fDrawTarget->resetVertexSource();
154 fVertices = NULL;
155 fMaxVertices = 0;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000156 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000157 fVertexBounds.setLargestInverted();
djsollen2e1a8262014-08-27 13:12:25 -0700158 SkSafeSetNull(fCurrTexture);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000159 }
160}
161
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000162inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
163 GrTextContext::init(paint, skPaint);
164
165 fStrike = NULL;
166
djsollen2e1a8262014-08-27 13:12:25 -0700167 fCurrTexture = NULL;
jvanverth9c3d24b2014-08-27 11:53:17 -0700168 fCurrVertex = 0;
djsollen2e1a8262014-08-27 13:12:25 -0700169
170 fVertices = NULL;
171 fMaxVertices = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000172}
173
174inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700175 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000176
177 GrTextContext::finish();
178}
179
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000180void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000181 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000182 SkScalar x, SkScalar y) {
183 SkASSERT(byteLength == 0 || text != NULL);
184
185 // nothing to draw
186 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
187 return;
188 }
189
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000190 this->init(paint, skPaint);
191
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000192 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
193
194 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
195 SkGlyphCache* cache = autoCache.getCache();
196 GrFontScaler* fontScaler = GetGrFontScaler(cache);
djsollen2e1a8262014-08-27 13:12:25 -0700197
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000198 // transform our starting point
199 {
200 SkPoint loc;
201 fContext->getMatrix().mapXY(x, y, &loc);
202 x = loc.fX;
203 y = loc.fY;
204 }
205
206 // need to measure first
207 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
208 SkVector stop;
209
210 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
211
212 SkScalar stopX = stop.fX;
213 SkScalar stopY = stop.fY;
214
215 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
216 stopX = SkScalarHalf(stopX);
217 stopY = SkScalarHalf(stopY);
218 }
219 x -= stopX;
220 y -= stopY;
221 }
222
223 const char* stop = text + byteLength;
224
djsollen2e1a8262014-08-27 13:12:25 -0700225 SkAutoKern autokern;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000226
227 SkFixed fxMask = ~0;
228 SkFixed fyMask = ~0;
229 SkFixed halfSampleX, halfSampleY;
230 if (cache->isSubpixel()) {
231 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
232 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
233 if (kX_SkAxisAlignment == baseline) {
234 fyMask = 0;
235 halfSampleY = SK_FixedHalf;
236 } else if (kY_SkAxisAlignment == baseline) {
237 fxMask = 0;
238 halfSampleX = SK_FixedHalf;
239 }
240 } else {
241 halfSampleX = halfSampleY = SK_FixedHalf;
242 }
243
244 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
245 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000246
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000247 GrContext::AutoMatrix autoMatrix;
248 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000249
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000250 while (text < stop) {
251 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
252
253 fx += autokern.adjust(glyph);
254
255 if (glyph.fWidth) {
256 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
257 glyph.getSubXFixed(),
258 glyph.getSubYFixed()),
259 SkFixedFloorToFixed(fx),
260 SkFixedFloorToFixed(fy),
261 fontScaler);
262 }
263
264 fx += glyph.fAdvanceX;
265 fy += glyph.fAdvanceY;
266 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000267
268 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000269}
270
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000271void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000272 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000273 const SkScalar pos[], SkScalar constY,
274 int scalarsPerPosition) {
275 SkASSERT(byteLength == 0 || text != NULL);
276 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
277
278 // nothing to draw
279 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
280 return;
281 }
282
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000283 this->init(paint, skPaint);
284
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000285 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
286
287 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
288 SkGlyphCache* cache = autoCache.getCache();
289 GrFontScaler* fontScaler = GetGrFontScaler(cache);
290
291 // store original matrix before we reset, so we can use it to transform positions
292 SkMatrix ctm = fContext->getMatrix();
293 GrContext::AutoMatrix autoMatrix;
294 autoMatrix.setIdentity(fContext, &fPaint);
295
296 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700297 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
298 SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000299 SkFixed halfSampleX = 0, halfSampleY = 0;
300
301 if (cache->isSubpixel()) {
302 // maybe we should skip the rounding if linearText is set
303 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
304
305 SkFixed fxMask = ~0;
306 SkFixed fyMask = ~0;
307 if (kX_SkAxisAlignment == baseline) {
308 fyMask = 0;
309#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
310 halfSampleY = SK_FixedHalf;
311#endif
312 } else if (kY_SkAxisAlignment == baseline) {
313 fxMask = 0;
314#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
315 halfSampleX = SK_FixedHalf;
316#endif
317 }
318
319 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
320 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700321 SkPoint tmsLoc;
322 tmsProc(pos, &tmsLoc);
323 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
324 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000325
326 const SkGlyph& glyph = glyphCacheProc(cache, &text,
327 fx & fxMask, fy & fyMask);
328
329 if (glyph.fWidth) {
330 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
331 glyph.getSubXFixed(),
332 glyph.getSubYFixed()),
333 SkFixedFloorToFixed(fx),
334 SkFixedFloorToFixed(fy),
335 fontScaler);
336 }
337 pos += scalarsPerPosition;
338 }
339 } else {
340 while (text < stop) {
341 const char* currentText = text;
342 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
343
344 if (metricGlyph.fWidth) {
345 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
346 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700347 SkPoint tmsLoc;
348 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000349 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700350 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000351
352 SkFixed fx = fixedLoc.fX + halfSampleX;
353 SkFixed fy = fixedLoc.fY + halfSampleY;
354
355 // have to call again, now that we've been "aligned"
356 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
357 fx & fxMask, fy & fyMask);
358 // the assumption is that the metrics haven't changed
359 SkASSERT(prevAdvX == glyph.fAdvanceX);
360 SkASSERT(prevAdvY == glyph.fAdvanceY);
361 SkASSERT(glyph.fWidth);
362
363 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
364 glyph.getSubXFixed(),
365 glyph.getSubYFixed()),
366 SkFixedFloorToFixed(fx),
367 SkFixedFloorToFixed(fy),
368 fontScaler);
369 }
370 pos += scalarsPerPosition;
371 }
372 }
373 } else { // not subpixel
374
375 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
376 while (text < stop) {
377 // the last 2 parameters are ignored
378 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
379
380 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700381 SkPoint tmsLoc;
382 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000383
kkinnunencb9a2c82014-06-12 23:06:28 -0700384 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
385 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000386 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
387 glyph.getSubXFixed(),
388 glyph.getSubYFixed()),
389 SkFixedFloorToFixed(fx),
390 SkFixedFloorToFixed(fy),
391 fontScaler);
392 }
393 pos += scalarsPerPosition;
394 }
395 } else {
396 while (text < stop) {
397 // the last 2 parameters are ignored
398 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
399
400 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700401 SkPoint tmsLoc;
402 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000403
404 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700405 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000406
407 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
408 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
409 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
410 glyph.getSubXFixed(),
411 glyph.getSubYFixed()),
412 SkFixedFloorToFixed(fx),
413 SkFixedFloorToFixed(fy),
414 fontScaler);
415 }
416 pos += scalarsPerPosition;
417 }
418 }
419 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000420
421 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000422}
423
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000424void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000425 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000426 GrFontScaler* scaler) {
djsollen2e1a8262014-08-27 13:12:25 -0700427 if (NULL == fDrawTarget) {
428 return;
429 }
430
431 if (NULL == fStrike) {
432 fStrike = fContext->getFontCache()->getStrike(scaler, false);
433 }
434
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000435 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
436 if (NULL == glyph || glyph->fBounds.isEmpty()) {
437 return;
438 }
439
440 vx += SkIntToFixed(glyph->fBounds.fLeft);
441 vy += SkIntToFixed(glyph->fBounds.fTop);
442
443 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000444 SkFixed width = glyph->fBounds.width();
445 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000446
447 // check if we clipped out
448 if (true || NULL == glyph->fPlot) {
449 int x = vx >> 16;
450 int y = vy >> 16;
451 if (fClipRect.quickReject(x, y, x + width, y + height)) {
452// SkCLZ(3); // so we can set a break-point in the debugger
453 return;
454 }
455 }
456
457 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000458 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000459 goto HAS_ATLAS;
460 }
461
462 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000463 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
464 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000465 goto HAS_ATLAS;
466 }
467
468 if (c_DumpFontCache) {
469#ifdef SK_DEVELOPER
470 fContext->getFontCache()->dump();
471#endif
472 }
473
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000474 // flush any accumulated draws to allow us to free up a plot
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000475 this->flushGlyphs();
476 fContext->flush();
477
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000478 // we should have an unused plot now
479 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
480 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000481 goto HAS_ATLAS;
482 }
483
484 if (NULL == glyph->fPath) {
485 SkPath* path = SkNEW(SkPath);
486 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
487 // flag the glyph as being dead?
488 delete path;
489 return;
490 }
491 glyph->fPath = path;
492 }
493
494 GrContext::AutoMatrix am;
495 SkMatrix translate;
496 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
497 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
498 GrPaint tmpPaint(fPaint);
499 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700500 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
501 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000502 return;
503 }
504
505HAS_ATLAS:
506 SkASSERT(glyph->fPlot);
507 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
508 glyph->fPlot->setDrawToken(drawToken);
509
510 // now promote them to fixed (TODO: Rethink using fixed pt).
511 width = SkIntToFixed(width);
512 height = SkIntToFixed(height);
513
514 GrTexture* texture = glyph->fPlot->texture();
515 SkASSERT(texture);
516
djsollen2e1a8262014-08-27 13:12:25 -0700517 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
518 this->flushGlyphs();
519 fCurrTexture = texture;
520 fCurrTexture->ref();
521 }
522
523 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
524
525 if (NULL == fVertices) {
526 // If we need to reserve vertices allow the draw target to suggest
527 // a number of verts to reserve and whether to perform a flush.
528 fMaxVertices = kMinRequestedVerts;
529 if (useColorVerts) {
530 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
531 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
532 } else {
533 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
534 SK_ARRAY_COUNT(gTextVertexAttribs));
535 }
536 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
537 if (flush) {
538 this->flushGlyphs();
539 fContext->flush();
540 if (useColorVerts) {
541 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
542 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
543 } else {
544 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
545 SK_ARRAY_COUNT(gTextVertexAttribs));
546 }
547 }
548 fMaxVertices = kDefaultRequestedVerts;
549 // ignore return, no point in flushing again.
550 fDrawTarget->geometryHints(&fMaxVertices, NULL);
551
552 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
553 if (fMaxVertices < kMinRequestedVerts) {
554 fMaxVertices = kDefaultRequestedVerts;
555 } else if (fMaxVertices > maxQuadVertices) {
556 // don't exceed the limit of the index buffer
557 fMaxVertices = maxQuadVertices;
558 }
559 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
560 0,
561 &fVertices,
562 NULL);
563 GrAlwaysAssert(success);
564 }
565
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000566 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
567 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000568
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000569 SkRect r;
570 r.fLeft = SkFixedToFloat(vx);
571 r.fTop = SkFixedToFloat(vy);
572 r.fRight = SkFixedToFloat(vx + width);
573 r.fBottom = SkFixedToFloat(vy + height);
574
575 fVertexBounds.growToInclude(r);
576
bsalomon594069f2014-06-06 06:16:34 -0700577 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
578 (2 * sizeof(SkPoint));
579
djsollenea81ced2014-08-27 13:07:34 -0700580 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
bsalomon594069f2014-06-06 06:16:34 -0700581
582 SkPoint* positions = reinterpret_cast<SkPoint*>(
583 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
584 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
585
586 // The texture coords are last in both the with and without color vertex layouts.
587 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
588 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
589 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
590 SkFixedToFloat(texture->normalizeFixedY(ty)),
591 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
592 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
593 vertSize);
594 if (useColorVerts) {
bsalomon62c447d2014-08-08 08:08:50 -0700595 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
596 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
597 }
bsalomon594069f2014-06-06 06:16:34 -0700598 // color comes after position.
599 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
600 for (int i = 0; i < 4; ++i) {
601 *colors = fPaint.getColor();
602 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
603 }
604 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000605 fCurrVertex += 4;
606}