gfx/skia/trunk/src/gpu/GrBitmapTextContext.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rwxr-xr-x

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
     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"
    21 #include "SkAutoKern.h"
    22 #include "SkDraw.h"
    23 #include "SkGlyphCache.h"
    24 #include "SkGpuDevice.h"
    25 #include "SkGr.h"
    27 static const int kGlyphCoordsAttributeIndex = 1;
    29 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
    30                 "Dump the contents of the font cache before every purge.");
    32 GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
    33                                          const SkDeviceProperties& properties)
    34                                        : GrTextContext(context, properties) {
    35     fStrike = NULL;
    37     fCurrTexture = NULL;
    38     fCurrVertex = 0;
    40     fVertices = NULL;
    41     fMaxVertices = 0;
    43     fVertexBounds.setLargestInverted();
    44 }
    46 GrBitmapTextContext::~GrBitmapTextContext() {
    47     this->flushGlyphs();
    48 }
    50 bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
    51     return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
    52 }
    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 }
    61 void GrBitmapTextContext::flushGlyphs() {
    62     if (NULL == fDrawTarget) {
    63         return;
    64     }
    66     GrDrawState* drawState = fDrawTarget->drawState();
    67     GrDrawState::AutoRestoreEffects are(drawState);
    68     drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
    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);
    76         // This effect could be stored with one of the cache objects (atlas?)
    77         drawState->addCoverageEffect(
    78                                 GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
    79                                 kGlyphCoordsAttributeIndex)->unref();
    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         }
   106         int nGlyphs = fCurrVertex / 4;
   107         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
   108         fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
   109                                           nGlyphs,
   110                                           4, 6, &fVertexBounds);
   112         fDrawTarget->resetVertexSource();
   113         fVertices = NULL;
   114         fMaxVertices = 0;
   115         fCurrVertex = 0;
   116         fVertexBounds.setLargestInverted();
   117         SkSafeSetNull(fCurrTexture);
   118     }
   119 }
   121 inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
   122     GrTextContext::init(paint, skPaint);
   124     fStrike = NULL;
   126     fCurrTexture = NULL;
   127     fCurrVertex = 0;
   129     fVertices = NULL;
   130     fMaxVertices = 0;
   131 }
   133 inline void GrBitmapTextContext::finish() {
   134     flushGlyphs();
   136     GrTextContext::finish();
   137 }
   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);
   144     // nothing to draw
   145     if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
   146         return;
   147     }
   149     this->init(paint, skPaint);
   151     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
   153     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
   154     SkGlyphCache*       cache = autoCache.getCache();
   155     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
   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     }
   165     // need to measure first
   166     if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
   167         SkVector    stop;
   169         MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
   171         SkScalar    stopX = stop.fX;
   172         SkScalar    stopY = stop.fY;
   174         if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
   175             stopX = SkScalarHalf(stopX);
   176             stopY = SkScalarHalf(stopY);
   177         }
   178         x -= stopX;
   179         y -= stopY;
   180     }
   182     const char* stop = text + byteLength;
   184     SkAutoKern autokern;
   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     }
   203     SkFixed fx = SkScalarToFixed(x) + halfSampleX;
   204     SkFixed fy = SkScalarToFixed(y) + halfSampleY;
   206     GrContext::AutoMatrix  autoMatrix;
   207     autoMatrix.setIdentity(fContext, &fPaint);
   209     while (text < stop) {
   210         const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
   212         fx += autokern.adjust(glyph);
   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         }
   223         fx += glyph.fAdvanceX;
   224         fy += glyph.fAdvanceY;
   225     }
   227     this->finish();
   228 }
   230 ///////////////////////////////////////////////////////////////////////////////
   231 // Copied from SkDraw
   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*);
   238 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
   239     dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
   240 }
   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 }
   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 }
   252 static AlignProc pick_align_proc(SkPaint::Align align) {
   253     static const AlignProc gProcs[] = {
   254         leftAlignProc, centerAlignProc, rightAlignProc
   255     };
   257     SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
   259     return gProcs[align];
   260 }
   262 class BitmapTextMapState {
   263 public:
   264     mutable SkPoint fLoc;
   266     BitmapTextMapState(const SkMatrix& matrix, SkScalar y)
   267         : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
   269     typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]);
   271     Proc pickProc(int scalarsPerPosition);
   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;
   280     static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) {
   281         state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
   282     }
   284     static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) {
   285         state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
   286     }
   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     }
   294     static void MapOnlyTransXProc(const BitmapTextMapState& state,
   295                                   const SkScalar pos[]) {
   296         state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
   297     }
   298 };
   300 BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) {
   301     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
   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 }
   320 ///////////////////////////////////////////////////////////////////////////////
   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);
   329     // nothing to draw
   330     if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
   331         return;
   332     }
   334     this->init(paint, skPaint);
   336     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
   338     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
   339     SkGlyphCache*       cache = autoCache.getCache();
   340     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
   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);
   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;
   353     if (cache->isSubpixel()) {
   354         // maybe we should skip the rounding if linearText is set
   355         SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
   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         }
   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;
   377                 const SkGlyph& glyph = glyphCacheProc(cache, &text,
   378                                                       fx & fxMask, fy & fyMask);
   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);
   395                 if (metricGlyph.fWidth) {
   396                     SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
   397                     SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
   399                     tmsProc(tms, pos);
   400                     SkIPoint fixedLoc;
   401                     alignProc(tms.fLoc, metricGlyph, &fixedLoc);
   403                     SkFixed fx = fixedLoc.fX + halfSampleX;
   404                     SkFixed fy = fixedLoc.fY + halfSampleY;
   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);
   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
   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);
   431                 if (glyph.fWidth) {
   432                     tmsProc(tms, pos);
   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);
   450                 if (glyph.fWidth) {
   451                     tmsProc(tms, pos);
   453                     SkIPoint fixedLoc;
   454                     alignProc(tms.fLoc, glyph, &fixedLoc);
   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     }
   470     this->finish();
   471 }
   473 namespace {
   475 // position + texture coord
   476 extern const GrVertexAttrib gTextVertexAttribs[] = {
   477     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
   478     {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
   479 };
   481 };
   483 void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
   484                                           GrFixed vx, GrFixed vy,
   485                                           GrFontScaler* scaler) {
   486     if (NULL == fDrawTarget) {
   487         return;
   488     }
   490     if (NULL == fStrike) {
   491         fStrike = fContext->getFontCache()->getStrike(scaler, false);
   492     }
   494     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
   495     if (NULL == glyph || glyph->fBounds.isEmpty()) {
   496         return;
   497     }
   499     vx += SkIntToFixed(glyph->fBounds.fLeft);
   500     vy += SkIntToFixed(glyph->fBounds.fTop);
   502     // keep them as ints until we've done the clip-test
   503     GrFixed width = glyph->fBounds.width();
   504     GrFixed height = glyph->fBounds.height();
   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     }
   516     if (NULL == glyph->fPlot) {
   517         if (fStrike->addGlyphToAtlas(glyph, scaler)) {
   518             goto HAS_ATLAS;
   519         }
   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         }
   527         if (c_DumpFontCache) {
   528 #ifdef SK_DEVELOPER
   529             fContext->getFontCache()->dump();
   530 #endif
   531         }
   533         // flush any accumulated draws to allow us to free up a plot
   534         this->flushGlyphs();
   535         fContext->flush();
   537         // we should have an unused plot now
   538         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
   539             fStrike->addGlyphToAtlas(glyph, scaler)) {
   540             goto HAS_ATLAS;
   541         }
   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         }
   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     }
   564 HAS_ATLAS:
   565     SkASSERT(glyph->fPlot);
   566     GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
   567     glyph->fPlot->setDrawToken(drawToken);
   569     // now promote them to fixed (TODO: Rethink using fixed pt).
   570     width = SkIntToFixed(width);
   571     height = SkIntToFixed(height);
   573     GrTexture* texture = glyph->fPlot->texture();
   574     SkASSERT(texture);
   576     if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
   577         this->flushGlyphs();
   578         fCurrTexture = texture;
   579         fCurrTexture->ref();
   580     }
   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);
   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(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
   612     }
   614     GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
   615     GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
   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);
   623     fVertexBounds.growToInclude(r);
   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 }

mercurial