Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrBitmapTextContext.cpp
1 /*
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 "GrStrokeInfo.h"
14 #include "GrTexturePriv.h"
15 #include "GrTextStrike.h"
16 #include "GrTextStrike_impl.h"
17 #include "effects/GrCustomCoordsTextureEffect.h"
18 #include "effects/GrSimpleTextureEffect.h"
19
20 #include "SkAutoKern.h"
21 #include "SkColorPriv.h"
22 #include "SkDraw.h"
23 #include "SkDrawProcs.h"
24 #include "SkGlyphCache.h"
25 #include "SkGpuDevice.h"
26 #include "SkGr.h"
27 #include "SkPath.h"
28 #include "SkRTConf.h"
29 #include "SkStrokeRec.h"
30 #include "SkTextMapStateProc.h"
31
32 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
33                 "Dump the contents of the font cache before every purge.");
34
35 namespace {
36 // position + texture coord
37 extern const GrVertexAttrib gLCDVertexAttribs[] = {
38     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
39     {kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
40 };
41
42 static const size_t kLCDTextVASize = 2 * sizeof(SkPoint);
43
44 // position + local coord
45 extern const GrVertexAttrib gColorVertexAttribs[] = {
46     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
47     {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}
48 };
49
50 static const size_t kColorTextVASize = 2 * sizeof(SkPoint);
51
52 // position + color + texture coord
53 extern const GrVertexAttrib gGrayVertexAttribs[] = {
54     {kVec2f_GrVertexAttribType,  0,                                 kPosition_GrVertexAttribBinding},
55     {kVec4ub_GrVertexAttribType, sizeof(SkPoint),                   kColor_GrVertexAttribBinding},
56     {kVec2f_GrVertexAttribType,  sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
57 };
58
59 static const size_t kGrayTextVASize = 2 * sizeof(SkPoint) + sizeof(GrColor);
60
61 static const int kVerticesPerGlyph = 4;
62 static const int kIndicesPerGlyph = 6;
63 };
64
65 GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
66                                          const SkDeviceProperties& properties)
67                                        : GrTextContext(context, properties) {
68     fStrike = NULL;
69
70     fCurrTexture = NULL;
71     fEffectTextureUniqueID = SK_InvalidUniqueID;
72
73     fVertices = NULL;
74     fCurrVertex = 0;
75     fAllocVertexCount = 0;
76     fTotalVertexCount = 0;
77
78     fVertexBounds.setLargestInverted();
79 }
80
81 GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context,
82                                                  const SkDeviceProperties& props) {
83     return SkNEW_ARGS(GrBitmapTextContext, (context, props));
84 }
85
86 GrBitmapTextContext::~GrBitmapTextContext() {
87     this->finish();
88 }
89
90 bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
91     return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
92 }
93
94 inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
95     GrTextContext::init(paint, skPaint);
96
97     fStrike = NULL;
98
99     fCurrTexture = NULL;
100     fCurrVertex = 0;
101
102     fVertices = NULL;
103     fAllocVertexCount = 0;
104     fTotalVertexCount = 0;
105 }
106
107 void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
108                                    const char text[], size_t byteLength,
109                                    SkScalar x, SkScalar y) {
110     SkASSERT(byteLength == 0 || text != NULL);
111
112     // nothing to draw
113     if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
114         return;
115     }
116
117     this->init(paint, skPaint);
118
119     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
120
121     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
122     SkGlyphCache*       cache = autoCache.getCache();
123     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
124
125     // transform our starting point
126     {
127         SkPoint loc;
128         fContext->getMatrix().mapXY(x, y, &loc);
129         x = loc.fX;
130         y = loc.fY;
131     }
132
133     // need to measure first
134     int numGlyphs;
135     if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
136         SkVector    stopVector;
137         numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
138
139         SkScalar    stopX = stopVector.fX;
140         SkScalar    stopY = stopVector.fY;
141
142         if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
143             stopX = SkScalarHalf(stopX);
144             stopY = SkScalarHalf(stopY);
145         }
146         x -= stopX;
147         y -= stopY;
148     } else {
149         numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
150     }
151     fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
152
153     const char* stop = text + byteLength;
154
155     SkAutoKern autokern;
156
157     SkFixed fxMask = ~0;
158     SkFixed fyMask = ~0;
159     SkFixed halfSampleX, halfSampleY;
160     if (cache->isSubpixel()) {
161         halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
162         SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
163         if (kX_SkAxisAlignment == baseline) {
164             fyMask = 0;
165             halfSampleY = SK_FixedHalf;
166         } else if (kY_SkAxisAlignment == baseline) {
167             fxMask = 0;
168             halfSampleX = SK_FixedHalf;
169         }
170     } else {
171         halfSampleX = halfSampleY = SK_FixedHalf;
172     }
173
174     SkFixed fx = SkScalarToFixed(x) + halfSampleX;
175     SkFixed fy = SkScalarToFixed(y) + halfSampleY;
176
177     GrContext::AutoMatrix  autoMatrix;
178     autoMatrix.setIdentity(fContext, &fPaint);
179
180     while (text < stop) {
181         const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
182
183         fx += autokern.adjust(glyph);
184
185         if (glyph.fWidth) {
186             this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
187                                             glyph.getSubXFixed(),
188                                             glyph.getSubYFixed()),
189                               SkFixedFloorToFixed(fx),
190                               SkFixedFloorToFixed(fy),
191                               fontScaler);
192         }
193
194         fx += glyph.fAdvanceX;
195         fy += glyph.fAdvanceY;
196     }
197
198     this->finish();
199 }
200
201 void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
202                                       const char text[], size_t byteLength,
203                                       const SkScalar pos[], int scalarsPerPosition,
204                                       const SkPoint& offset) {
205     SkASSERT(byteLength == 0 || text != NULL);
206     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
207
208     // nothing to draw
209     if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
210         return;
211     }
212
213     this->init(paint, skPaint);
214
215     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
216
217     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
218     SkGlyphCache*       cache = autoCache.getCache();
219     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
220
221     // store original matrix before we reset, so we can use it to transform positions
222     SkMatrix ctm = fContext->getMatrix();
223     GrContext::AutoMatrix  autoMatrix;
224     autoMatrix.setIdentity(fContext, &fPaint);
225
226     int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
227     fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
228
229     const char*        stop = text + byteLength;
230     SkTextAlignProc    alignProc(fSkPaint.getTextAlign());
231     SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
232     SkFixed halfSampleX = 0, halfSampleY = 0;
233
234     if (cache->isSubpixel()) {
235         // maybe we should skip the rounding if linearText is set
236         SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
237
238         SkFixed fxMask = ~0;
239         SkFixed fyMask = ~0;
240         if (kX_SkAxisAlignment == baseline) {
241             fyMask = 0;
242 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
243             halfSampleY = SK_FixedHalf;
244 #endif
245         } else if (kY_SkAxisAlignment == baseline) {
246             fxMask = 0;
247 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
248             halfSampleX = SK_FixedHalf;
249 #endif
250         }
251
252         if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
253             while (text < stop) {
254                 SkPoint tmsLoc;
255                 tmsProc(pos, &tmsLoc);
256                 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
257                 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
258
259                 const SkGlyph& glyph = glyphCacheProc(cache, &text,
260                                                       fx & fxMask, fy & fyMask);
261
262                 if (glyph.fWidth) {
263                     this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
264                                                     glyph.getSubXFixed(),
265                                                     glyph.getSubYFixed()),
266                                       SkFixedFloorToFixed(fx),
267                                       SkFixedFloorToFixed(fy),
268                                       fontScaler);
269                 }
270                 pos += scalarsPerPosition;
271             }
272         } else {
273             while (text < stop) {
274                 const char* currentText = text;
275                 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
276
277                 if (metricGlyph.fWidth) {
278                     SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
279                     SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
280                     SkPoint tmsLoc;
281                     tmsProc(pos, &tmsLoc);
282                     SkIPoint fixedLoc;
283                     alignProc(tmsLoc, metricGlyph, &fixedLoc);
284
285                     SkFixed fx = fixedLoc.fX + halfSampleX;
286                     SkFixed fy = fixedLoc.fY + halfSampleY;
287
288                     // have to call again, now that we've been "aligned"
289                     const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
290                                                           fx & fxMask, fy & fyMask);
291                     // the assumption is that the metrics haven't changed
292                     SkASSERT(prevAdvX == glyph.fAdvanceX);
293                     SkASSERT(prevAdvY == glyph.fAdvanceY);
294                     SkASSERT(glyph.fWidth);
295
296                     this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
297                                                     glyph.getSubXFixed(),
298                                                     glyph.getSubYFixed()),
299                                       SkFixedFloorToFixed(fx),
300                                       SkFixedFloorToFixed(fy),
301                                       fontScaler);
302                 }
303                 pos += scalarsPerPosition;
304             }
305         }
306     } else {    // not subpixel
307
308         if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
309             while (text < stop) {
310                 // the last 2 parameters are ignored
311                 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
312
313                 if (glyph.fWidth) {
314                     SkPoint tmsLoc;
315                     tmsProc(pos, &tmsLoc);
316
317                     SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
318                     SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
319                     this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
320                                                     glyph.getSubXFixed(),
321                                                     glyph.getSubYFixed()),
322                                       SkFixedFloorToFixed(fx),
323                                       SkFixedFloorToFixed(fy),
324                                       fontScaler);
325                 }
326                 pos += scalarsPerPosition;
327             }
328         } else {
329             while (text < stop) {
330                 // the last 2 parameters are ignored
331                 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
332
333                 if (glyph.fWidth) {
334                     SkPoint tmsLoc;
335                     tmsProc(pos, &tmsLoc);
336
337                     SkIPoint fixedLoc;
338                     alignProc(tmsLoc, glyph, &fixedLoc);
339
340                     SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
341                     SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
342                     this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
343                                                     glyph.getSubXFixed(),
344                                                     glyph.getSubYFixed()),
345                                       SkFixedFloorToFixed(fx),
346                                       SkFixedFloorToFixed(fy),
347                                       fontScaler);
348                 }
349                 pos += scalarsPerPosition;
350             }
351         }
352     }
353
354     this->finish();
355 }
356
357 static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, GrMaskFormat maskFormat) {
358     if (numVertices <= 0) {
359         return NULL;
360     }
361
362     // set up attributes
363     if (kA8_GrMaskFormat == maskFormat) {
364         drawTarget->drawState()->setVertexAttribs<gGrayVertexAttribs>(
365                                     SK_ARRAY_COUNT(gGrayVertexAttribs), kGrayTextVASize);
366     } else if (kARGB_GrMaskFormat == maskFormat) {
367         drawTarget->drawState()->setVertexAttribs<gColorVertexAttribs>(
368                                     SK_ARRAY_COUNT(gColorVertexAttribs), kColorTextVASize);
369     } else {
370         drawTarget->drawState()->setVertexAttribs<gLCDVertexAttribs>(
371                                     SK_ARRAY_COUNT(gLCDVertexAttribs), kLCDTextVASize);
372     }
373     void* vertices = NULL;
374     bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
375                                                           0,
376                                                           &vertices,
377                                                           NULL);
378     GrAlwaysAssert(success);
379     return vertices;
380 }
381
382 void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
383                                       SkFixed vx, SkFixed vy,
384                                       GrFontScaler* scaler) {
385     if (NULL == fDrawTarget) {
386         return;
387     }
388
389     if (NULL == fStrike) {
390         fStrike = fContext->getFontCache()->getStrike(scaler, false);
391     }
392
393     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
394     if (NULL == glyph || glyph->fBounds.isEmpty()) {
395         return;
396     }
397
398     vx += SkIntToFixed(glyph->fBounds.fLeft);
399     vy += SkIntToFixed(glyph->fBounds.fTop);
400
401     // keep them as ints until we've done the clip-test
402     SkFixed width = glyph->fBounds.width();
403     SkFixed height = glyph->fBounds.height();
404
405     // check if we clipped out
406     if (true || NULL == glyph->fPlot) {
407         int x = vx >> 16;
408         int y = vy >> 16;
409         if (fClipRect.quickReject(x, y, x + width, y + height)) {
410 //            SkCLZ(3);    // so we can set a break-point in the debugger
411             return;
412         }
413     }
414
415     if (NULL == glyph->fPlot) {
416         if (!fStrike->glyphTooLargeForAtlas(glyph)) {
417             if (fStrike->addGlyphToAtlas(glyph, scaler)) {
418                 goto HAS_ATLAS;
419             }
420
421             // try to clear out an unused plot before we flush
422             if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
423                 fStrike->addGlyphToAtlas(glyph, scaler)) {
424                 goto HAS_ATLAS;
425             }
426
427             if (c_DumpFontCache) {
428 #ifdef SK_DEVELOPER
429                 fContext->getFontCache()->dump();
430 #endif
431             }
432
433             // flush any accumulated draws to allow us to free up a plot
434             this->flush();
435             fContext->flush();
436
437             // we should have an unused plot now
438             if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
439                 fStrike->addGlyphToAtlas(glyph, scaler)) {
440                 goto HAS_ATLAS;
441             }
442         }
443
444         if (NULL == glyph->fPath) {
445             SkPath* path = SkNEW(SkPath);
446             if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
447                 // flag the glyph as being dead?
448                 delete path;
449                 return;
450             }
451             glyph->fPath = path;
452         }
453
454         // flush any accumulated draws before drawing this glyph as a path.
455         this->flush();
456
457         GrContext::AutoMatrix am;
458         SkMatrix translate;
459         translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
460                                SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
461         GrPaint tmpPaint(fPaint);
462         am.setPreConcat(fContext, translate, &tmpPaint);
463         GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
464         fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
465
466         // remove this glyph from the vertices we need to allocate
467         fTotalVertexCount -= kVerticesPerGlyph;
468         return;
469     }
470
471 HAS_ATLAS:
472     SkASSERT(glyph->fPlot);
473     GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
474     glyph->fPlot->setDrawToken(drawToken);
475
476     // now promote them to fixed (TODO: Rethink using fixed pt).
477     width = SkIntToFixed(width);
478     height = SkIntToFixed(height);
479
480     // the current texture/maskformat must match what the glyph needs
481     GrTexture* texture = glyph->fPlot->texture();
482     SkASSERT(texture);
483
484     if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
485         this->flush();
486         fCurrTexture = texture;
487         fCurrTexture->ref();
488         fCurrMaskFormat = glyph->fMaskFormat;
489     }
490
491     if (NULL == fVertices) {
492         int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
493         fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
494         fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
495     }
496
497     SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
498     SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
499
500     SkRect r;
501     r.fLeft = SkFixedToFloat(vx);
502     r.fTop = SkFixedToFloat(vy);
503     r.fRight = SkFixedToFloat(vx + width);
504     r.fBottom = SkFixedToFloat(vy + height);
505
506     fVertexBounds.joinNonEmptyArg(r);
507
508     size_t vertSize;
509     switch (fCurrMaskFormat) {
510         case kA8_GrMaskFormat:
511             vertSize = kGrayTextVASize;
512             break;
513         case kARGB_GrMaskFormat:
514             vertSize = kColorTextVASize;
515         default:
516             vertSize = kLCDTextVASize;
517     }
518
519     SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
520
521     SkPoint* positions = reinterpret_cast<SkPoint*>(
522         reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
523     positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
524
525     // The texture coords are last in both the with and without color vertex layouts.
526     SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
527             reinterpret_cast<intptr_t>(positions) + vertSize  - sizeof(SkPoint));
528     textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
529                               SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
530                               SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
531                               SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
532                               vertSize);
533     if (kA8_GrMaskFormat == fCurrMaskFormat) {
534         if (0xFF == GrColorUnpackA(fPaint.getColor())) {
535             fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
536         }
537         // color comes after position.
538         GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
539         for (int i = 0; i < 4; ++i) {
540            *colors = fPaint.getColor();
541            colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
542         }
543     }
544     fCurrVertex += 4;
545 }
546
547 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
548     unsigned r = SkColorGetR(c);
549     unsigned g = SkColorGetG(c);
550     unsigned b = SkColorGetB(c);
551     return GrColorPackRGBA(r, g, b, 0xff);
552 }
553
554 void GrBitmapTextContext::flush() {
555     if (NULL == fDrawTarget) {
556         return;
557     }
558
559     GrDrawState* drawState = fDrawTarget->drawState();
560     GrDrawState::AutoRestoreEffects are(drawState);
561     drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
562
563     if (fCurrVertex > 0) {
564         // setup our sampler state for our text texture/atlas
565         SkASSERT(SkIsAlign4(fCurrVertex));
566         SkASSERT(fCurrTexture);
567         GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
568
569         // This effect could be stored with one of the cache objects (atlas?)
570         if (kARGB_GrMaskFormat == fCurrMaskFormat) {
571             GrFragmentProcessor* fragProcessor = GrSimpleTextureEffect::Create(fCurrTexture,
572                                                                                SkMatrix::I(),
573                                                                                params);
574             drawState->addColorProcessor(fragProcessor)->unref();
575         } else {
576             uint32_t textureUniqueID = fCurrTexture->getUniqueID();
577             if (textureUniqueID != fEffectTextureUniqueID) {
578                 fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
579                                                                                    params));
580                 fEffectTextureUniqueID = textureUniqueID;
581             }
582
583             drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
584         }
585
586         SkASSERT(fStrike);
587         switch (fCurrMaskFormat) {
588                 // Color bitmap text
589             case kARGB_GrMaskFormat:
590                 SkASSERT(!drawState->hasColorVertexAttribute());
591                 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
592                 drawState->setAlpha(fSkPaint.getAlpha());
593                 break;
594                 // LCD text
595             case kA888_GrMaskFormat:
596             case kA565_GrMaskFormat: {
597                 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
598                     kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
599                     fPaint.numColorStages()) {
600                     SkDebugf("LCD Text will not draw correctly.\n");
601                 }
602                 SkASSERT(!drawState->hasColorVertexAttribute());
603                 // We don't use the GrPaint's color in this case because it's been premultiplied by
604                 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
605                 // the mask texture color. The end result is that we get
606                 //            mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
607                 int a = SkColorGetA(fSkPaint.getColor());
608                 // paintAlpha
609                 drawState->setColor(SkColorSetARGB(a, a, a, a));
610                 // paintColor
611                 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
612                 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
613                 break;
614             }
615                 // Grayscale/BW text
616             case kA8_GrMaskFormat:
617                 // set back to normal in case we took LCD path previously.
618                 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
619                 // We're using per-vertex color.
620                 SkASSERT(drawState->hasColorVertexAttribute());
621                 break;
622             default:
623                 SkFAIL("Unexpected mask format.");
624         }
625         int nGlyphs = fCurrVertex / kVerticesPerGlyph;
626         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
627         fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
628                                           nGlyphs,
629                                           kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds);
630
631         fDrawTarget->resetVertexSource();
632         fVertices = NULL;
633         fAllocVertexCount = 0;
634         // reset to be those that are left
635         fTotalVertexCount -= fCurrVertex;
636         fCurrVertex = 0;
637         fVertexBounds.setLargestInverted();
638         SkSafeSetNull(fCurrTexture);
639     }
640 }
641
642 inline void GrBitmapTextContext::finish() {
643     this->flush();
644     fTotalVertexCount = 0;
645
646     GrTextContext::finish();
647 }
648