blob: 488aa137e9a14f5c72033df5d74dedcea9d639ae [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"
13#include "GrTextStrike.h"
14#include "GrTextStrike_impl.h"
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000015#include "SkColorPriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000016#include "SkPath.h"
17#include "SkRTConf.h"
18#include "SkStrokeRec.h"
19#include "effects/GrCustomCoordsTextureEffect.h"
20
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000021#include "SkAutoKern.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000022#include "SkDraw.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000023#include "SkGlyphCache.h"
24#include "SkGpuDevice.h"
25#include "SkGr.h"
26
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000027static const int kGlyphCoordsAttributeIndex = 1;
28
29SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
30 "Dump the contents of the font cache before every purge.");
31
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000032bool GrBitmapTextContext::CanDraw(const SkPaint& paint, const SkMatrix& ctm) {
33 return !SkDraw::ShouldDrawTextAsPaths(paint, ctm);
34}
35
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000036GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000037 const GrPaint& grPaint,
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000038 const SkPaint& skPaint,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000039 const SkDeviceProperties& properties)
40 : GrTextContext(context, grPaint, skPaint, properties) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000041 fStrike = NULL;
42
43 fCurrTexture = NULL;
44 fCurrVertex = 0;
45
46 fVertices = NULL;
47 fMaxVertices = 0;
48}
49
50GrBitmapTextContext::~GrBitmapTextContext() {
51 this->flushGlyphs();
52}
53
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000054static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
55 unsigned r = SkColorGetR(c);
56 unsigned g = SkColorGetG(c);
57 unsigned b = SkColorGetB(c);
58 return GrColorPackRGBA(r, g, b, 0xff);
59}
60
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000061void GrBitmapTextContext::flushGlyphs() {
62 if (NULL == fDrawTarget) {
63 return;
64 }
65
66 GrDrawState* drawState = fDrawTarget->drawState();
67 GrDrawState::AutoRestoreEffects are(drawState);
68 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
69
70 if (fCurrVertex > 0) {
71 // setup our sampler state for our text texture/atlas
72 SkASSERT(GrIsALIGN4(fCurrVertex));
73 SkASSERT(fCurrTexture);
74 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
75
76 // This effect could be stored with one of the cache objects (atlas?)
77 drawState->addCoverageEffect(
78 GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
79 kGlyphCoordsAttributeIndex)->unref();
80
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +000081 if (NULL != fStrike && kARGB_GrMaskFormat == fStrike->getMaskFormat()) {
82 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
83 drawState->setColor(0xffffffff);
84 } else if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000085 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
86 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
87 fPaint.numColorStages()) {
88 GrPrintf("LCD Text will not draw correctly.\n");
89 }
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000090 // We don't use the GrPaint's color in this case because it's been premultiplied by
91 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
skia.committer@gmail.com70402c32013-10-29 07:01:50 +000092 // the mask texture color. The end result is that we get
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000093 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.orgcc40f062014-01-24 14:38:27 +000094 int a = SkColorGetA(fSkPaint.getColor());
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000095 // paintAlpha
96 drawState->setColor(SkColorSetARGB(a, a, a, a));
97 // paintColor
commit-bot@chromium.orgcc40f062014-01-24 14:38:27 +000098 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000099 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000100 } else {
101 // set back to normal in case we took LCD path previously.
102 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
103 drawState->setColor(fPaint.getColor());
104 }
105
106 int nGlyphs = fCurrVertex / 4;
107 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
108 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
109 nGlyphs,
110 4, 6);
commit-bot@chromium.org42a89572013-10-28 15:13:50 +0000111
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000112 fDrawTarget->resetVertexSource();
113 fVertices = NULL;
114 fMaxVertices = 0;
115 fCurrVertex = 0;
116 SkSafeSetNull(fCurrTexture);
117 }
118}
119
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000120void GrBitmapTextContext::drawText(const char text[], size_t byteLength,
121 SkScalar x, SkScalar y) {
122 SkASSERT(byteLength == 0 || text != NULL);
123
124 // nothing to draw
125 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
126 return;
127 }
128
129 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
130
131 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
132 SkGlyphCache* cache = autoCache.getCache();
133 GrFontScaler* fontScaler = GetGrFontScaler(cache);
134
135 // transform our starting point
136 {
137 SkPoint loc;
138 fContext->getMatrix().mapXY(x, y, &loc);
139 x = loc.fX;
140 y = loc.fY;
141 }
142
143 // need to measure first
144 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
145 SkVector stop;
146
147 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
148
149 SkScalar stopX = stop.fX;
150 SkScalar stopY = stop.fY;
151
152 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
153 stopX = SkScalarHalf(stopX);
154 stopY = SkScalarHalf(stopY);
155 }
156 x -= stopX;
157 y -= stopY;
158 }
159
160 const char* stop = text + byteLength;
161
162 SkAutoKern autokern;
163
164 SkFixed fxMask = ~0;
165 SkFixed fyMask = ~0;
166 SkFixed halfSampleX, halfSampleY;
167 if (cache->isSubpixel()) {
168 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
169 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
170 if (kX_SkAxisAlignment == baseline) {
171 fyMask = 0;
172 halfSampleY = SK_FixedHalf;
173 } else if (kY_SkAxisAlignment == baseline) {
174 fxMask = 0;
175 halfSampleX = SK_FixedHalf;
176 }
177 } else {
178 halfSampleX = halfSampleY = SK_FixedHalf;
179 }
180
181 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
182 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000183
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000184 GrContext::AutoMatrix autoMatrix;
185 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000186
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000187 while (text < stop) {
188 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
189
190 fx += autokern.adjust(glyph);
191
192 if (glyph.fWidth) {
193 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
194 glyph.getSubXFixed(),
195 glyph.getSubYFixed()),
196 SkFixedFloorToFixed(fx),
197 SkFixedFloorToFixed(fy),
198 fontScaler);
199 }
200
201 fx += glyph.fAdvanceX;
202 fy += glyph.fAdvanceY;
203 }
204}
205
206///////////////////////////////////////////////////////////////////////////////
207// Copied from SkDraw
208
209// last parameter is interpreted as SkFixed [x, y]
210// return the fixed position, which may be rounded or not by the caller
211// e.g. subpixel doesn't round
212typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
213
214static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
215 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
216}
217
218static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
219 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
220 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
221}
222
223static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
224 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
225 SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
226}
227
228static AlignProc pick_align_proc(SkPaint::Align align) {
229 static const AlignProc gProcs[] = {
230 leftAlignProc, centerAlignProc, rightAlignProc
231 };
232
233 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
234
235 return gProcs[align];
236}
237
238class BitmapTextMapState {
239public:
240 mutable SkPoint fLoc;
241
242 BitmapTextMapState(const SkMatrix& matrix, SkScalar y)
243 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
244
245 typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]);
246
247 Proc pickProc(int scalarsPerPosition);
248
249private:
250 const SkMatrix& fMatrix;
251 SkMatrix::MapXYProc fProc;
252 SkScalar fY; // ignored by MapXYProc
253 // these are only used by Only... procs
254 SkScalar fScaleX, fTransX, fTransformedY;
255
256 static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) {
257 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
258 }
259
260 static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) {
261 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
262 }
263
264 static void MapOnlyScaleXProc(const BitmapTextMapState& state,
265 const SkScalar pos[]) {
266 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
267 state.fTransformedY);
268 }
269
270 static void MapOnlyTransXProc(const BitmapTextMapState& state,
271 const SkScalar pos[]) {
272 state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
273 }
274};
275
276BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) {
277 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
278
279 if (1 == scalarsPerPosition) {
280 unsigned mtype = fMatrix.getType();
281 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
282 return MapXProc;
283 } else {
284 fScaleX = fMatrix.getScaleX();
285 fTransX = fMatrix.getTranslateX();
286 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
287 fMatrix.getTranslateY();
288 return (mtype & SkMatrix::kScale_Mask) ?
289 MapOnlyScaleXProc : MapOnlyTransXProc;
290 }
291 } else {
292 return MapXYProc;
293 }
294}
295
296///////////////////////////////////////////////////////////////////////////////
297
298void GrBitmapTextContext::drawPosText(const char text[], size_t byteLength,
299 const SkScalar pos[], SkScalar constY,
300 int scalarsPerPosition) {
301 SkASSERT(byteLength == 0 || text != NULL);
302 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
303
304 // nothing to draw
305 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
306 return;
307 }
308
309 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
310
311 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
312 SkGlyphCache* cache = autoCache.getCache();
313 GrFontScaler* fontScaler = GetGrFontScaler(cache);
314
315 // store original matrix before we reset, so we can use it to transform positions
316 SkMatrix ctm = fContext->getMatrix();
317 GrContext::AutoMatrix autoMatrix;
318 autoMatrix.setIdentity(fContext, &fPaint);
319
320 const char* stop = text + byteLength;
321 AlignProc alignProc = pick_align_proc(fSkPaint.getTextAlign());
322 BitmapTextMapState tms(ctm, constY);
323 BitmapTextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
324 SkFixed halfSampleX = 0, halfSampleY = 0;
325
326 if (cache->isSubpixel()) {
327 // maybe we should skip the rounding if linearText is set
328 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
329
330 SkFixed fxMask = ~0;
331 SkFixed fyMask = ~0;
332 if (kX_SkAxisAlignment == baseline) {
333 fyMask = 0;
334#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
335 halfSampleY = SK_FixedHalf;
336#endif
337 } else if (kY_SkAxisAlignment == baseline) {
338 fxMask = 0;
339#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
340 halfSampleX = SK_FixedHalf;
341#endif
342 }
343
344 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
345 while (text < stop) {
346 tmsProc(tms, pos);
347 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + halfSampleX;
348 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + halfSampleY;
349
350 const SkGlyph& glyph = glyphCacheProc(cache, &text,
351 fx & fxMask, fy & fyMask);
352
353 if (glyph.fWidth) {
354 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
355 glyph.getSubXFixed(),
356 glyph.getSubYFixed()),
357 SkFixedFloorToFixed(fx),
358 SkFixedFloorToFixed(fy),
359 fontScaler);
360 }
361 pos += scalarsPerPosition;
362 }
363 } else {
364 while (text < stop) {
365 const char* currentText = text;
366 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
367
368 if (metricGlyph.fWidth) {
369 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
370 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
371
372 tmsProc(tms, pos);
373 SkIPoint fixedLoc;
374 alignProc(tms.fLoc, metricGlyph, &fixedLoc);
375
376 SkFixed fx = fixedLoc.fX + halfSampleX;
377 SkFixed fy = fixedLoc.fY + halfSampleY;
378
379 // have to call again, now that we've been "aligned"
380 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
381 fx & fxMask, fy & fyMask);
382 // the assumption is that the metrics haven't changed
383 SkASSERT(prevAdvX == glyph.fAdvanceX);
384 SkASSERT(prevAdvY == glyph.fAdvanceY);
385 SkASSERT(glyph.fWidth);
386
387 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 }
397 } else { // not subpixel
398
399 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
400 while (text < stop) {
401 // the last 2 parameters are ignored
402 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
403
404 if (glyph.fWidth) {
405 tmsProc(tms, pos);
406
407 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf; //halfSampleX;
408 SkFixed fy = SkScalarToFixed(tms.fLoc.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 } else {
419 while (text < stop) {
420 // the last 2 parameters are ignored
421 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
422
423 if (glyph.fWidth) {
424 tmsProc(tms, pos);
425
426 SkIPoint fixedLoc;
427 alignProc(tms.fLoc, glyph, &fixedLoc);
428
429 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
430 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
431 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
432 glyph.getSubXFixed(),
433 glyph.getSubYFixed()),
434 SkFixedFloorToFixed(fx),
435 SkFixedFloorToFixed(fy),
436 fontScaler);
437 }
438 pos += scalarsPerPosition;
439 }
440 }
441 }
442}
443
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000444namespace {
445
446// position + texture coord
447extern const GrVertexAttrib gTextVertexAttribs[] = {
448 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
449 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
450};
451
452};
453
454void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
455 GrFixed vx, GrFixed vy,
456 GrFontScaler* scaler) {
457 if (NULL == fDrawTarget) {
458 return;
459 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000460
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000461 if (NULL == fStrike) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000462#if SK_DISTANCEFIELD_FONTS
commit-bot@chromium.org75a22952013-11-21 15:09:33 +0000463 fStrike = fContext->getFontCache()->getStrike(scaler, false);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000464#else
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000465 fStrike = fContext->getFontCache()->getStrike(scaler);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000466#endif
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000467 }
468
469 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
470 if (NULL == glyph || glyph->fBounds.isEmpty()) {
471 return;
472 }
473
474 vx += SkIntToFixed(glyph->fBounds.fLeft);
475 vy += SkIntToFixed(glyph->fBounds.fTop);
476
477 // keep them as ints until we've done the clip-test
478 GrFixed width = glyph->fBounds.width();
479 GrFixed height = glyph->fBounds.height();
480
481 // check if we clipped out
482 if (true || NULL == glyph->fPlot) {
483 int x = vx >> 16;
484 int y = vy >> 16;
485 if (fClipRect.quickReject(x, y, x + width, y + height)) {
486// SkCLZ(3); // so we can set a break-point in the debugger
487 return;
488 }
489 }
490
491 if (NULL == glyph->fPlot) {
492 if (fStrike->getGlyphAtlas(glyph, scaler)) {
493 goto HAS_ATLAS;
494 }
495
496 // try to clear out an unused plot before we flush
497 fContext->getFontCache()->freePlotExceptFor(fStrike);
498 if (fStrike->getGlyphAtlas(glyph, scaler)) {
499 goto HAS_ATLAS;
500 }
501
502 if (c_DumpFontCache) {
503#ifdef SK_DEVELOPER
504 fContext->getFontCache()->dump();
505#endif
506 }
507
508 // before we purge the cache, we must flush any accumulated draws
509 this->flushGlyphs();
510 fContext->flush();
511
512 // try to purge
513 fContext->getFontCache()->purgeExceptFor(fStrike);
514 // need to use new flush count here
515 if (fStrike->getGlyphAtlas(glyph, scaler)) {
516 goto HAS_ATLAS;
517 }
518
519 if (NULL == glyph->fPath) {
520 SkPath* path = SkNEW(SkPath);
521 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
522 // flag the glyph as being dead?
523 delete path;
524 return;
525 }
526 glyph->fPath = path;
527 }
528
529 GrContext::AutoMatrix am;
530 SkMatrix translate;
531 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
532 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
533 GrPaint tmpPaint(fPaint);
534 am.setPreConcat(fContext, translate, &tmpPaint);
535 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
536 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
537 return;
538 }
539
540HAS_ATLAS:
541 SkASSERT(glyph->fPlot);
542 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
543 glyph->fPlot->setDrawToken(drawToken);
544
545 // now promote them to fixed (TODO: Rethink using fixed pt).
546 width = SkIntToFixed(width);
547 height = SkIntToFixed(height);
548
549 GrTexture* texture = glyph->fPlot->texture();
550 SkASSERT(texture);
551
552 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
553 this->flushGlyphs();
554 fCurrTexture = texture;
555 fCurrTexture->ref();
556 }
557
558 if (NULL == fVertices) {
559 // If we need to reserve vertices allow the draw target to suggest
560 // a number of verts to reserve and whether to perform a flush.
561 fMaxVertices = kMinRequestedVerts;
562 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
563 SK_ARRAY_COUNT(gTextVertexAttribs));
564 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
565 if (flush) {
566 this->flushGlyphs();
567 fContext->flush();
568 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
569 SK_ARRAY_COUNT(gTextVertexAttribs));
570 }
571 fMaxVertices = kDefaultRequestedVerts;
572 // ignore return, no point in flushing again.
573 fDrawTarget->geometryHints(&fMaxVertices, NULL);
574
575 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
576 if (fMaxVertices < kMinRequestedVerts) {
577 fMaxVertices = kDefaultRequestedVerts;
578 } else if (fMaxVertices > maxQuadVertices) {
579 // don't exceed the limit of the index buffer
580 fMaxVertices = maxQuadVertices;
581 }
582 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
583 0,
584 GrTCast<void**>(&fVertices),
585 NULL);
586 GrAlwaysAssert(success);
587 SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
588 }
589
590 GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
591 GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
592
593 fVertices[2*fCurrVertex].setRectFan(SkFixedToFloat(vx),
594 SkFixedToFloat(vy),
595 SkFixedToFloat(vx + width),
596 SkFixedToFloat(vy + height),
597 2 * sizeof(SkPoint));
598 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
599 SkFixedToFloat(texture->normalizeFixedY(ty)),
600 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
601 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
602 2 * sizeof(SkPoint));
603 fCurrVertex += 4;
604}