Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrDistanceFieldTextContext.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 "GrDistanceFieldTextContext.h"
9 #include "GrAtlas.h"
10 #include "SkColorFilter.h"
11 #include "GrDrawTarget.h"
12 #include "GrDrawTargetCaps.h"
13 #include "GrFontScaler.h"
14 #include "SkGlyphCache.h"
15 #include "GrGpu.h"
16 #include "GrIndexBuffer.h"
17 #include "GrStrokeInfo.h"
18 #include "GrTextStrike.h"
19 #include "GrTextStrike_impl.h"
20 #include "SkDistanceFieldGen.h"
21 #include "SkDraw.h"
22 #include "SkGpuDevice.h"
23 #include "SkPath.h"
24 #include "SkRTConf.h"
25 #include "SkStrokeRec.h"
26 #include "effects/GrDistanceFieldTextureEffect.h"
27
28 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
29                 "Dump the contents of the font cache before every purge.");
30
31 static const int kGlyphCoordsNoColorAttributeIndex = 1;
32 static const int kGlyphCoordsWithColorAttributeIndex = 2;
33
34 static const int kSmallDFFontSize = 32;
35 static const int kSmallDFFontLimit = 32;
36 static const int kMediumDFFontSize = 64;
37 static const int kMediumDFFontLimit = 64;
38 static const int kLargeDFFontSize = 128;
39
40 namespace {
41 // position + texture coord
42 extern const GrVertexAttrib gTextVertexAttribs[] = {
43     {kVec2f_GrVertexAttribType, 0,                kPosition_GrVertexAttribBinding},
44     {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
45 };
46
47 // position + color + texture coord
48 extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
49     {kVec2f_GrVertexAttribType,  0,                                 kPosition_GrVertexAttribBinding},
50     {kVec4ub_GrVertexAttribType, sizeof(SkPoint),                   kColor_GrVertexAttribBinding},
51     {kVec2f_GrVertexAttribType,  sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
52 };
53     
54 };
55
56 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
57                                                        const SkDeviceProperties& properties,
58                                                        bool enable)
59                                                     : GrTextContext(context, properties) {
60 #if SK_FORCE_DISTANCEFIELD_FONTS
61     fEnableDFRendering = true;
62 #else
63     fEnableDFRendering = enable;
64 #endif
65     fStrike = NULL;
66     fGammaTexture = NULL;
67
68     fCurrTexture = NULL;
69     fCurrVertex = 0;
70     fEffectTextureUniqueID = SK_InvalidUniqueID;
71     fEffectColor = GrColor_ILLEGAL;
72     fEffectFlags = 0;
73
74     fVertices = NULL;
75     fMaxVertices = 0;
76
77     fVertexBounds.setLargestInverted();
78 }
79
80 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
81     this->flushGlyphs();
82     SkSafeSetNull(fGammaTexture);
83 }
84
85 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
86     if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
87         return false;
88     }
89
90     // rasterizers and mask filters modify alpha, which doesn't
91     // translate well to distance
92     if (paint.getRasterizer() || paint.getMaskFilter() ||
93         !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
94         return false;
95     }
96
97     // TODO: add some stroking support
98     if (paint.getStyle() != SkPaint::kFill_Style) {
99         return false;
100     }
101
102     // TODO: choose an appropriate maximum scale for distance fields and
103     //       enable perspective
104     if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
105         return false;
106     }
107
108     // distance fields cannot represent color fonts
109     SkScalerContext::Rec    rec;
110     SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
111     return rec.getFormat() != SkMask::kARGB32_Format;
112 }
113
114 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
115     unsigned r = SkColorGetR(c);
116     unsigned g = SkColorGetG(c);
117     unsigned b = SkColorGetB(c);
118     return GrColorPackRGBA(r, g, b, 0xff);
119 }
120
121 void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColor) {
122     GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
123     GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
124     
125     uint32_t textureUniqueID = fCurrTexture->getUniqueID();
126     
127     // set up any flags
128     uint32_t flags = 0;
129     flags |= fContext->getMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
130     flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
131     flags |= fUseLCDText && fContext->getMatrix().rectStaysRect() ?
132     kRectToRect_DistanceFieldEffectFlag : 0;
133     bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
134     fDeviceProperties.fGeometry.getLayout();
135     flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
136     
137     // see if we need to create a new effect
138     if (textureUniqueID != fEffectTextureUniqueID ||
139         filteredColor != fEffectColor ||
140         flags != fEffectFlags) {
141         if (fUseLCDText) {
142             GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
143             fCachedEffect.reset(GrDistanceFieldLCDTextureEffect::Create(fCurrTexture,
144                                                                         params,
145                                                                         fGammaTexture,
146                                                                         gammaParams,
147                                                                         colorNoPreMul,
148                                                                         flags));
149         } else {
150 #ifdef SK_GAMMA_APPLY_TO_A8
151             U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
152                                                                 filteredColor);
153             fCachedEffect.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
154                                                                      params,
155                                                                      fGammaTexture,
156                                                                      gammaParams,
157                                                                      lum/255.f,
158                                                                      flags));
159 #else
160             fCachedEffect.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
161                                                                      params, flags));
162 #endif
163         }
164         fEffectTextureUniqueID = textureUniqueID;
165         fEffectColor = filteredColor;
166         fEffectFlags = flags;
167     }
168     
169 }
170
171 void GrDistanceFieldTextContext::flushGlyphs() {
172     if (NULL == fDrawTarget) {
173         return;
174     }
175
176     GrDrawState* drawState = fDrawTarget->drawState();
177     GrDrawState::AutoRestoreEffects are(drawState);
178     drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
179
180     if (fCurrVertex > 0) {
181         // setup our sampler state for our text texture/atlas
182         SkASSERT(SkIsAlign4(fCurrVertex));
183
184         // get our current color
185         SkColor filteredColor;
186         SkColorFilter* colorFilter = fSkPaint.getColorFilter();
187         if (NULL != colorFilter) {
188             filteredColor = colorFilter->filterColor(fSkPaint.getColor());
189         } else {
190             filteredColor = fSkPaint.getColor();
191         }
192         this->setupCoverageEffect(filteredColor);
193        
194         // Effects could be stored with one of the cache objects (atlas?)
195         int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
196                                                                kGlyphCoordsNoColorAttributeIndex;
197         drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
198         
199         // Set draw state
200         if (fUseLCDText) {
201             GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
202             if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
203                 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
204                 fPaint.numColorStages()) {
205                 GrPrintf("LCD Text will not draw correctly.\n");
206             }
207             SkASSERT(!drawState->hasColorVertexAttribute());
208             // We don't use the GrPaint's color in this case because it's been premultiplied by
209             // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
210             // the mask texture color. The end result is that we get
211             //            mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
212             int a = SkColorGetA(fSkPaint.getColor());
213             // paintAlpha
214             drawState->setColor(SkColorSetARGB(a, a, a, a));
215             // paintColor
216             drawState->setBlendConstant(colorNoPreMul);
217             drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
218         } else {
219             // set back to normal in case we took LCD path previously.
220             drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
221             // We're using per-vertex color.
222             SkASSERT(drawState->hasColorVertexAttribute());
223         }
224         int nGlyphs = fCurrVertex / 4;
225         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
226         fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
227                                           nGlyphs,
228                                           4, 6, &fVertexBounds);
229         fDrawTarget->resetVertexSource();
230         fVertices = NULL;
231         fMaxVertices = 0;
232         fCurrVertex = 0;
233         SkSafeSetNull(fCurrTexture);
234         fVertexBounds.setLargestInverted();
235     }
236 }
237
238 void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
239                                                  SkFixed vx, SkFixed vy,
240                                                  GrFontScaler* scaler) {
241     if (NULL == fDrawTarget) {
242         return;
243     }
244     
245     if (NULL == fStrike) {
246         fStrike = fContext->getFontCache()->getStrike(scaler, true);
247     }
248     
249     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
250     if (NULL == glyph || glyph->fBounds.isEmpty()) {
251         return;
252     }
253
254     SkScalar sx = SkFixedToScalar(vx);
255     SkScalar sy = SkFixedToScalar(vy);
256 /*
257     // not valid, need to find a different solution for this
258     vx += SkIntToFixed(glyph->fBounds.fLeft);
259     vy += SkIntToFixed(glyph->fBounds.fTop);
260
261     // keep them as ints until we've done the clip-test
262     GrFixed width = glyph->fBounds.width();
263     GrFixed height = glyph->fBounds.height();
264
265     // check if we clipped out
266     if (true || NULL == glyph->fPlot) {
267         int x = vx >> 16;
268         int y = vy >> 16;
269         if (fClipRect.quickReject(x, y, x + width, y + height)) {
270 //            SkCLZ(3);    // so we can set a break-point in the debugger
271             return;
272         }
273     }
274 */
275     if (NULL == glyph->fPlot) {
276         if (fStrike->addGlyphToAtlas(glyph, scaler)) {
277             goto HAS_ATLAS;
278         }
279
280         // try to clear out an unused plot before we flush
281         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
282             fStrike->addGlyphToAtlas(glyph, scaler)) {
283             goto HAS_ATLAS;
284         }
285
286         if (c_DumpFontCache) {
287 #ifdef SK_DEVELOPER
288             fContext->getFontCache()->dump();
289 #endif
290         }
291
292         // before we purge the cache, we must flush any accumulated draws
293         this->flushGlyphs();
294         fContext->flush();
295
296         // we should have an unused plot now
297         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
298             fStrike->addGlyphToAtlas(glyph, scaler)) {
299             goto HAS_ATLAS;
300         }
301
302         if (NULL == glyph->fPath) {
303             SkPath* path = SkNEW(SkPath);
304             if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
305                 // flag the glyph as being dead?
306                 delete path;
307                 return;
308             }
309             glyph->fPath = path;
310         }
311
312         GrContext::AutoMatrix am;
313         SkMatrix ctm;
314         ctm.setScale(fTextRatio, fTextRatio);
315         ctm.postTranslate(sx, sy);
316         GrPaint tmpPaint(fPaint);
317         am.setPreConcat(fContext, ctm, &tmpPaint);
318         GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
319         fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
320         return;
321     }
322
323 HAS_ATLAS:
324     SkASSERT(glyph->fPlot);
325     GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
326     glyph->fPlot->setDrawToken(drawToken);
327
328     GrTexture* texture = glyph->fPlot->texture();
329     SkASSERT(texture);
330
331     if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
332         this->flushGlyphs();
333         fCurrTexture = texture;
334         fCurrTexture->ref();
335     }
336
337     bool useColorVerts = !fUseLCDText;
338     
339     if (NULL == fVertices) {
340         // If we need to reserve vertices allow the draw target to suggest
341         // a number of verts to reserve and whether to perform a flush.
342         fMaxVertices = kMinRequestedVerts;
343         if (useColorVerts) {
344             fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
345                                                     SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
346         } else {
347             fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
348                                                     SK_ARRAY_COUNT(gTextVertexAttribs));
349         }
350         bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
351         if (flush) {
352             this->flushGlyphs();
353             fContext->flush();
354             if (useColorVerts) {
355                 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
356                                                     SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
357             } else {
358                 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
359                                                     SK_ARRAY_COUNT(gTextVertexAttribs));
360             }
361         }
362         fMaxVertices = kDefaultRequestedVerts;
363         // ignore return, no point in flushing again.
364         fDrawTarget->geometryHints(&fMaxVertices, NULL);
365         
366         int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
367         if (fMaxVertices < kMinRequestedVerts) {
368             fMaxVertices = kDefaultRequestedVerts;
369         } else if (fMaxVertices > maxQuadVertices) {
370             // don't exceed the limit of the index buffer
371             fMaxVertices = maxQuadVertices;
372         }
373         bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
374                                                                0,
375                                                                &fVertices,
376                                                                NULL);
377         GrAlwaysAssert(success);
378     }
379     
380     SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
381     SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
382     SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
383     SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
384
385     SkScalar scale = fTextRatio;
386     dx *= scale;
387     dy *= scale;
388     sx += dx;
389     sy += dy;
390     width *= scale;
391     height *= scale;
392     
393     SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
394     SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
395     SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
396     SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
397
398     SkRect r;
399     r.fLeft = sx;
400     r.fTop = sy;
401     r.fRight = sx + width;
402     r.fBottom = sy + height;
403
404     fVertexBounds.growToInclude(r);
405
406     size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint))
407                                   : (2 * sizeof(SkPoint) + sizeof(GrColor));
408
409     SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
410
411     SkPoint* positions = reinterpret_cast<SkPoint*>(
412         reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
413     positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
414
415     // The texture coords are last in both the with and without color vertex layouts.
416     SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
417             reinterpret_cast<intptr_t>(positions) + vertSize  - sizeof(SkPoint));
418     textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
419                               SkFixedToFloat(texture->normalizeFixedY(ty)),
420                               SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
421                               SkFixedToFloat(texture->normalizeFixedY(ty + th)),
422                               vertSize);
423     if (useColorVerts) {
424         if (0xFF == GrColorUnpackA(fPaint.getColor())) {
425             fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
426         }
427         // color comes after position.
428         GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
429         for (int i = 0; i < 4; ++i) {
430             *colors = fPaint.getColor();
431             colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
432         }
433     }
434
435     fCurrVertex += 4;
436 }
437
438 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
439     GrTextContext::init(paint, skPaint);
440
441     fStrike = NULL;
442
443     fCurrVertex = 0;
444
445     fVertices = NULL;
446
447     if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
448         fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
449         fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
450     } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
451         fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
452         fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
453     } else {
454         fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
455         fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
456     }
457
458     fUseLCDText = fSkPaint.isLCDRenderText();
459
460     fSkPaint.setLCDRenderText(false);
461     fSkPaint.setAutohinted(false);
462     fSkPaint.setHinting(SkPaint::kNormal_Hinting);
463     fSkPaint.setSubpixelText(true);
464
465 }
466
467 inline void GrDistanceFieldTextContext::finish() {
468     this->flushGlyphs();
469
470     GrTextContext::finish();
471 }
472
473 static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
474                                 const SkDeviceProperties& deviceProperties,
475                                 GrTexture** gammaTexture) {
476     if (NULL == *gammaTexture) {
477         int width, height;
478         size_t size;
479
480 #ifdef SK_GAMMA_CONTRAST
481         SkScalar contrast = SK_GAMMA_CONTRAST;
482 #else
483         SkScalar contrast = 0.5f;
484 #endif
485         SkScalar paintGamma = deviceProperties.fGamma;
486         SkScalar deviceGamma = deviceProperties.fGamma;
487
488         size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
489                                                 &width, &height);
490
491         SkAutoTArray<uint8_t> data((int)size);
492         SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
493
494         // TODO: Update this to use the cache rather than directly creating a texture.
495         GrTextureDesc desc;
496         desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
497         desc.fWidth = width;
498         desc.fHeight = height;
499         desc.fConfig = kAlpha_8_GrPixelConfig;
500
501         *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
502         if (NULL == *gammaTexture) {
503             return;
504         }
505
506         context->writeTexturePixels(*gammaTexture,
507                                     0, 0, width, height,
508                                     (*gammaTexture)->config(), data.get(), 0,
509                                     GrContext::kDontFlush_PixelOpsFlag);
510     }
511 }
512
513 void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
514                                           const char text[], size_t byteLength,
515                                           SkScalar x, SkScalar y) {
516     SkASSERT(byteLength == 0 || text != NULL);
517
518     // nothing to draw or can't draw
519     if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
520         || fSkPaint.getRasterizer()) {
521         return;
522     }
523
524     this->init(paint, skPaint);
525
526     SkScalar sizeRatio = fTextRatio;
527
528     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
529
530     SkAutoGlyphCacheNoGamma    autoCache(fSkPaint, &fDeviceProperties, NULL);
531     SkGlyphCache*              cache = autoCache.getCache();
532     GrFontScaler*              fontScaler = GetGrFontScaler(cache);
533
534     setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
535
536     // need to measure first
537     // TODO - generate positions and pre-load cache as well?
538     const char* stop = text + byteLength;
539     if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
540         SkFixed    stopX = 0;
541         SkFixed    stopY = 0;
542
543         const char* textPtr = text;
544         while (textPtr < stop) {
545             // don't need x, y here, since all subpixel variants will have the
546             // same advance
547             const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
548
549             stopX += glyph.fAdvanceX;
550             stopY += glyph.fAdvanceY;
551         }
552         SkASSERT(textPtr == stop);
553
554         SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
555         SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
556
557         if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
558             alignX = SkScalarHalf(alignX);
559             alignY = SkScalarHalf(alignY);
560         }
561
562         x -= alignX;
563         y -= alignY;
564     }
565
566     SkFixed fx = SkScalarToFixed(x);
567     SkFixed fy = SkScalarToFixed(y);
568     SkFixed fixedScale = SkScalarToFixed(sizeRatio);
569     while (text < stop) {
570         const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
571
572         if (glyph.fWidth) {
573             this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
574                                                 glyph.getSubXFixed(),
575                                                 glyph.getSubYFixed()),
576                                   fx,
577                                   fy,
578                                   fontScaler);
579         }
580
581         fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
582         fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
583     }
584
585     this->finish();
586 }
587
588 void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
589                                              const char text[], size_t byteLength,
590                                              const SkScalar pos[], SkScalar constY,
591                                              int scalarsPerPosition) {
592
593     SkASSERT(byteLength == 0 || text != NULL);
594     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
595
596     // nothing to draw
597     if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
598         return;
599     }
600
601     this->init(paint, skPaint);
602
603     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
604
605     SkAutoGlyphCacheNoGamma    autoCache(fSkPaint, &fDeviceProperties, NULL);
606     SkGlyphCache*              cache = autoCache.getCache();
607     GrFontScaler*              fontScaler = GetGrFontScaler(cache);
608
609     setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
610
611     const char*        stop = text + byteLength;
612
613     if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
614         while (text < stop) {
615             // the last 2 parameters are ignored
616             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
617
618             if (glyph.fWidth) {
619                 SkScalar x = pos[0];
620                 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
621
622                 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
623                                                     glyph.getSubXFixed(),
624                                                     glyph.getSubYFixed()),
625                                       SkScalarToFixed(x),
626                                       SkScalarToFixed(y),
627                                       fontScaler);
628             }
629             pos += scalarsPerPosition;
630         }
631     } else {
632         int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
633         while (text < stop) {
634             // the last 2 parameters are ignored
635             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
636
637             if (glyph.fWidth) {
638                 SkScalar x = pos[0];
639                 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
640
641                 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
642                                                     glyph.getSubXFixed(),
643                                                     glyph.getSubYFixed()),
644                                       SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
645                                       SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
646                                       fontScaler);
647             }
648             pos += scalarsPerPosition;
649         }
650     }
651
652     this->finish();
653 }