gfx/skia/trunk/src/gpu/GrDistanceFieldTextContext.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 "GrDistanceFieldTextContext.h"
     9 #include "GrAtlas.h"
    10 #include "GrDrawTarget.h"
    11 #include "GrDrawTargetCaps.h"
    12 #include "GrFontScaler.h"
    13 #include "SkGlyphCache.h"
    14 #include "GrIndexBuffer.h"
    15 #include "GrTextStrike.h"
    16 #include "GrTextStrike_impl.h"
    17 #include "SkDraw.h"
    18 #include "SkGpuDevice.h"
    19 #include "SkPath.h"
    20 #include "SkRTConf.h"
    21 #include "SkStrokeRec.h"
    22 #include "effects/GrDistanceFieldTextureEffect.h"
    24 static const int kGlyphCoordsAttributeIndex = 1;
    26 static const int kBaseDFFontSize = 32;
    28 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
    29                 "Dump the contents of the font cache before every purge.");
    31 #if SK_FORCE_DISTANCEFIELD_FONTS
    32 static const bool kForceDistanceFieldFonts = true;
    33 #else
    34 static const bool kForceDistanceFieldFonts = false;
    35 #endif
    37 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
    38                                                        const SkDeviceProperties& properties)
    39                                                     : GrTextContext(context, properties) {
    40     fStrike = NULL;
    42     fCurrTexture = NULL;
    43     fCurrVertex = 0;
    45     fVertices = NULL;
    46     fMaxVertices = 0;
    47 }
    49 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
    50     this->flushGlyphs();
    51 }
    53 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
    54     return (kForceDistanceFieldFonts || paint.isDistanceFieldTextTEMP()) &&
    55            !paint.getRasterizer() && !paint.getMaskFilter() &&
    56            paint.getStyle() == SkPaint::kFill_Style &&
    57            fContext->getTextTarget()->caps()->shaderDerivativeSupport() &&
    58            !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
    59 }
    61 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
    62     unsigned r = SkColorGetR(c);
    63     unsigned g = SkColorGetG(c);
    64     unsigned b = SkColorGetB(c);
    65     return GrColorPackRGBA(r, g, b, 0xff);
    66 }
    68 void GrDistanceFieldTextContext::flushGlyphs() {
    69     if (NULL == fDrawTarget) {
    70         return;
    71     }
    73     GrDrawState* drawState = fDrawTarget->drawState();
    74     GrDrawState::AutoRestoreEffects are(drawState);
    75     drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
    77     if (fCurrVertex > 0) {
    78         // setup our sampler state for our text texture/atlas
    79         SkASSERT(GrIsALIGN4(fCurrVertex));
    80         SkASSERT(fCurrTexture);
    81         GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
    83         // This effect could be stored with one of the cache objects (atlas?)
    84         SkISize size = fStrike->getAtlasSize();
    85         drawState->addCoverageEffect(
    86                                 GrDistanceFieldTextureEffect::Create(fCurrTexture, params, size),
    87                                 kGlyphCoordsAttributeIndex)->unref();
    89         if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
    90             if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
    91                 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
    92                 fPaint.numColorStages()) {
    93                 GrPrintf("LCD Text will not draw correctly.\n");
    94             }
    95             // We don't use the GrPaint's color in this case because it's been premultiplied by
    96             // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
    97             // the mask texture color. The end result is that we get
    98             //            mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
    99             int a = SkColorGetA(fSkPaint.getColor());
   100             // paintAlpha
   101             drawState->setColor(SkColorSetARGB(a, a, a, a));
   102             // paintColor
   103             drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
   104             drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
   105         } else {
   106             // set back to normal in case we took LCD path previously.
   107             drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
   108             drawState->setColor(fPaint.getColor());
   109         }
   111         int nGlyphs = fCurrVertex / 4;
   112         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
   113         fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
   114                                           nGlyphs,
   115                                           4, 6);
   116         fDrawTarget->resetVertexSource();
   117         fVertices = NULL;
   118         fMaxVertices = 0;
   119         fCurrVertex = 0;
   120         SkSafeSetNull(fCurrTexture);
   121     }
   122 }
   124 namespace {
   126 // position + texture coord
   127 extern const GrVertexAttrib gTextVertexAttribs[] = {
   128     {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
   129     {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
   130 };
   132 };
   134 void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
   135                                                  GrFixed vx, GrFixed vy,
   136                                                  GrFontScaler* scaler) {
   137     if (NULL == fDrawTarget) {
   138         return;
   139     }
   140     if (NULL == fStrike) {
   141         fStrike = fContext->getFontCache()->getStrike(scaler, true);
   142     }
   144     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
   145     if (NULL == glyph || glyph->fBounds.isEmpty()) {
   146         return;
   147     }
   149     SkScalar sx = SkFixedToScalar(vx);
   150     SkScalar sy = SkFixedToScalar(vy);
   151 /*
   152     // not valid, need to find a different solution for this
   153     vx += SkIntToFixed(glyph->fBounds.fLeft);
   154     vy += SkIntToFixed(glyph->fBounds.fTop);
   156     // keep them as ints until we've done the clip-test
   157     GrFixed width = glyph->fBounds.width();
   158     GrFixed height = glyph->fBounds.height();
   160     // check if we clipped out
   161     if (true || NULL == glyph->fPlot) {
   162         int x = vx >> 16;
   163         int y = vy >> 16;
   164         if (fClipRect.quickReject(x, y, x + width, y + height)) {
   165 //            SkCLZ(3);    // so we can set a break-point in the debugger
   166             return;
   167         }
   168     }
   169 */
   170     if (NULL == glyph->fPlot) {
   171         if (fStrike->addGlyphToAtlas(glyph, scaler)) {
   172             goto HAS_ATLAS;
   173         }
   175         // try to clear out an unused plot before we flush
   176         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
   177             fStrike->addGlyphToAtlas(glyph, scaler)) {
   178             goto HAS_ATLAS;
   179         }
   181         if (c_DumpFontCache) {
   182 #ifdef SK_DEVELOPER
   183             fContext->getFontCache()->dump();
   184 #endif
   185         }
   187         // before we purge the cache, we must flush any accumulated draws
   188         this->flushGlyphs();
   189         fContext->flush();
   191         // we should have an unused plot now
   192         if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
   193             fStrike->addGlyphToAtlas(glyph, scaler)) {
   194             goto HAS_ATLAS;
   195         }
   197         if (NULL == glyph->fPath) {
   198             SkPath* path = SkNEW(SkPath);
   199             if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
   200                 // flag the glyph as being dead?
   201                 delete path;
   202                 return;
   203             }
   204             glyph->fPath = path;
   205         }
   207         GrContext::AutoMatrix am;
   208         SkMatrix translate;
   209         translate.setTranslate(sx, sy);
   210         GrPaint tmpPaint(fPaint);
   211         am.setPreConcat(fContext, translate, &tmpPaint);
   212         SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
   213         fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
   214         return;
   215     }
   217 HAS_ATLAS:
   218     SkASSERT(glyph->fPlot);
   219     GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
   220     glyph->fPlot->setDrawToken(drawToken);
   222     GrTexture* texture = glyph->fPlot->texture();
   223     SkASSERT(texture);
   225     if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
   226         this->flushGlyphs();
   227         fCurrTexture = texture;
   228         fCurrTexture->ref();
   229     }
   231     if (NULL == fVertices) {
   232        // If we need to reserve vertices allow the draw target to suggest
   233         // a number of verts to reserve and whether to perform a flush.
   234         fMaxVertices = kMinRequestedVerts;
   235         fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
   236             SK_ARRAY_COUNT(gTextVertexAttribs));
   237         bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
   238         if (flush) {
   239             this->flushGlyphs();
   240             fContext->flush();
   241             fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
   242                 SK_ARRAY_COUNT(gTextVertexAttribs));
   243         }
   244         fMaxVertices = kDefaultRequestedVerts;
   245         // ignore return, no point in flushing again.
   246         fDrawTarget->geometryHints(&fMaxVertices, NULL);
   248         int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
   249         if (fMaxVertices < kMinRequestedVerts) {
   250             fMaxVertices = kDefaultRequestedVerts;
   251         } else if (fMaxVertices > maxQuadVertices) {
   252             // don't exceed the limit of the index buffer
   253             fMaxVertices = maxQuadVertices;
   254         }
   255         bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
   256                                                                0,
   257                                                                GrTCast<void**>(&fVertices),
   258                                                                NULL);
   259         GrAlwaysAssert(success);
   260         SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
   261     }
   263     SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft);
   264     SkScalar dy = SkIntToScalar(glyph->fBounds.fTop);
   265     SkScalar width = SkIntToScalar(glyph->fBounds.width());
   266     SkScalar height = SkIntToScalar(glyph->fBounds.height());
   268     SkScalar scale = fTextRatio;
   269     dx *= scale;
   270     dy *= scale;
   271     sx += dx;
   272     sy += dy;
   273     width *= scale;
   274     height *= scale;
   276     GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
   277     GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
   278     GrFixed tw = SkIntToFixed(glyph->fBounds.width());
   279     GrFixed th = SkIntToFixed(glyph->fBounds.height());
   281     static const size_t kVertexSize = 2 * sizeof(SkPoint);
   282     fVertices[2*fCurrVertex].setRectFan(sx,
   283                                         sy,
   284                                         sx + width,
   285                                         sy + height,
   286                                         kVertexSize);
   287     fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
   288                                           SkFixedToFloat(texture->normalizeFixedY(ty)),
   289                                           SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
   290                                           SkFixedToFloat(texture->normalizeFixedY(ty + th)),
   291                                           kVertexSize);
   292     fCurrVertex += 4;
   293 }
   295 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
   296     GrTextContext::init(paint, skPaint);
   298     fStrike = NULL;
   300     fCurrTexture = NULL;
   301     fCurrVertex = 0;
   303     fVertices = NULL;
   304     fMaxVertices = 0;
   306     fTextRatio = fSkPaint.getTextSize()/kBaseDFFontSize;
   308     fSkPaint.setTextSize(SkIntToScalar(kBaseDFFontSize));
   309     fSkPaint.setLCDRenderText(false);
   310     fSkPaint.setAutohinted(false);
   311     fSkPaint.setSubpixelText(true);
   312 }
   314 inline void GrDistanceFieldTextContext::finish() {
   315     flushGlyphs();
   317     GrTextContext::finish();
   318 }
   320 void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
   321                                           const char text[], size_t byteLength,
   322                                           SkScalar x, SkScalar y) {
   323     SkASSERT(byteLength == 0 || text != NULL);
   325     // nothing to draw or can't draw
   326     if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
   327         || fSkPaint.getRasterizer()) {
   328         return;
   329     }
   331     this->init(paint, skPaint);
   333     SkScalar sizeRatio = fTextRatio;
   335     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
   337     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, NULL);
   338     SkGlyphCache*       cache = autoCache.getCache();
   339     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
   341     // need to measure first
   342     // TODO - generate positions and pre-load cache as well?
   343     const char* stop = text + byteLength;
   344     if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
   345         SkFixed    stopX = 0;
   346         SkFixed    stopY = 0;
   348         const char* textPtr = text;
   349         while (textPtr < stop) {
   350             // don't need x, y here, since all subpixel variants will have the
   351             // same advance
   352             const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
   354             stopX += glyph.fAdvanceX;
   355             stopY += glyph.fAdvanceY;
   356         }
   357         SkASSERT(textPtr == stop);
   359         SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
   360         SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
   362         if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
   363             alignX = SkScalarHalf(alignX);
   364             alignY = SkScalarHalf(alignY);
   365         }
   367         x -= alignX;
   368         y -= alignY;
   369     }
   371     SkFixed fx = SkScalarToFixed(x) + SK_FixedHalf;
   372     SkFixed fy = SkScalarToFixed(y) + SK_FixedHalf;
   373     SkFixed fixedScale = SkScalarToFixed(sizeRatio);
   374     while (text < stop) {
   375         const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy);
   377         if (glyph.fWidth) {
   378             this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
   379                                                 glyph.getSubXFixed(),
   380                                                 glyph.getSubYFixed()),
   381                                   SkFixedFloorToFixed(fx),
   382                                   SkFixedFloorToFixed(fy),
   383                                   fontScaler);
   384         }
   386         fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
   387         fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
   388     }
   390     this->finish();
   391 }
   393 void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
   394                                              const char text[], size_t byteLength,
   395                                              const SkScalar pos[], SkScalar constY,
   396                                              int scalarsPerPosition) {
   398     SkASSERT(byteLength == 0 || text != NULL);
   399     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
   401     // nothing to draw
   402     if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
   403         return;
   404     }
   406     this->init(paint, skPaint);
   408     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
   410     SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, NULL);
   411     SkGlyphCache*       cache = autoCache.getCache();
   412     GrFontScaler*       fontScaler = GetGrFontScaler(cache);
   414     const char*        stop = text + byteLength;
   416     if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
   417         while (text < stop) {
   418             // the last 2 parameters are ignored
   419             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
   421             if (glyph.fWidth) {
   422                 SkScalar x = pos[0];
   423                 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
   425                 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
   426                                                     glyph.getSubXFixed(),
   427                                                     glyph.getSubYFixed()),
   428                                       SkScalarToFixed(x) + SK_FixedHalf, //d1g.fHalfSampleX,
   429                                       SkScalarToFixed(y) + SK_FixedHalf, //d1g.fHalfSampleY,
   430                                       fontScaler);
   431             }
   432             pos += scalarsPerPosition;
   433         }
   434     } else {
   435         int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
   436         while (text < stop) {
   437             // the last 2 parameters are ignored
   438             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
   440             if (glyph.fWidth) {
   441                 SkScalar x = pos[0];
   442                 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
   444                 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
   445                                                     glyph.getSubXFixed(),
   446                                                     glyph.getSubYFixed()),
   447                                       SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift)
   448                                         + SK_FixedHalf, //d1g.fHalfSampleX,
   449                                       SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift)
   450                                         + SK_FixedHalf, //d1g.fHalfSampleY,
   451                                       fontScaler);
   452             }
   453             pos += scalarsPerPosition;
   454         }
   455     }
   457     this->finish();
   458 }

mercurial