Upstream version 7.36.149.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 "GrTextStrike.h"
14 #include "GrTextStrike_impl.h"
15 #include "SkColorPriv.h"
16 #include "SkPath.h"
17 #include "SkRTConf.h"
18 #include "SkStrokeRec.h"
19 #include "effects/GrCustomCoordsTextureEffect.h"
20
21 #include "SkAutoKern.h"
22 #include "SkDraw.h"
23 #include "SkGlyphCache.h"
24 #include "SkGpuDevice.h"
25 #include "SkGr.h"
26
27 static const int kGlyphCoordsAttributeIndex = 1;
28
29 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
30                 "Dump the contents of the font cache before every purge.");
31
32 GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
33                                          const SkDeviceProperties& properties)
34                                        : GrTextContext(context, properties) {
35     fStrike = NULL;
36
37     fCurrTexture = NULL;
38     fCurrVertex = 0;
39
40     fVertices = NULL;
41     fMaxVertices = 0;
42
43     fVertexBounds.setLargestInverted();
44 }
45
46 GrBitmapTextContext::~GrBitmapTextContext() {
47     this->flushGlyphs();
48 }
49
50 bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
51     return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
52 }
53
54 static 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
61 void 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(SkIsAlign4(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
81         if (NULL != fStrike && kARGB_GrMaskFormat == fStrike->getMaskFormat()) {
82             drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
83             drawState->setColor(0xffffffff);
84         } else if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
85             if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
86                 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
87                 fPaint.numColorStages()) {
88                 GrPrintf("LCD Text will not draw correctly.\n");
89             }
90             // 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
92             // the mask texture color. The end result is that we get
93             //            mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
94             int a = SkColorGetA(fSkPaint.getColor());
95             // paintAlpha
96             drawState->setColor(SkColorSetARGB(a, a, a, a));
97             // paintColor
98             drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
99             drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
100         } 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, &fVertexBounds);
111
112         fDrawTarget->resetVertexSource();
113         fVertices = NULL;
114         fMaxVertices = 0;
115         fCurrVertex = 0;
116         fVertexBounds.setLargestInverted();
117         SkSafeSetNull(fCurrTexture);
118     }
119 }
120
121 inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
122     GrTextContext::init(paint, skPaint);
123
124     fStrike = NULL;
125
126     fCurrTexture = NULL;
127     fCurrVertex = 0;
128
129     fVertices = NULL;
130     fMaxVertices = 0;
131 }
132
133 inline void GrBitmapTextContext::finish() {
134     flushGlyphs();
135
136     GrTextContext::finish();
137 }
138
139 void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
140                                    const char text[], size_t byteLength,
141                                    SkScalar x, SkScalar y) {
142     SkASSERT(byteLength == 0 || text != NULL);
143
144     // nothing to draw
145     if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
146         return;
147     }
148
149     this->init(paint, skPaint);
150
151     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
152
153     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
154     SkGlyphCache*       cache = autoCache.getCache();
155     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
156
157     // transform our starting point
158     {
159         SkPoint loc;
160         fContext->getMatrix().mapXY(x, y, &loc);
161         x = loc.fX;
162         y = loc.fY;
163     }
164
165     // need to measure first
166     if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
167         SkVector    stop;
168
169         MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
170
171         SkScalar    stopX = stop.fX;
172         SkScalar    stopY = stop.fY;
173
174         if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
175             stopX = SkScalarHalf(stopX);
176             stopY = SkScalarHalf(stopY);
177         }
178         x -= stopX;
179         y -= stopY;
180     }
181
182     const char* stop = text + byteLength;
183
184     SkAutoKern autokern;
185
186     SkFixed fxMask = ~0;
187     SkFixed fyMask = ~0;
188     SkFixed halfSampleX, halfSampleY;
189     if (cache->isSubpixel()) {
190         halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
191         SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
192         if (kX_SkAxisAlignment == baseline) {
193             fyMask = 0;
194             halfSampleY = SK_FixedHalf;
195         } else if (kY_SkAxisAlignment == baseline) {
196             fxMask = 0;
197             halfSampleX = SK_FixedHalf;
198         }
199     } else {
200         halfSampleX = halfSampleY = SK_FixedHalf;
201     }
202
203     SkFixed fx = SkScalarToFixed(x) + halfSampleX;
204     SkFixed fy = SkScalarToFixed(y) + halfSampleY;
205
206     GrContext::AutoMatrix  autoMatrix;
207     autoMatrix.setIdentity(fContext, &fPaint);
208
209     while (text < stop) {
210         const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
211
212         fx += autokern.adjust(glyph);
213
214         if (glyph.fWidth) {
215             this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
216                                           glyph.getSubXFixed(),
217                                           glyph.getSubYFixed()),
218                                   SkFixedFloorToFixed(fx),
219                                   SkFixedFloorToFixed(fy),
220                                   fontScaler);
221         }
222
223         fx += glyph.fAdvanceX;
224         fy += glyph.fAdvanceY;
225     }
226
227     this->finish();
228 }
229
230 ///////////////////////////////////////////////////////////////////////////////
231 // Copied from SkDraw
232
233 // last parameter is interpreted as SkFixed [x, y]
234 // return the fixed position, which may be rounded or not by the caller
235 //   e.g. subpixel doesn't round
236 typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
237
238 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
239     dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
240 }
241
242 static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
243     dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
244              SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
245 }
246
247 static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
248     dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
249              SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
250 }
251
252 static AlignProc pick_align_proc(SkPaint::Align align) {
253     static const AlignProc gProcs[] = {
254         leftAlignProc, centerAlignProc, rightAlignProc
255     };
256
257     SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
258
259     return gProcs[align];
260 }
261
262 class BitmapTextMapState {
263 public:
264     mutable SkPoint fLoc;
265
266     BitmapTextMapState(const SkMatrix& matrix, SkScalar y)
267         : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
268
269     typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]);
270
271     Proc pickProc(int scalarsPerPosition);
272
273 private:
274     const SkMatrix&     fMatrix;
275     SkMatrix::MapXYProc fProc;
276     SkScalar            fY; // ignored by MapXYProc
277     // these are only used by Only... procs
278     SkScalar            fScaleX, fTransX, fTransformedY;
279
280     static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) {
281         state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
282     }
283
284     static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) {
285         state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
286     }
287
288     static void MapOnlyScaleXProc(const BitmapTextMapState& state,
289                                   const SkScalar pos[]) {
290         state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
291                        state.fTransformedY);
292     }
293
294     static void MapOnlyTransXProc(const BitmapTextMapState& state,
295                                   const SkScalar pos[]) {
296         state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
297     }
298 };
299
300 BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) {
301     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
302
303     if (1 == scalarsPerPosition) {
304         unsigned mtype = fMatrix.getType();
305         if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
306             return MapXProc;
307         } else {
308             fScaleX = fMatrix.getScaleX();
309             fTransX = fMatrix.getTranslateX();
310             fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
311                             fMatrix.getTranslateY();
312             return (mtype & SkMatrix::kScale_Mask) ?
313                         MapOnlyScaleXProc : MapOnlyTransXProc;
314         }
315     } else {
316         return MapXYProc;
317     }
318 }
319
320 ///////////////////////////////////////////////////////////////////////////////
321
322 void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
323                                       const char text[], size_t byteLength,
324                                       const SkScalar pos[], SkScalar constY,
325                                       int scalarsPerPosition) {
326     SkASSERT(byteLength == 0 || text != NULL);
327     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
328
329     // nothing to draw
330     if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
331         return;
332     }
333
334     this->init(paint, skPaint);
335
336     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
337
338     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
339     SkGlyphCache*       cache = autoCache.getCache();
340     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
341
342     // store original matrix before we reset, so we can use it to transform positions
343     SkMatrix ctm = fContext->getMatrix();
344     GrContext::AutoMatrix  autoMatrix;
345     autoMatrix.setIdentity(fContext, &fPaint);
346
347     const char*        stop = text + byteLength;
348     AlignProc          alignProc = pick_align_proc(fSkPaint.getTextAlign());
349     BitmapTextMapState       tms(ctm, constY);
350     BitmapTextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
351     SkFixed halfSampleX = 0, halfSampleY = 0;
352
353     if (cache->isSubpixel()) {
354         // maybe we should skip the rounding if linearText is set
355         SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
356
357         SkFixed fxMask = ~0;
358         SkFixed fyMask = ~0;
359         if (kX_SkAxisAlignment == baseline) {
360             fyMask = 0;
361 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
362             halfSampleY = SK_FixedHalf;
363 #endif
364         } else if (kY_SkAxisAlignment == baseline) {
365             fxMask = 0;
366 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
367             halfSampleX = SK_FixedHalf;
368 #endif
369         }
370
371         if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
372             while (text < stop) {
373                 tmsProc(tms, pos);
374                 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + halfSampleX;
375                 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + halfSampleY;
376
377                 const SkGlyph& glyph = glyphCacheProc(cache, &text,
378                                                       fx & fxMask, fy & fyMask);
379
380                 if (glyph.fWidth) {
381                     this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
382                                                         glyph.getSubXFixed(),
383                                                         glyph.getSubYFixed()),
384                                           SkFixedFloorToFixed(fx),
385                                           SkFixedFloorToFixed(fy),
386                                           fontScaler);
387                 }
388                 pos += scalarsPerPosition;
389             }
390         } else {
391             while (text < stop) {
392                 const char* currentText = text;
393                 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
394
395                 if (metricGlyph.fWidth) {
396                     SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
397                     SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
398
399                     tmsProc(tms, pos);
400                     SkIPoint fixedLoc;
401                     alignProc(tms.fLoc, metricGlyph, &fixedLoc);
402
403                     SkFixed fx = fixedLoc.fX + halfSampleX;
404                     SkFixed fy = fixedLoc.fY + halfSampleY;
405
406                     // have to call again, now that we've been "aligned"
407                     const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
408                                                           fx & fxMask, fy & fyMask);
409                     // the assumption is that the metrics haven't changed
410                     SkASSERT(prevAdvX == glyph.fAdvanceX);
411                     SkASSERT(prevAdvY == glyph.fAdvanceY);
412                     SkASSERT(glyph.fWidth);
413
414                     this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
415                                                         glyph.getSubXFixed(),
416                                                         glyph.getSubYFixed()),
417                                           SkFixedFloorToFixed(fx),
418                                           SkFixedFloorToFixed(fy),
419                                           fontScaler);
420                 }
421                 pos += scalarsPerPosition;
422             }
423         }
424     } else {    // not subpixel
425
426         if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
427             while (text < stop) {
428                 // the last 2 parameters are ignored
429                 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
430
431                 if (glyph.fWidth) {
432                     tmsProc(tms, pos);
433
434                     SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf; //halfSampleX;
435                     SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf; //halfSampleY;
436                     this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
437                                                         glyph.getSubXFixed(),
438                                                         glyph.getSubYFixed()),
439                                           SkFixedFloorToFixed(fx),
440                                           SkFixedFloorToFixed(fy),
441                                           fontScaler);
442                 }
443                 pos += scalarsPerPosition;
444             }
445         } else {
446             while (text < stop) {
447                 // the last 2 parameters are ignored
448                 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
449
450                 if (glyph.fWidth) {
451                     tmsProc(tms, pos);
452
453                     SkIPoint fixedLoc;
454                     alignProc(tms.fLoc, glyph, &fixedLoc);
455
456                     SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
457                     SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
458                     this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
459                                                         glyph.getSubXFixed(),
460                                                         glyph.getSubYFixed()),
461                                           SkFixedFloorToFixed(fx),
462                                           SkFixedFloorToFixed(fy),
463                                           fontScaler);
464                 }
465                 pos += scalarsPerPosition;
466             }
467         }
468     }
469
470     this->finish();
471 }
472
473 namespace {
474
475 // position + texture coord
476 extern const GrVertexAttrib gTextVertexAttribs[] = {
477     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
478     {kVec2f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
479 };
480
481 };
482
483 void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
484                                           SkFixed vx, SkFixed vy,
485                                           GrFontScaler* scaler) {
486     if (NULL == fDrawTarget) {
487         return;
488     }
489
490     if (NULL == fStrike) {
491         fStrike = fContext->getFontCache()->getStrike(scaler, false);
492     }
493
494     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
495     if (NULL == glyph || glyph->fBounds.isEmpty()) {
496         return;
497     }
498
499     vx += SkIntToFixed(glyph->fBounds.fLeft);
500     vy += SkIntToFixed(glyph->fBounds.fTop);
501
502     // keep them as ints until we've done the clip-test
503     SkFixed width = glyph->fBounds.width();
504     SkFixed height = glyph->fBounds.height();
505
506     // check if we clipped out
507     if (true || NULL == glyph->fPlot) {
508         int x = vx >> 16;
509         int y = vy >> 16;
510         if (fClipRect.quickReject(x, y, x + width, y + height)) {
511 //            SkCLZ(3);    // so we can set a break-point in the debugger
512             return;
513         }
514     }
515
516     if (NULL == glyph->fPlot) {
517         if (fStrike->addGlyphToAtlas(glyph, scaler)) {
518             goto HAS_ATLAS;
519         }
520
521         // try to clear out an unused plot before we flush
522         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
523             fStrike->addGlyphToAtlas(glyph, scaler)) {
524             goto HAS_ATLAS;
525         }
526
527         if (c_DumpFontCache) {
528 #ifdef SK_DEVELOPER
529             fContext->getFontCache()->dump();
530 #endif
531         }
532
533         // flush any accumulated draws to allow us to free up a plot
534         this->flushGlyphs();
535         fContext->flush();
536
537         // we should have an unused plot now
538         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
539             fStrike->addGlyphToAtlas(glyph, scaler)) {
540             goto HAS_ATLAS;
541         }
542
543         if (NULL == glyph->fPath) {
544             SkPath* path = SkNEW(SkPath);
545             if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
546                 // flag the glyph as being dead?
547                 delete path;
548                 return;
549             }
550             glyph->fPath = path;
551         }
552
553         GrContext::AutoMatrix am;
554         SkMatrix translate;
555         translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
556                                SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
557         GrPaint tmpPaint(fPaint);
558         am.setPreConcat(fContext, translate, &tmpPaint);
559         SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
560         fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
561         return;
562     }
563
564 HAS_ATLAS:
565     SkASSERT(glyph->fPlot);
566     GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
567     glyph->fPlot->setDrawToken(drawToken);
568
569     // now promote them to fixed (TODO: Rethink using fixed pt).
570     width = SkIntToFixed(width);
571     height = SkIntToFixed(height);
572
573     GrTexture* texture = glyph->fPlot->texture();
574     SkASSERT(texture);
575
576     if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
577         this->flushGlyphs();
578         fCurrTexture = texture;
579         fCurrTexture->ref();
580     }
581
582     if (NULL == fVertices) {
583        // If we need to reserve vertices allow the draw target to suggest
584         // a number of verts to reserve and whether to perform a flush.
585         fMaxVertices = kMinRequestedVerts;
586         fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
587             SK_ARRAY_COUNT(gTextVertexAttribs));
588         bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
589         if (flush) {
590             this->flushGlyphs();
591             fContext->flush();
592             fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
593                 SK_ARRAY_COUNT(gTextVertexAttribs));
594         }
595         fMaxVertices = kDefaultRequestedVerts;
596         // ignore return, no point in flushing again.
597         fDrawTarget->geometryHints(&fMaxVertices, NULL);
598
599         int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
600         if (fMaxVertices < kMinRequestedVerts) {
601             fMaxVertices = kDefaultRequestedVerts;
602         } else if (fMaxVertices > maxQuadVertices) {
603             // don't exceed the limit of the index buffer
604             fMaxVertices = maxQuadVertices;
605         }
606         bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
607                                                                0,
608                                                                GrTCast<void**>(&fVertices),
609                                                                NULL);
610         GrAlwaysAssert(success);
611         SkASSERT(2*sizeof(SkPoint) == fDrawTarget->getDrawState().getVertexSize());
612     }
613
614     SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
615     SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
616
617     SkRect r;
618     r.fLeft = SkFixedToFloat(vx);
619     r.fTop = SkFixedToFloat(vy);
620     r.fRight = SkFixedToFloat(vx + width);
621     r.fBottom = SkFixedToFloat(vy + height);
622
623     fVertexBounds.growToInclude(r);
624
625     fVertices[2*fCurrVertex].setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom,
626                                         2 * sizeof(SkPoint));
627     fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
628                                           SkFixedToFloat(texture->normalizeFixedY(ty)),
629                                           SkFixedToFloat(texture->normalizeFixedX(tx + width)),
630                                           SkFixedToFloat(texture->normalizeFixedY(ty + height)),
631                                           2 * sizeof(SkPoint));
632     fCurrVertex += 4;
633 }