diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 812c885bee..94a7f407e0 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -1762,14 +1762,14 @@ private: kCanonicalTextSizeForPaths = 64, }; - static bool TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM); + static bool TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM, SkScalar maxLimit); // Set flags/hinting/textSize up to use for drawing text as paths. // Returns scale factor to restore the original textSize, since will will // have change it to kCanonicalTextSizeForPaths. SkScalar setupForAsPaths(); - static SkScalar MaxCacheSize2(); + static SkScalar MaxCacheSize2(SkScalar maxLimit); friend class SkAutoGlyphCache; friend class SkAutoGlyphCacheNoGamma; diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 5068fb0151..a0f08e5916 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1353,7 +1353,7 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& ori #include "SkTextToPathIter.h" #include "SkUtils.h" -bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { +bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm, SkScalar sizeLimit) { // hairline glyphs are fast enough so we don't need to cache them if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) { return true; @@ -1366,7 +1366,7 @@ bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { SkMatrix textM; SkPaintPriv::MakeTextMatrix(&textM, paint); - return SkPaint::TooBigToUseCache(ctm, textM); + return SkPaint::TooBigToUseCache(ctm, textM, sizeLimit); } void SkDraw::drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y, diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h index 524f300e42..0561eab2ec 100644 --- a/src/core/SkDraw.h +++ b/src/core/SkDraw.h @@ -114,7 +114,7 @@ public: static RectType ComputeRectType(const SkPaint&, const SkMatrix&, SkPoint* strokeSize); - static bool ShouldDrawTextAsPaths(const SkPaint&, const SkMatrix&); + static bool ShouldDrawTextAsPaths(const SkPaint&, const SkMatrix&, SkScalar sizeLimit = 1024); void drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint&) const; void drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[], diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 0987c640c1..d659b41410 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -384,18 +384,18 @@ static bool tooBig(const SkMatrix& m, SkScalar ma2max) { mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max; } -bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM) { +bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM, SkScalar maxLimit) { SkASSERT(!ctm.hasPerspective()); SkASSERT(!textM.hasPerspective()); SkMatrix matrix; matrix.setConcat(ctm, textM); - return tooBig(matrix, MaxCacheSize2()); + return tooBig(matrix, MaxCacheSize2(maxLimit)); } -SkScalar SkPaint::MaxCacheSize2() { +SkScalar SkPaint::MaxCacheSize2(SkScalar maxLimit) { // we have a self-imposed maximum, just for memory-usage sanity - const int limit = SkMin32(SkGraphics::GetFontCachePointSizeLimit(), 1024); + const int limit = SkMin32(SkGraphics::GetFontCachePointSizeLimit(), maxLimit); const SkScalar maxSize = SkIntToScalar(limit); return maxSize * maxSize; } diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrAtlasGlyphCache.cpp index 421160f28f..edc751ec95 100644 --- a/src/gpu/text/GrAtlasGlyphCache.cpp +++ b/src/gpu/text/GrAtlasGlyphCache.cpp @@ -72,6 +72,8 @@ GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context, float maxTextureBytes, fAtlasConfigs[kARGB_GrMaskFormat].fHeight = maxDim; fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = minPlot; fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = minPlot; + + fGlyphSizeLimit = minPlot; } GrAtlasGlyphCache::~GrAtlasGlyphCache() { diff --git a/src/gpu/text/GrAtlasGlyphCache.h b/src/gpu/text/GrAtlasGlyphCache.h index 223ed6e69f..c4e1528e7b 100644 --- a/src/gpu/text/GrAtlasGlyphCache.h +++ b/src/gpu/text/GrAtlasGlyphCache.h @@ -144,6 +144,8 @@ public: return 0; } + SkScalar getGlyphSizeLimit() const { return fGlyphSizeLimit; } + bool hasGlyph(GrGlyph* glyph) { SkASSERT(glyph); return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID); @@ -261,6 +263,7 @@ private: std::unique_ptr fAtlases[kMaskFormatCount]; GrAtlasTextStrike* fPreserveStrike; GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount]; + SkScalar fGlyphSizeLimit; }; #endif diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index 41072ee296..bdbc600cc1 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -12,6 +12,7 @@ #include "SkDrawFilter.h" #include "SkFindAndPlaceGlyph.h" #include "SkGr.h" +#include "SkGraphics.h" #include "SkMakeUnique.h" #include "ops/GrMeshDrawOp.h" @@ -46,12 +47,13 @@ std::unique_ptr GrAtlasTextContext::Make(const Options& opti return std::unique_ptr(new GrAtlasTextContext(options)); } -bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, +bool GrAtlasTextContext::canDraw(const GrAtlasGlyphCache* fontCache, + const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const GrShaderCaps& shaderCaps) { return this->canDrawAsDistanceFields(skPaint, viewMatrix, props, shaderCaps) || - !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); + !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix, fontCache->getGlyphSizeLimit()); } SkColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { @@ -317,7 +319,8 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe return; } GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); - if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { + if (this->canDraw(context->getAtlasGlyphCache(), skPaint, viewMatrix, props, + *context->caps()->shaderCaps())) { sk_sp blob( this->makeDrawTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(), *context->caps()->shaderCaps(), paint, @@ -344,7 +347,8 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); if (context->abandoned()) { return; - } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { + } else if (this->canDraw(context->getAtlasGlyphCache(), skPaint, viewMatrix, props, + *context->caps()->shaderCaps())) { sk_sp blob(this->makeDrawPosTextBlob( context->getTextBlobCache(), context->getAtlasGlyphCache(), *context->caps()->shaderCaps(), paint, @@ -385,8 +389,8 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; BmpAppendGlyph(blob, runIndex, fontCache, &currStrike, - glyph, SkScalarFloorToInt(position.fX), - SkScalarFloorToInt(position.fY), + glyph, SkScalarFloorToScalar(position.fX), + SkScalarFloorToScalar(position.fY), paint.filteredPremulColor(), cache, SK_Scalar1); }); @@ -422,7 +426,8 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; BmpAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, - SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), + SkScalarFloorToScalar(position.fX), + SkScalarFloorToScalar(position.fY), paint.filteredPremulColor(), cache, textRatio); }); @@ -431,8 +436,9 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache, GrAtlasTextStrike** strike, - const SkGlyph& skGlyph, int vx, int vy, GrColor color, - SkGlyphCache* glyphCache, SkScalar textRatio) { + const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, + GrColor color, SkGlyphCache* glyphCache, + SkScalar textRatio) { if (!*strike) { *strike = fontCache->getStrike(glyphCache); } @@ -446,12 +452,13 @@ void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, return; } + SkASSERT(skGlyph.fWidth == glyph->width()); + SkASSERT(skGlyph.fHeight == glyph->height()); + SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft); SkScalar dy = SkIntToScalar(glyph->fBounds.fTop); SkScalar width = SkIntToScalar(glyph->fBounds.width()); SkScalar height = SkIntToScalar(glyph->fBounds.height()); - SkScalar sx = SkIntToScalar(vx); - SkScalar sy = SkIntToScalar(vy); dx *= textRatio; dy *= textRatio; @@ -651,6 +658,13 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkTDArray fallbackTxt; SkTDArray fallbackPos; + SkTDArray bigFallbackTxt; + SkTDArray bigFallbackPos; + SkScalar textSize = paint.skPaint().getTextSize(); + SkScalar maxTextSize = fontCache->getGlyphSizeLimit(); + SkScalar bigFallbackTextSize = maxTextSize; + SkScalar maxScale = viewMatrix.getMaxScale(); + bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW; // Setup distance field paint and text ratio @@ -689,13 +703,26 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, if (glyph.fMaskFormat != SkMask::kARGB32_Format) { DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x - advanceX, - y - advanceY, paint.filteredPremulColor(), cache, textRatio); + y - advanceY, paint.filteredPremulColor(), cache, textRatio); } else { // can't append color glyph to SDF batch, send to fallback - fallbackTxt.append(SkToInt(text - lastText), lastText); - *fallbackPos.append() = pos[0]; - if (2 == scalarsPerPosition) { - *fallbackPos.append() = pos[1]; + SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*textRatio; + SkScalar scaledGlyphSize = maxDim*maxScale; + + if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) { + bigFallbackTxt.append(SkToInt(text - lastText), lastText); + *bigFallbackPos.append() = maxScale*pos[0]; + if (2 == scalarsPerPosition) { + *bigFallbackPos.append() = maxScale*pos[1]; + } + SkScalar glyphTextSize = SkScalarFloorToScalar(maxTextSize*textSize/maxDim); + bigFallbackTextSize = SkTMin(glyphTextSize, bigFallbackTextSize); + } else { + fallbackTxt.append(SkToInt(text - lastText), lastText); + *fallbackPos.append() = pos[0]; + if (2 == scalarsPerPosition) { + *fallbackPos.append() = pos[1]; + } } } } @@ -710,6 +737,26 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, fallbackTxt.count(), fallbackPos.begin(), scalarsPerPosition, offset, SK_Scalar1); } + + if (bigFallbackTxt.count()) { + // Set up paint and matrix to scale glyphs + blob->initOverride(runIndex); + SkPaint largePaint(paint); + largePaint.setTextSize(bigFallbackTextSize); + // remove maxScale from viewMatrix and move it into textRatio + // this keeps the base glyph size consistent regardless of matrix scale + SkMatrix modMatrix(viewMatrix); + SkScalar invScale = SkScalarInvert(maxScale); + modMatrix.preScale(invScale, invScale); + SkScalar bigFallbackTextRatio = textSize*maxScale/bigFallbackTextSize; + SkPoint modOffset(offset); + modOffset *= maxScale; + GrTextUtils::Paint textPaint(&largePaint, paint.dstColorSpaceInfo()); + GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, textPaint, + scalerContextFlags, modMatrix, bigFallbackTxt.begin(), + bigFallbackTxt.count(), bigFallbackPos.begin(), + scalarsPerPosition, modOffset, bigFallbackTextRatio); + } } // TODO: merge with BmpAppendGlyph diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h index 9c44128f52..b03ffa3fbf 100644 --- a/src/gpu/text/GrAtlasTextContext.h +++ b/src/gpu/text/GrAtlasTextContext.h @@ -44,8 +44,8 @@ public: static std::unique_ptr Make(const Options& options); - bool canDraw(const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, - const GrShaderCaps&); + bool canDraw(const GrAtlasGlyphCache* fontCache, const SkPaint&, const SkMatrix& viewMatrix, + const SkSurfaceProps&, const GrShaderCaps&); void drawText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], @@ -131,7 +131,7 @@ private: const SkMatrix& viewMatrix) const; static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*, - GrAtlasTextStrike**, const SkGlyph&, int left, int top, + GrAtlasTextStrike**, const SkGlyph&, SkScalar sx, SkScalar sy, GrColor color, SkGlyphCache*, SkScalar textRatio); static void DfAppendGlyph(GrAtlasTextBlob*, int runIndex, GrAtlasGlyphCache*,