LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/text - GrTextUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 296 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 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 "GrTextUtils.h"
       9             : #include "GrAtlasGlyphCache.h"
      10             : #include "GrAtlasTextBlob.h"
      11             : #include "GrBlurUtils.h"
      12             : #include "GrCaps.h"
      13             : #include "GrContext.h"
      14             : #include "GrRenderTargetContext.h"
      15             : #include "GrSurfaceContextPriv.h"
      16             : #include "SkDistanceFieldGen.h"
      17             : #include "SkDrawFilter.h"
      18             : #include "SkDrawProcs.h"
      19             : #include "SkFindAndPlaceGlyph.h"
      20             : #include "SkGlyphCache.h"
      21             : #include "SkGr.h"
      22             : #include "SkPaint.h"
      23             : #include "SkRect.h"
      24             : #include "SkTextBlobRunIterator.h"
      25             : #include "SkTextMapStateProc.h"
      26             : #include "SkTextToPathIter.h"
      27             : 
      28             : namespace {
      29             : static const int kMinDFFontSize = 18;
      30             : static const int kSmallDFFontSize = 32;
      31             : static const int kSmallDFFontLimit = 32;
      32             : static const int kMediumDFFontSize = 72;
      33             : static const int kMediumDFFontLimit = 72;
      34             : static const int kLargeDFFontSize = 162;
      35             : #ifdef SK_BUILD_FOR_ANDROID
      36             : static const int kLargeDFFontLimit = 384;
      37             : #else
      38             : static const int kLargeDFFontLimit = 2 * kLargeDFFontSize;
      39             : #endif
      40             : };
      41             : 
      42           0 : bool GrTextUtils::Paint::toGrPaint(GrMaskFormat maskFormat, GrRenderTargetContext* rtc,
      43             :                                    const SkMatrix& viewMatrix, GrPaint* grPaint) const {
      44             :     // TODO: this is the last use of GrSurfaceContextPriv
      45           0 :     GrContext* context = rtc->surfPriv().getContext();
      46           0 :     if (kARGB_GrMaskFormat == maskFormat) {
      47           0 :         return SkPaintToGrPaintWithPrimitiveColor(context, rtc, this->skPaint(), grPaint);
      48             :     } else {
      49           0 :         return SkPaintToGrPaint(context, rtc, this->skPaint(), viewMatrix, grPaint);
      50             :     }
      51             : }
      52             : 
      53           0 : bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) {
      54           0 :     if (!fModifiedPaint.isValid()) {
      55           0 :         fModifiedPaint.init(fOriginalPaint->skPaint());
      56           0 :         fPaint = fModifiedPaint.get();
      57           0 :     } else if (fFilter) {
      58             :         // We have to reset before applying the run because the filter could have arbitrary
      59             :         // changed the paint.
      60           0 :         *fModifiedPaint.get() = fOriginalPaint->skPaint();
      61             :     }
      62           0 :     run.applyFontToPaint(fModifiedPaint.get());
      63             : 
      64           0 :     if (fFilter) {
      65           0 :         if (!fFilter->filter(fModifiedPaint.get(), SkDrawFilter::kText_Type)) {
      66             :             // A false return from filter() means we should abort the current draw.
      67           0 :             return false;
      68             :         }
      69             :         // The draw filter could have changed either the paint color or color filter.
      70           0 :         this->initFilteredColor();
      71             :     }
      72           0 :     fModifiedPaint.get()->setFlags(FilterTextFlags(fProps, *fModifiedPaint.get()));
      73           0 :     return true;
      74             : }
      75             : 
      76           0 : void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache,
      77             :                               const SkSurfaceProps& props, const GrTextUtils::Paint& paint,
      78             :                               uint32_t scalerContextFlags, const SkMatrix& viewMatrix,
      79             :                               const char text[], size_t byteLength, SkScalar x, SkScalar y) {
      80           0 :     SkASSERT(byteLength == 0 || text != nullptr);
      81             : 
      82             :     // nothing to draw
      83           0 :     if (text == nullptr || byteLength == 0) {
      84           0 :         return;
      85             :     }
      86             : 
      87             :     // Ensure the blob is set for bitmaptext
      88           0 :     blob->setHasBitmap();
      89             : 
      90           0 :     GrAtlasTextStrike* currStrike = nullptr;
      91             : 
      92           0 :     SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
      93           0 :     SkFindAndPlaceGlyph::ProcessText(
      94           0 :         paint.skPaint().getTextEncoding(), text, byteLength,
      95           0 :         {x, y}, viewMatrix, paint.skPaint().getTextAlign(),
      96             :         cache,
      97           0 :         [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
      98           0 :              position += rounding;
      99           0 :              BmpAppendGlyph(
     100           0 :                  blob, runIndex, fontCache, &currStrike, glyph,
     101           0 :                  SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
     102           0 :                  paint.filteredPremulGrColor(), cache);
     103           0 :         }
     104           0 :     );
     105             : 
     106           0 :     SkGlyphCache::AttachCache(cache);
     107             : }
     108             : 
     109           0 : void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache,
     110             :                                  const SkSurfaceProps& props, const GrTextUtils::Paint& paint,
     111             :                                  uint32_t scalerContextFlags, const SkMatrix& viewMatrix,
     112             :                                  const char text[], size_t byteLength, const SkScalar pos[],
     113             :                                  int scalarsPerPosition, const SkPoint& offset) {
     114           0 :     SkASSERT(byteLength == 0 || text != nullptr);
     115           0 :     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
     116             : 
     117             :     // nothing to draw
     118           0 :     if (text == nullptr || byteLength == 0) {
     119           0 :         return;
     120             :     }
     121             : 
     122             :     // Ensure the blob is set for bitmaptext
     123           0 :     blob->setHasBitmap();
     124             : 
     125           0 :     GrAtlasTextStrike* currStrike = nullptr;
     126             : 
     127           0 :     SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
     128             : 
     129           0 :     SkFindAndPlaceGlyph::ProcessPosText(
     130           0 :         paint.skPaint().getTextEncoding(), text, byteLength,
     131             :         offset, viewMatrix, pos, scalarsPerPosition,
     132           0 :         paint.skPaint().getTextAlign(), cache,
     133           0 :         [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
     134           0 :             position += rounding;
     135           0 :             BmpAppendGlyph(
     136           0 :                 blob, runIndex, fontCache, &currStrike, glyph,
     137           0 :                 SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
     138           0 :                 paint.filteredPremulGrColor(), cache);
     139           0 :         }
     140           0 :     );
     141             : 
     142           0 :     SkGlyphCache::AttachCache(cache);
     143             : }
     144             : 
     145           0 : void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
     146             :                                  GrAtlasGlyphCache* fontCache,
     147             :                                  GrAtlasTextStrike** strike, const SkGlyph& skGlyph,
     148             :                                  int vx, int vy, GrColor color, SkGlyphCache* cache) {
     149           0 :     if (!*strike) {
     150           0 :         *strike = fontCache->getStrike(cache);
     151             :     }
     152             : 
     153           0 :     GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
     154             :                                          skGlyph.getSubXFixed(),
     155             :                                          skGlyph.getSubYFixed(),
     156           0 :                                          GrGlyph::kCoverage_MaskStyle);
     157           0 :     GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, cache);
     158           0 :     if (!glyph) {
     159           0 :         return;
     160             :     }
     161             : 
     162           0 :     int x = vx + glyph->fBounds.fLeft;
     163           0 :     int y = vy + glyph->fBounds.fTop;
     164             : 
     165             :     // keep them as ints until we've done the clip-test
     166           0 :     int width = glyph->fBounds.width();
     167           0 :     int height = glyph->fBounds.height();
     168             : 
     169             :     SkRect r;
     170           0 :     r.fLeft = SkIntToScalar(x);
     171           0 :     r.fTop = SkIntToScalar(y);
     172           0 :     r.fRight = r.fLeft + SkIntToScalar(width);
     173           0 :     r.fBottom = r.fTop + SkIntToScalar(height);
     174             : 
     175           0 :     blob->appendGlyph(runIndex, r, color, *strike, glyph, cache, skGlyph,
     176           0 :                       SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, true);
     177             : }
     178             : 
     179           0 : bool GrTextUtils::CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix,
     180             :                                           const SkSurfaceProps& props, const GrShaderCaps& caps) {
     181             :     // TODO: support perspective (need getMaxScale replacement)
     182           0 :     if (viewMatrix.hasPerspective()) {
     183           0 :         return false;
     184             :     }
     185             : 
     186           0 :     SkScalar maxScale = viewMatrix.getMaxScale();
     187           0 :     SkScalar scaledTextSize = maxScale * skPaint.getTextSize();
     188             :     // Hinted text looks far better at small resolutions
     189             :     // Scaling up beyond 2x yields undesireable artifacts
     190           0 :     if (scaledTextSize < kMinDFFontSize ||
     191             :         scaledTextSize > kLargeDFFontLimit) {
     192           0 :         return false;
     193             :     }
     194             : 
     195           0 :     bool useDFT = props.isUseDeviceIndependentFonts();
     196             : #if SK_FORCE_DISTANCE_FIELD_TEXT
     197             :     useDFT = true;
     198             : #endif
     199             : 
     200           0 :     if (!useDFT && scaledTextSize < kLargeDFFontSize) {
     201           0 :         return false;
     202             :     }
     203             : 
     204             :     // rasterizers and mask filters modify alpha, which doesn't
     205             :     // translate well to distance
     206           0 :     if (skPaint.getRasterizer() || skPaint.getMaskFilter() || !caps.shaderDerivativeSupport()) {
     207           0 :         return false;
     208             :     }
     209             : 
     210             :     // TODO: add some stroking support
     211           0 :     if (skPaint.getStyle() != SkPaint::kFill_Style) {
     212           0 :         return false;
     213             :     }
     214             : 
     215           0 :     return true;
     216             : }
     217             : 
     218           0 : void GrTextUtils::InitDistanceFieldPaint(GrAtlasTextBlob* blob,
     219             :                                          SkPaint* skPaint,
     220             :                                          SkScalar* textRatio,
     221             :                                          const SkMatrix& viewMatrix) {
     222             :     // getMaxScale doesn't support perspective, so neither do we at the moment
     223           0 :     SkASSERT(!viewMatrix.hasPerspective());
     224           0 :     SkScalar maxScale = viewMatrix.getMaxScale();
     225           0 :     SkScalar textSize = skPaint->getTextSize();
     226           0 :     SkScalar scaledTextSize = textSize;
     227             :     // if we have non-unity scale, we need to choose our base text size
     228             :     // based on the SkPaint's text size multiplied by the max scale factor
     229             :     // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
     230           0 :     if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
     231           0 :         scaledTextSize *= maxScale;
     232             :     }
     233             : 
     234             :     // We have three sizes of distance field text, and within each size 'bucket' there is a floor
     235             :     // and ceiling.  A scale outside of this range would require regenerating the distance fields
     236             :     SkScalar dfMaskScaleFloor;
     237             :     SkScalar dfMaskScaleCeil;
     238           0 :     if (scaledTextSize <= kSmallDFFontLimit) {
     239           0 :         dfMaskScaleFloor = kMinDFFontSize;
     240           0 :         dfMaskScaleCeil = kSmallDFFontLimit;
     241           0 :         *textRatio = textSize / kSmallDFFontSize;
     242           0 :         skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
     243           0 :     } else if (scaledTextSize <= kMediumDFFontLimit) {
     244           0 :         dfMaskScaleFloor = kSmallDFFontLimit;
     245           0 :         dfMaskScaleCeil = kMediumDFFontLimit;
     246           0 :         *textRatio = textSize / kMediumDFFontSize;
     247           0 :         skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
     248             :     } else {
     249           0 :         dfMaskScaleFloor = kMediumDFFontLimit;
     250           0 :         dfMaskScaleCeil = kLargeDFFontLimit;
     251           0 :         *textRatio = textSize / kLargeDFFontSize;
     252           0 :         skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
     253             :     }
     254             : 
     255             :     // Because there can be multiple runs in the blob, we want the overall maxMinScale, and
     256             :     // minMaxScale to make regeneration decisions.  Specifically, we want the maximum minimum scale
     257             :     // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can
     258             :     // tolerate before we'd have to move to a large mip size.  When we actually test these values
     259             :     // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test
     260             :     // against these values to decide if we can reuse or not(ie, will a given scale change our mip
     261             :     // level)
     262           0 :     SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil);
     263           0 :     blob->setMinAndMaxScale(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize);
     264             : 
     265           0 :     skPaint->setLCDRenderText(false);
     266           0 :     skPaint->setAutohinted(false);
     267           0 :     skPaint->setHinting(SkPaint::kNormal_Hinting);
     268           0 :     skPaint->setSubpixelText(true);
     269           0 : }
     270             : 
     271           0 : void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex,
     272             :                              GrAtlasGlyphCache* fontCache, const SkSurfaceProps& props,
     273             :                              const GrTextUtils::Paint& paint, uint32_t scalerContextFlags,
     274             :                              const SkMatrix& viewMatrix,
     275             :                              const char text[], size_t byteLength,
     276             :                              SkScalar x, SkScalar y) {
     277           0 :     SkASSERT(byteLength == 0 || text != nullptr);
     278             : 
     279             :     // nothing to draw
     280           0 :     if (text == nullptr || byteLength == 0) {
     281           0 :         return;
     282             :     }
     283             : 
     284           0 :     const SkPaint& skPaint = paint.skPaint();
     285           0 :     SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(),
     286           0 :                                                                         skPaint.isDevKernText(),
     287           0 :                                                                         true);
     288           0 :     SkAutoDescriptor desc;
     289           0 :     SkScalerContextEffects effects;
     290             :     // We apply the fake-gamma by altering the distance in the shader, so we ignore the
     291             :     // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
     292             :     skPaint.getScalerContextDescriptor(&effects, &desc, props, SkPaint::kNone_ScalerContextFlags,
     293           0 :                                        nullptr);
     294           0 :     SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface(), effects,
     295           0 :                                                              desc.getDesc());
     296             : 
     297           0 :     SkTArray<SkScalar> positions;
     298             : 
     299           0 :     const char* textPtr = text;
     300           0 :     SkScalar stopX = 0;
     301           0 :     SkScalar stopY = 0;
     302           0 :     SkScalar origin = 0;
     303           0 :     switch (skPaint.getTextAlign()) {
     304           0 :         case SkPaint::kRight_Align: origin = SK_Scalar1; break;
     305           0 :         case SkPaint::kCenter_Align: origin = SK_ScalarHalf; break;
     306           0 :         case SkPaint::kLeft_Align: origin = 0; break;
     307             :     }
     308             : 
     309           0 :     SkAutoKern autokern;
     310           0 :     const char* stop = text + byteLength;
     311           0 :     while (textPtr < stop) {
     312             :         // don't need x, y here, since all subpixel variants will have the
     313             :         // same advance
     314           0 :         const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr);
     315             : 
     316           0 :         SkScalar width = SkFloatToScalar(glyph.fAdvanceX) + autokern.adjust(glyph);
     317           0 :         positions.push_back(stopX + origin * width);
     318             : 
     319           0 :         SkScalar height = SkFloatToScalar(glyph.fAdvanceY);
     320           0 :         positions.push_back(stopY + origin * height);
     321             : 
     322           0 :         stopX += width;
     323           0 :         stopY += height;
     324             :     }
     325           0 :     SkASSERT(textPtr == stop);
     326             : 
     327           0 :     SkGlyphCache::AttachCache(origPaintCache);
     328             : 
     329             :     // now adjust starting point depending on alignment
     330           0 :     SkScalar alignX = stopX;
     331           0 :     SkScalar alignY = stopY;
     332           0 :     if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
     333           0 :         alignX = SkScalarHalf(alignX);
     334           0 :         alignY = SkScalarHalf(alignY);
     335           0 :     } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
     336           0 :         alignX = 0;
     337           0 :         alignY = 0;
     338             :     }
     339           0 :     x -= alignX;
     340           0 :     y -= alignY;
     341           0 :     SkPoint offset = SkPoint::Make(x, y);
     342             : 
     343             :     DrawDFPosText(blob, runIndex, fontCache, props, paint, scalerContextFlags, viewMatrix, text,
     344           0 :                   byteLength, positions.begin(), 2, offset);
     345             : }
     346             : 
     347           0 : void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache,
     348             :                                 const SkSurfaceProps& props, const GrTextUtils::Paint& paint,
     349             :                                 uint32_t scalerContextFlags, const SkMatrix& viewMatrix,
     350             :                                 const char text[], size_t byteLength, const SkScalar pos[],
     351             :                                 int scalarsPerPosition, const SkPoint& offset) {
     352           0 :     SkASSERT(byteLength == 0 || text != nullptr);
     353           0 :     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
     354             : 
     355             :     // nothing to draw
     356           0 :     if (text == nullptr || byteLength == 0) {
     357           0 :         return;
     358             :     }
     359             : 
     360           0 :     SkTDArray<char> fallbackTxt;
     361           0 :     SkTDArray<SkScalar> fallbackPos;
     362             : 
     363             :     // Setup distance field paint and text ratio
     364             :     SkScalar textRatio;
     365           0 :     SkPaint dfPaint(paint);
     366           0 :     GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
     367           0 :     blob->setHasDistanceField();
     368           0 :     blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText());
     369             : 
     370           0 :     GrAtlasTextStrike* currStrike = nullptr;
     371             : 
     372             :     // We apply the fake-gamma by altering the distance in the shader, so we ignore the
     373             :     // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
     374             :     SkGlyphCache* cache = blob->setupCache(runIndex, props, SkPaint::kNone_ScalerContextFlags,
     375           0 :                                            dfPaint, nullptr);
     376           0 :     SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(dfPaint.getTextEncoding(),
     377           0 :                                                                         dfPaint.isDevKernText(),
     378           0 :                                                                         true);
     379             : 
     380           0 :     const char* stop = text + byteLength;
     381             : 
     382           0 :     if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) {
     383           0 :         while (text < stop) {
     384           0 :             const char* lastText = text;
     385             :             // the last 2 parameters are ignored
     386           0 :             const SkGlyph& glyph = glyphCacheProc(cache, &text);
     387             : 
     388           0 :             if (glyph.fWidth) {
     389           0 :                 SkScalar x = offset.x() + pos[0];
     390           0 :                 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
     391             : 
     392           0 :                 if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x, y,
     393             :                                    paint.filteredPremulGrColor(), cache, textRatio, viewMatrix)) {
     394             :                     // couldn't append, send to fallback
     395           0 :                     fallbackTxt.append(SkToInt(text-lastText), lastText);
     396           0 :                     *fallbackPos.append() = pos[0];
     397           0 :                     if (2 == scalarsPerPosition) {
     398           0 :                         *fallbackPos.append() = pos[1];
     399             :                     }
     400             :                 }
     401             :             }
     402           0 :             pos += scalarsPerPosition;
     403             :         }
     404             :     } else {
     405           0 :         SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? SK_ScalarHalf
     406           0 :                                                                              : SK_Scalar1;
     407           0 :         while (text < stop) {
     408           0 :             const char* lastText = text;
     409             :             // the last 2 parameters are ignored
     410           0 :             const SkGlyph& glyph = glyphCacheProc(cache, &text);
     411             : 
     412           0 :             if (glyph.fWidth) {
     413           0 :                 SkScalar x = offset.x() + pos[0];
     414           0 :                 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
     415             : 
     416           0 :                 SkScalar advanceX = SkFloatToScalar(glyph.fAdvanceX) * alignMul * textRatio;
     417           0 :                 SkScalar advanceY = SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio;
     418             : 
     419           0 :                 if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x - advanceX,
     420             :                                    y - advanceY, paint.filteredPremulGrColor(), cache, textRatio,
     421             :                                    viewMatrix)) {
     422             :                     // couldn't append, send to fallback
     423           0 :                     fallbackTxt.append(SkToInt(text-lastText), lastText);
     424           0 :                     *fallbackPos.append() = pos[0];
     425           0 :                     if (2 == scalarsPerPosition) {
     426           0 :                         *fallbackPos.append() = pos[1];
     427             :                     }
     428             :                 }
     429             :             }
     430           0 :             pos += scalarsPerPosition;
     431             :         }
     432             :     }
     433             : 
     434           0 :     SkGlyphCache::AttachCache(cache);
     435           0 :     if (fallbackTxt.count()) {
     436           0 :         blob->initOverride(runIndex);
     437           0 :         GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props, paint, scalerContextFlags,
     438           0 :                                     viewMatrix, fallbackTxt.begin(), fallbackTxt.count(),
     439           0 :                                     fallbackPos.begin(), scalarsPerPosition, offset);
     440             :     }
     441             : }
     442             : 
     443           0 : bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* cache,
     444             :                                 GrAtlasTextStrike** strike, const SkGlyph& skGlyph,
     445             :                                 SkScalar sx, SkScalar sy, GrColor color,
     446             :                                 SkGlyphCache* glyphCache,
     447             :                                 SkScalar textRatio, const SkMatrix& viewMatrix) {
     448           0 :     if (!*strike) {
     449           0 :         *strike = cache->getStrike(glyphCache);
     450             :     }
     451             : 
     452           0 :     GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
     453             :                                          skGlyph.getSubXFixed(),
     454             :                                          skGlyph.getSubYFixed(),
     455           0 :                                          GrGlyph::kDistance_MaskStyle);
     456           0 :     GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, glyphCache);
     457           0 :     if (!glyph) {
     458           0 :         return true;
     459             :     }
     460             : 
     461             :     // fallback to color glyph support
     462           0 :     if (kA8_GrMaskFormat != glyph->fMaskFormat) {
     463           0 :         return false;
     464             :     }
     465             : 
     466           0 :     SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
     467           0 :     SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
     468           0 :     SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset);
     469           0 :     SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset);
     470             : 
     471           0 :     SkScalar scale = textRatio;
     472           0 :     dx *= scale;
     473           0 :     dy *= scale;
     474           0 :     width *= scale;
     475           0 :     height *= scale;
     476           0 :     sx += dx;
     477           0 :     sy += dy;
     478           0 :     SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);
     479             : 
     480           0 :     blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, glyphCache, skGlyph,
     481           0 :                       sx - dx, sy - dy, scale, false);
     482           0 :     return true;
     483             : }
     484             : 
     485           0 : void GrTextUtils::DrawTextAsPath(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip,
     486             :                                  const SkPaint& paint, const SkMatrix& viewMatrix,
     487             :                                  const char text[], size_t byteLength, SkScalar x, SkScalar y,
     488             :                                  const SkIRect& clipBounds) {
     489           0 :     SkTextToPathIter iter(text, byteLength, paint, true);
     490             : 
     491             :     SkMatrix    matrix;
     492           0 :     matrix.setScale(iter.getPathScale(), iter.getPathScale());
     493           0 :     matrix.postTranslate(x, y);
     494             : 
     495             :     const SkPath* iterPath;
     496           0 :     SkScalar xpos, prevXPos = 0;
     497             : 
     498           0 :     while (iter.next(&iterPath, &xpos)) {
     499           0 :         matrix.postTranslate(xpos - prevXPos, 0);
     500           0 :         if (iterPath) {
     501           0 :             const SkPaint& pnt = iter.getPaint();
     502           0 :             GrBlurUtils::drawPathWithMaskFilter(context, rtc, clip, *iterPath,
     503           0 :                                                 pnt, viewMatrix, &matrix, clipBounds, false);
     504             :         }
     505           0 :         prevXPos = xpos;
     506             :     }
     507           0 : }
     508             : 
     509           0 : void GrTextUtils::DrawPosTextAsPath(GrContext* context,
     510             :                                     GrRenderTargetContext* rtc,
     511             :                                     const SkSurfaceProps& props,
     512             :                                     const GrClip& clip,
     513             :                                     const SkPaint& origPaint, const SkMatrix& viewMatrix,
     514             :                                     const char text[], size_t byteLength,
     515             :                                     const SkScalar pos[], int scalarsPerPosition,
     516             :                                     const SkPoint& offset, const SkIRect& clipBounds) {
     517             :     // setup our std paint, in hopes of getting hits in the cache
     518           0 :     SkPaint paint(origPaint);
     519           0 :     SkScalar matrixScale = paint.setupForAsPaths();
     520             : 
     521             :     SkMatrix matrix;
     522           0 :     matrix.setScale(matrixScale, matrixScale);
     523             : 
     524             :     // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
     525           0 :     paint.setStyle(SkPaint::kFill_Style);
     526           0 :     paint.setPathEffect(nullptr);
     527             : 
     528           0 :     SkPaint::GlyphCacheProc    glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
     529           0 :                                                                            paint.isDevKernText(),
     530           0 :                                                                            true);
     531           0 :     SkAutoGlyphCache           autoCache(paint, &props, nullptr);
     532           0 :     SkGlyphCache*              cache = autoCache.getCache();
     533             : 
     534           0 :     const char*        stop = text + byteLength;
     535           0 :     SkTextAlignProc    alignProc(paint.getTextAlign());
     536           0 :     SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
     537             : 
     538             :     // Now restore the original settings, so we "draw" with whatever style/stroking.
     539           0 :     paint.setStyle(origPaint.getStyle());
     540           0 :     paint.setPathEffect(origPaint.refPathEffect());
     541             : 
     542           0 :     while (text < stop) {
     543           0 :         const SkGlyph& glyph = glyphCacheProc(cache, &text);
     544           0 :         if (glyph.fWidth) {
     545           0 :             const SkPath* path = cache->findPath(glyph);
     546           0 :             if (path) {
     547             :                 SkPoint tmsLoc;
     548           0 :                 tmsProc(pos, &tmsLoc);
     549             :                 SkPoint loc;
     550           0 :                 alignProc(tmsLoc, glyph, &loc);
     551             : 
     552           0 :                 matrix[SkMatrix::kMTransX] = loc.fX;
     553           0 :                 matrix[SkMatrix::kMTransY] = loc.fY;
     554             :                 GrBlurUtils::drawPathWithMaskFilter(context, rtc, clip, *path, paint,
     555           0 :                                                     viewMatrix, &matrix, clipBounds, false);
     556             :             }
     557             :         }
     558           0 :         pos += scalarsPerPosition;
     559             :     }
     560           0 : }
     561             : 
     562           0 : bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) {
     563           0 :     return paint.getMaskFilter() ||
     564           0 :            paint.getRasterizer() ||
     565           0 :            paint.getPathEffect() ||
     566           0 :            paint.isFakeBoldText() ||
     567           0 :            paint.getStyle() != SkPaint::kFill_Style;
     568             : }
     569             : 
     570           0 : uint32_t GrTextUtils::FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint) {
     571           0 :     uint32_t flags = paint.getFlags();
     572             : 
     573           0 :     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
     574           0 :         return flags;
     575             :     }
     576             : 
     577           0 :     if (kUnknown_SkPixelGeometry == surfaceProps.pixelGeometry() || ShouldDisableLCD(paint)) {
     578           0 :         flags &= ~SkPaint::kLCDRenderText_Flag;
     579           0 :         flags |= SkPaint::kGenA8FromLCD_Flag;
     580             :     }
     581             : 
     582           0 :     return flags;
     583             : }

Generated by: LCOV version 1.13