diff options
-rw-r--r-- | include/core/SkPaint.h | 32 | ||||
-rw-r--r-- | src/core/SkGlyphCache.cpp | 14 | ||||
-rw-r--r-- | src/core/SkGlyphCache.h | 15 | ||||
-rw-r--r-- | src/core/SkPaint.cpp | 432 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 419 | ||||
-rw-r--r-- | src/core/SkScalerContext.h | 49 | ||||
-rw-r--r-- | src/core/SkTypeface.cpp | 11 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.cpp | 3 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.cpp | 4 | ||||
-rw-r--r-- | src/gpu/text/GrStencilAndCoverTextContext.cpp | 5 |
10 files changed, 491 insertions, 493 deletions
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 5e5240ad4a..530b3d42b4 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -30,13 +30,11 @@ class SkMaskFilter; class SkPath; class SkPathEffect; struct SkPoint; -struct SkScalerContextEffects; class SkShader; class SkSurfaceProps; class SkTextBlob; class SkTypeface; - /** \class SkPaint SkPaint controls options applied when drawing and measuring. SkPaint collects all options outside of the SkCanvas clip and SkCanvas matrix. @@ -1680,20 +1678,6 @@ private: SkScalar measure_text(SkGlyphCache*, const char* text, size_t length, int* count, SkRect* bounds) const; - void getScalerContextDescriptor(SkScalerContextEffects*, SkAutoDescriptor*, - const SkSurfaceProps* surfaceProps, - uint32_t scalerContextFlags, const SkMatrix*) const; - - SkGlyphCache* detachCache(const SkSurfaceProps* surfaceProps, - uint32_t scalerContextFlags, - const SkMatrix*) const; - - void descriptorProc(const SkSurfaceProps* surfaceProps, uint32_t scalerContextFlags, - const SkMatrix* deviceMatrix, - void (*proc)(SkTypeface*, const SkScalerContextEffects&, - const SkDescriptor*, void*), - void* context) const; - /* * The luminance color is used to determine which Gamma Canonical color to map to. This is * really only used by backends which want to cache glyph masks, and need some way to know if @@ -1728,20 +1712,20 @@ private: static SkScalar MaxCacheSize2(SkScalar maxLimit); + friend class GrAtlasTextBlob; + friend class GrAtlasTextContext; + friend class GrGLPathRendering; + friend class GrPathRendering; + friend class GrStencilAndCoverTextContext; + friend class GrTextUtils; friend class SkAutoGlyphCache; friend class SkAutoGlyphCacheNoGamma; + friend class SkCanonicalizePaint; friend class SkCanvas; friend class SkDraw; friend class SkPDFDevice; - friend class GrAtlasTextBlob; - friend class GrAtlasTextContext; - friend class GrStencilAndCoverTextContext; - friend class GrPathRendering; - friend class GrTextUtils; - friend class GrGLPathRendering; - friend class SkScalerContext; + friend class SkScalerContext; // for computeLuminanceColor() friend class SkTextBaseIter; - friend class SkCanonicalizePaint; }; #endif diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp index 9ddf70cc4d..16f18639bd 100644 --- a/src/core/SkGlyphCache.cpp +++ b/src/core/SkGlyphCache.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ + #include "SkGlyphCache.h" #include "SkGlyphCache_Globals.h" #include "SkGraphics.h" @@ -810,3 +811,16 @@ void SkGraphics::PurgeFontCache() { // TODO(herb): clean up TLS apis. size_t SkGraphics::GetTLSFontCacheLimit() { return 0; } void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { } + +SkGlyphCache* SkGlyphCache::DetachCacheUsingPaint(const SkPaint& paint, + const SkSurfaceProps* surfaceProps, + SkScalerContextFlags scalerContextFlags, + const SkMatrix* deviceMatrix) { + SkAutoDescriptor ad; + SkScalerContextEffects effects; + + auto desc = SkScalerContext::CreateDescriptorAndEffectsUsingPaint( + paint, surfaceProps, scalerContextFlags, deviceMatrix, &ad, &effects); + + return SkGlyphCache::DetachCache(paint.getTypeface(), effects, desc); +} diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h index 834db7ada0..052e07277e 100644 --- a/src/core/SkGlyphCache.h +++ b/src/core/SkGlyphCache.h @@ -138,6 +138,11 @@ public: return VisitCache(typeface, effects, desc, DetachProc, nullptr); } + static SkGlyphCache* DetachCacheUsingPaint(const SkPaint& paint, + const SkSurfaceProps* surfaceProps, + SkScalerContextFlags scalerContextFlags, + const SkMatrix* deviceMatrix); + static void Dump(); /** Dump memory usage statistics of all the attaches caches in the process using the @@ -262,15 +267,17 @@ public: SkAutoGlyphCache(const SkPaint& paint, const SkSurfaceProps* surfaceProps, const SkMatrix* matrix) - : INHERITED(paint.detachCache(surfaceProps, - SkScalerContextFlags::kFakeGammaAndBoostContrast, - matrix)) + : INHERITED( + SkGlyphCache::DetachCacheUsingPaint( + paint, surfaceProps, + SkScalerContextFlags::kFakeGammaAndBoostContrast, matrix)) {} SkAutoGlyphCache(const SkPaint& paint, const SkSurfaceProps* surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix* matrix) - : INHERITED(paint.detachCache(surfaceProps, scalerContextFlags, matrix)) + : INHERITED( + SkGlyphCache::DetachCacheUsingPaint(paint, surfaceProps, scalerContextFlags, matrix)) {} private: using INHERITED = std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>; diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 0686c3b017..2e5d22c538 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -398,11 +398,6 @@ SkScalar SkPaint::MaxCacheSize2(SkScalar maxLimit) { #include "SkGlyphCache.h" #include "SkUtils.h" -static void DetachDescProc(SkTypeface* typeface, const SkScalerContextEffects& effects, - const SkDescriptor* desc, void* context) { - *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(typeface, effects, desc); -} - int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyphs[]) const { if (byteLength == 0) { return 0; @@ -915,11 +910,6 @@ static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) { return false; // don't detach the cache } -static void FontMetricsDescProc(SkTypeface* typeface, const SkScalerContextEffects& effects, - const SkDescriptor* desc, void* context) { - SkGlyphCache::VisitCache(typeface, effects, desc, FontMetricsCacheProc, context); -} - SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { SkCanonicalizePaint canon(*this); const SkPaint& paint = canon.getPaint(); @@ -936,8 +926,13 @@ SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { metrics = &storage; } - paint.descriptorProc(nullptr, SkScalerContextFlags::kNone, zoomPtr, - FontMetricsDescProc, metrics); + SkAutoDescriptor ad; + SkScalerContextEffects effects; + + auto desc = SkScalerContext::CreateDescriptorAndEffectsUsingPaint( + paint, nullptr, SkScalerContextFlags::kNone, zoomPtr, &ad, &effects); + + SkGlyphCache::VisitCache(paint.getTypeface(), effects, desc, FontMetricsCacheProc, metrics); if (scale) { SkPaintPriv::ScaleFontMetrics(metrics, scale); @@ -1217,31 +1212,6 @@ SkRect SkPaint::getFontBounds() const { return bounds; } -static SkMask::Format compute_mask_format(const SkPaint& paint) { - uint32_t flags = paint.getFlags(); - - // Antialiasing being disabled trumps all other settings. - if (!(flags & SkPaint::kAntiAlias_Flag)) { - return SkMask::kBW_Format; - } - - if (flags & SkPaint::kLCDRenderText_Flag) { - return SkMask::kLCD16_Format; - } - - return SkMask::kA8_Format; -} - -// if linear-text is on, then we force hinting to be off (since that's sort of -// the point of linear-text. -static SkPaint::Hinting computeHinting(const SkPaint& paint) { - SkPaint::Hinting h = paint.getHinting(); - if (paint.isLinearText()) { - h = SkPaint::kNo_Hinting; - } - return h; -} - // return true if the paint is just a single color (i.e. not a shader). If its // a shader, then we can't compute a const luminance for it :( static bool justAColor(const SkPaint& paint, SkColor* color) { @@ -1270,250 +1240,6 @@ SkColor SkPaint::computeLuminanceColor() const { #define assert_byte(x) SkASSERT(0 == ((x) >> 8)) -// Beyond this size, LCD doesn't appreciably improve quality, but it always -// cost more RAM and draws slower, so we set a cap. -#ifndef SK_MAX_SIZE_FOR_LCDTEXT - #define SK_MAX_SIZE_FOR_LCDTEXT 48 -#endif - -const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT; - -static bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) { - if (checkPost2x2) { - SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] - - rec.fPost2x2[1][0] * rec.fPost2x2[0][1]; - area *= rec.fTextSize * rec.fTextSize; - return area > gMaxSize2ForLCDText; - } else { - return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT; - } -} - -/* - * Return the scalar with only limited fractional precision. Used to consolidate matrices - * that vary only slightly when we create our key into the font cache, since the font scaler - * typically returns the same looking resuts for tiny changes in the matrix. - */ -static SkScalar sk_relax(SkScalar x) { - SkScalar n = SkScalarRoundToScalar(x * 1024); - return n / 1024.0f; -} - -void SkScalerContext::MakeRecAndEffects(const SkPaint& paint, - const SkSurfaceProps* surfaceProps, - const SkMatrix* deviceMatrix, - SkScalerContextFlags scalerContextFlags, - SkScalerContextRec* rec, - SkScalerContextEffects* effects) { - SkASSERT(deviceMatrix == nullptr || !deviceMatrix->hasPerspective()); - - SkTypeface* typeface = paint.getTypeface(); - if (nullptr == typeface) { - typeface = SkTypeface::GetDefaultTypeface(); - } - rec->fFontID = typeface->uniqueID(); - rec->fTextSize = paint.getTextSize(); - rec->fPreScaleX = paint.getTextScaleX(); - rec->fPreSkewX = paint.getTextSkewX(); - - bool checkPost2x2 = false; - - if (deviceMatrix) { - const SkMatrix::TypeMask mask = deviceMatrix->getType(); - if (mask & SkMatrix::kScale_Mask) { - rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX()); - rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY()); - checkPost2x2 = true; - } else { - rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; - } - if (mask & SkMatrix::kAffine_Mask) { - rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX()); - rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY()); - checkPost2x2 = true; - } else { - rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; - } - } else { - rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; - rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; - } - - SkPaint::Style style = paint.getStyle(); - SkScalar strokeWidth = paint.getStrokeWidth(); - - unsigned flags = 0; - - if (paint.isFakeBoldText()) { -#ifdef SK_USE_FREETYPE_EMBOLDEN - flags |= SkScalerContext::kEmbolden_Flag; -#else - SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(), - kStdFakeBoldInterpKeys, - kStdFakeBoldInterpValues, - kStdFakeBoldInterpLength); - SkScalar extra = paint.getTextSize() * fakeBoldScale; - - if (style == SkPaint::kFill_Style) { - style = SkPaint::kStrokeAndFill_Style; - strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" - } else { - strokeWidth += extra; - } -#endif - } - - if (paint.isDevKernText()) { - flags |= SkScalerContext::kDevKernText_Flag; - } - - if (style != SkPaint::kFill_Style && strokeWidth > 0) { - rec->fFrameWidth = strokeWidth; - rec->fMiterLimit = paint.getStrokeMiter(); - rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); - rec->fStrokeCap = SkToU8(paint.getStrokeCap()); - - if (style == SkPaint::kStrokeAndFill_Style) { - flags |= SkScalerContext::kFrameAndFill_Flag; - } - } else { - rec->fFrameWidth = 0; - rec->fMiterLimit = 0; - rec->fStrokeJoin = 0; - rec->fStrokeCap = 0; - } - - rec->fMaskFormat = SkToU8(compute_mask_format(paint)); - - if (SkMask::kLCD16_Format == rec->fMaskFormat) { - if (too_big_for_lcd(*rec, checkPost2x2)) { - rec->fMaskFormat = SkMask::kA8_Format; - flags |= SkScalerContext::kGenA8FromLCD_Flag; - } else { - SkPixelGeometry geometry = surfaceProps - ? surfaceProps->pixelGeometry() - : SkSurfacePropsDefaultPixelGeometry(); - switch (geometry) { - case kUnknown_SkPixelGeometry: - // eeek, can't support LCD - rec->fMaskFormat = SkMask::kA8_Format; - flags |= SkScalerContext::kGenA8FromLCD_Flag; - break; - case kRGB_H_SkPixelGeometry: - // our default, do nothing. - break; - case kBGR_H_SkPixelGeometry: - flags |= SkScalerContext::kLCD_BGROrder_Flag; - break; - case kRGB_V_SkPixelGeometry: - flags |= SkScalerContext::kLCD_Vertical_Flag; - break; - case kBGR_V_SkPixelGeometry: - flags |= SkScalerContext::kLCD_Vertical_Flag; - flags |= SkScalerContext::kLCD_BGROrder_Flag; - break; - } - } - } - - if (paint.isEmbeddedBitmapText()) { - flags |= SkScalerContext::kEmbeddedBitmapText_Flag; - } - if (paint.isSubpixelText()) { - flags |= SkScalerContext::kSubpixelPositioning_Flag; - } - if (paint.isAutohinted()) { - flags |= SkScalerContext::kForceAutohinting_Flag; - } - if (paint.isVerticalText()) { - flags |= SkScalerContext::kVertical_Flag; - } - if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { - flags |= SkScalerContext::kGenA8FromLCD_Flag; - } - rec->fFlags = SkToU16(flags); - - // these modify fFlags, so do them after assigning fFlags - rec->setHinting(computeHinting(paint)); - - rec->setLuminanceColor(paint.computeLuminanceColor()); - - // For now always set the paint gamma equal to the device gamma. - // The math in SkMaskGamma can handle them being different, - // but it requires superluminous masks when - // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large. - rec->setDeviceGamma(SK_GAMMA_EXPONENT); - rec->setPaintGamma(SK_GAMMA_EXPONENT); - -#ifdef SK_GAMMA_CONTRAST - rec->setContrast(SK_GAMMA_CONTRAST); -#else - // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. - // With lower values small text appears washed out (though correctly so). - // With higher values lcd fringing is worse and the smoothing effect of - // partial coverage is diminished. - rec->setContrast(0.5f); -#endif - - rec->fReservedAlign = 0; - - // Allow the fonthost to modify our rec before we use it as a key into the - // cache. This way if we're asking for something that they will ignore, - // they can modify our rec up front, so we don't create duplicate cache - // entries. - typeface->onFilterRec(rec); - - if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) { - rec->ignoreGamma(); - } - if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) { - rec->setContrast(0); - } - - new (effects) SkScalerContextEffects{paint}; - if (effects->fPathEffect) { - rec->fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion - // seems like we could support kLCD as well at this point... - } - if (effects->fMaskFilter) { - // force antialiasing with maskfilters - rec->fMaskFormat = SkMask::kA8_Format; - // Pre-blend is not currently applied to filtered text. - // The primary filter is blur, for which contrast makes no sense, - // and for which the destination guess error is more visible. - // Also, all existing users of blur have calibrated for linear. - rec->ignorePreBlend(); - } - - // If we're asking for A8, we force the colorlum to be gray, since that - // limits the number of unique entries, and the scaler will only look at - // the lum of one of them. - switch (rec->fMaskFormat) { - case SkMask::kLCD16_Format: { - // filter down the luminance color to a finite number of bits - SkColor color = rec->getLuminanceColor(); - rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); - break; - } - case SkMask::kA8_Format: { - // filter down the luminance to a single component, since A8 can't - // use per-component information - SkColor color = rec->getLuminanceColor(); - U8CPU lum = SkComputeLuminance(SkColorGetR(color), - SkColorGetG(color), - SkColorGetB(color)); - // reduce to our finite number of bits - color = SkColorSetRGB(lum, lum, lum); - rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); - break; - } - case SkMask::kBW_Format: - // No need to differentiate gamma or apply contrast if we're BW - rec->ignorePreBlend(); - break; - } -} - /** * In order to call cachedDeviceLuminance, cachedPaintLuminance, or * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue @@ -1548,46 +1274,6 @@ static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma return *gMaskGamma; } -void SkPaint::getScalerContextDescriptor(SkScalerContextEffects* effects, - SkAutoDescriptor* ad, - const SkSurfaceProps* surfaceProps, - uint32_t scalerContextFlags, - const SkMatrix* deviceMatrix) const { - SkScalerContextRec rec; - - SkScalerContext::MakeRecAndEffects( - *this, surfaceProps, deviceMatrix, (SkScalerContextFlags)scalerContextFlags, &rec, effects); - auto alloc = [ad](size_t size) { - ad->reset(size); - return ad->getDesc(); - }; - SkScalerContext::CreateDescriptorGivenRecAndEffects(rec, *effects, alloc); -} - -void SkPaint::descriptorProc(const SkSurfaceProps* surfaceProps, - uint32_t scalerContextFlags, - const SkMatrix* deviceMatrix, - void (*proc)(SkTypeface*, const SkScalerContextEffects&, - const SkDescriptor*, void*), - void* context) const { - SkAutoDescriptor ad; - SkScalerContextEffects effects; - - this->getScalerContextDescriptor(&effects, &ad, surfaceProps, scalerContextFlags, - deviceMatrix); - - auto desc = ad.getDesc(); - proc(fTypeface.get(), effects, desc, context); -} - -SkGlyphCache* SkPaint::detachCache(const SkSurfaceProps* surfaceProps, - uint32_t scalerContextFlags, - const SkMatrix* deviceMatrix) const { - SkGlyphCache* cache; - this->descriptorProc(surfaceProps, scalerContextFlags, deviceMatrix, DetachDescProc, &cache); - return cache; -} - /** * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend. @@ -1632,106 +1318,6 @@ bool SkScalerContext::GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, Sk return true; } -size_t SkScalerContext::CalculateSizeAndFlatten( - const SkScalerContextRec& rec, - const SkScalerContextEffects& effects, - SkBinaryWriteBuffer* pathEffectBuffer, - SkBinaryWriteBuffer* maskFilterBuffer) { - size_t descSize = sizeof(rec); - int entryCount = 1; - - if (effects.fPathEffect) { - effects.fPathEffect->flatten(*pathEffectBuffer); - descSize += pathEffectBuffer->bytesWritten(); - entryCount += 1; - } - if (effects.fMaskFilter) { - effects.fMaskFilter->flatten(*maskFilterBuffer); - descSize += maskFilterBuffer->bytesWritten(); - entryCount += 1; - } - - descSize += SkDescriptor::ComputeOverhead(entryCount); - return descSize; -} - -#ifdef SK_DEBUG -#define TEST_DESC -#endif - -#ifdef TEST_DESC -static void test_desc(const SkScalerContextRec& rec, - const SkScalerContextEffects& effects, - SkBinaryWriteBuffer* peBuffer, - SkBinaryWriteBuffer* mfBuffer, - const SkDescriptor* desc) { - // Check that we completely write the bytes in desc (our key), and that - // there are no uninitialized bytes. If there were, then we would get - // false-misses (or worse, false-hits) in our fontcache. - // - // We do this buy filling 2 others, one with 0s and the other with 1s - // and create those, and then check that all 3 are identical. - SkAutoDescriptor ad1(desc->getLength()); - SkAutoDescriptor ad2(desc->getLength()); - SkDescriptor* desc1 = ad1.getDesc(); - SkDescriptor* desc2 = ad2.getDesc(); - - memset(desc1, 0x00, desc->getLength()); - memset(desc2, 0xFF, desc->getLength()); - - desc1->init(); - desc2->init(); - desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - - auto add_flattenable = [](SkDescriptor* desc, uint32_t tag, - SkBinaryWriteBuffer* buffer) { - buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr)); - }; - - if (effects.fPathEffect) { - add_flattenable(desc1, kPathEffect_SkDescriptorTag, peBuffer); - add_flattenable(desc2, kPathEffect_SkDescriptorTag, peBuffer); - } - if (effects.fMaskFilter) { - add_flattenable(desc1, kMaskFilter_SkDescriptorTag, mfBuffer); - add_flattenable(desc2, kMaskFilter_SkDescriptorTag, mfBuffer); - } - - SkASSERT(desc->getLength() == desc1->getLength()); - SkASSERT(desc->getLength() == desc2->getLength()); - desc1->computeChecksum(); - desc2->computeChecksum(); - SkASSERT(!memcmp(desc, desc1, desc->getLength())); - SkASSERT(!memcmp(desc, desc2, desc->getLength())); -} -#endif - -void SkScalerContext::GenerateDescriptor(const SkScalerContextRec& rec, - const SkScalerContextEffects& effects, - SkBinaryWriteBuffer* pathEffectBuffer, - SkBinaryWriteBuffer* maskFilterBuffer, - SkDescriptor* desc) { - desc->init(); - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - - auto add = [&desc](uint32_t tag, SkBinaryWriteBuffer* buffer) { - buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr)); - }; - - if (effects.fPathEffect) { - add(kPathEffect_SkDescriptorTag, pathEffectBuffer); - } - if (effects.fMaskFilter) { - add(kMaskFilter_SkDescriptorTag, maskFilterBuffer); - } - - desc->computeChecksum(); - #ifdef TEST_DESC - test_desc(rec, effects, pathEffectBuffer, maskFilterBuffer, desc); - #endif -} - /////////////////////////////////////////////////////////////////////////////// #include "SkStream.h" @@ -2171,7 +1757,9 @@ SkTextBaseIter::SkTextBaseIter(const char text[], size_t length, } // SRGBTODO: Is this correct? - fCache = fPaint.detachCache(nullptr, SkScalerContextFlags::kFakeGammaAndBoostContrast, nullptr); + fCache = SkGlyphCache::DetachCacheUsingPaint(fPaint, nullptr, + SkScalerContextFlags::kFakeGammaAndBoostContrast, + nullptr); SkPaint::Style style = SkPaint::kFill_Style; sk_sp<SkPathEffect> pe; diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index d082232986..f1ac9c18da 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -5,6 +5,8 @@ * found in the LICENSE file. */ +#include "SkGlyphCache.h" +#include "SkPaint.h" #include "SkScalerContext.h" #include "SkAutoMalloc.h" @@ -23,6 +25,8 @@ #include "SkReadBuffer.h" #include "SkStroke.h" #include "SkStrokeRec.h" +#include "SkSurfacePriv.h" +#include "SkTextFormatParams.h" #include "SkWriteBuffer.h" void SkGlyph::toMask(SkMask* mask) const { @@ -835,3 +839,418 @@ std::unique_ptr<SkScalerContext> SkTypeface::createScalerContext( } return c; } + +/* + * Return the scalar with only limited fractional precision. Used to consolidate matrices + * that vary only slightly when we create our key into the font cache, since the font scaler + * typically returns the same looking resuts for tiny changes in the matrix. + */ +static SkScalar sk_relax(SkScalar x) { + SkScalar n = SkScalarRoundToScalar(x * 1024); + return n / 1024.0f; +} + +static SkMask::Format compute_mask_format(const SkPaint& paint) { + uint32_t flags = paint.getFlags(); + + // Antialiasing being disabled trumps all other settings. + if (!(flags & SkPaint::kAntiAlias_Flag)) { + return SkMask::kBW_Format; + } + + if (flags & SkPaint::kLCDRenderText_Flag) { + return SkMask::kLCD16_Format; + } + + return SkMask::kA8_Format; +} + +// Beyond this size, LCD doesn't appreciably improve quality, but it always +// cost more RAM and draws slower, so we set a cap. +#ifndef SK_MAX_SIZE_FOR_LCDTEXT + #define SK_MAX_SIZE_FOR_LCDTEXT 48 +#endif + +const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT; + +static bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) { + if (checkPost2x2) { + SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] - + rec.fPost2x2[1][0] * rec.fPost2x2[0][1]; + area *= rec.fTextSize * rec.fTextSize; + return area > gMaxSize2ForLCDText; + } else { + return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT; + } +} + +// if linear-text is on, then we force hinting to be off (since that's sort of +// the point of linear-text. +static SkPaint::Hinting computeHinting(const SkPaint& paint) { + SkPaint::Hinting h = paint.getHinting(); + if (paint.isLinearText()) { + h = SkPaint::kNo_Hinting; + } + return h; +} + +// The only reason this is not file static is because it needs the context of SkScalerContext to +// access SkPaint::computeLuminanceColor. +void SkScalerContext::MakeRecAndEffects(const SkPaint& paint, + const SkSurfaceProps* surfaceProps, + const SkMatrix* deviceMatrix, + SkScalerContextFlags scalerContextFlags, + SkScalerContextRec* rec, + SkScalerContextEffects* effects) { + SkASSERT(deviceMatrix == nullptr || !deviceMatrix->hasPerspective()); + + SkTypeface* typeface = paint.getTypeface(); + if (nullptr == typeface) { + typeface = SkTypeface::GetDefaultTypeface(); + } + rec->fFontID = typeface->uniqueID(); + rec->fTextSize = paint.getTextSize(); + rec->fPreScaleX = paint.getTextScaleX(); + rec->fPreSkewX = paint.getTextSkewX(); + + bool checkPost2x2 = false; + + if (deviceMatrix) { + const SkMatrix::TypeMask mask = deviceMatrix->getType(); + if (mask & SkMatrix::kScale_Mask) { + rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX()); + rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY()); + checkPost2x2 = true; + } else { + rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; + } + if (mask & SkMatrix::kAffine_Mask) { + rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX()); + rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY()); + checkPost2x2 = true; + } else { + rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; + } + } else { + rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; + rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; + } + + SkPaint::Style style = paint.getStyle(); + SkScalar strokeWidth = paint.getStrokeWidth(); + + unsigned flags = 0; + + if (paint.isFakeBoldText()) { +#ifdef SK_USE_FREETYPE_EMBOLDEN + flags |= SkScalerContext::kEmbolden_Flag; +#else + SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(), + kStdFakeBoldInterpKeys, + kStdFakeBoldInterpValues, + kStdFakeBoldInterpLength); + SkScalar extra = paint.getTextSize() * fakeBoldScale; + + if (style == SkPaint::kFill_Style) { + style = SkPaint::kStrokeAndFill_Style; + strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" + } else { + strokeWidth += extra; + } +#endif + } + + if (paint.isDevKernText()) { + flags |= SkScalerContext::kDevKernText_Flag; + } + + if (style != SkPaint::kFill_Style && strokeWidth > 0) { + rec->fFrameWidth = strokeWidth; + rec->fMiterLimit = paint.getStrokeMiter(); + rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); + rec->fStrokeCap = SkToU8(paint.getStrokeCap()); + + if (style == SkPaint::kStrokeAndFill_Style) { + flags |= SkScalerContext::kFrameAndFill_Flag; + } + } else { + rec->fFrameWidth = 0; + rec->fMiterLimit = 0; + rec->fStrokeJoin = 0; + rec->fStrokeCap = 0; + } + + rec->fMaskFormat = SkToU8(compute_mask_format(paint)); + + if (SkMask::kLCD16_Format == rec->fMaskFormat) { + if (too_big_for_lcd(*rec, checkPost2x2)) { + rec->fMaskFormat = SkMask::kA8_Format; + flags |= SkScalerContext::kGenA8FromLCD_Flag; + } else { + SkPixelGeometry geometry = surfaceProps + ? surfaceProps->pixelGeometry() + : SkSurfacePropsDefaultPixelGeometry(); + switch (geometry) { + case kUnknown_SkPixelGeometry: + // eeek, can't support LCD + rec->fMaskFormat = SkMask::kA8_Format; + flags |= SkScalerContext::kGenA8FromLCD_Flag; + break; + case kRGB_H_SkPixelGeometry: + // our default, do nothing. + break; + case kBGR_H_SkPixelGeometry: + flags |= SkScalerContext::kLCD_BGROrder_Flag; + break; + case kRGB_V_SkPixelGeometry: + flags |= SkScalerContext::kLCD_Vertical_Flag; + break; + case kBGR_V_SkPixelGeometry: + flags |= SkScalerContext::kLCD_Vertical_Flag; + flags |= SkScalerContext::kLCD_BGROrder_Flag; + break; + } + } + } + + if (paint.isEmbeddedBitmapText()) { + flags |= SkScalerContext::kEmbeddedBitmapText_Flag; + } + if (paint.isSubpixelText()) { + flags |= SkScalerContext::kSubpixelPositioning_Flag; + } + if (paint.isAutohinted()) { + flags |= SkScalerContext::kForceAutohinting_Flag; + } + if (paint.isVerticalText()) { + flags |= SkScalerContext::kVertical_Flag; + } + if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { + flags |= SkScalerContext::kGenA8FromLCD_Flag; + } + rec->fFlags = SkToU16(flags); + + // these modify fFlags, so do them after assigning fFlags + rec->setHinting(computeHinting(paint)); + + rec->setLuminanceColor(paint.computeLuminanceColor()); + + // For now always set the paint gamma equal to the device gamma. + // The math in SkMaskGamma can handle them being different, + // but it requires superluminous masks when + // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large. + rec->setDeviceGamma(SK_GAMMA_EXPONENT); + rec->setPaintGamma(SK_GAMMA_EXPONENT); + +#ifdef SK_GAMMA_CONTRAST + rec->setContrast(SK_GAMMA_CONTRAST); +#else + // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. + // With lower values small text appears washed out (though correctly so). + // With higher values lcd fringing is worse and the smoothing effect of + // partial coverage is diminished. + rec->setContrast(0.5f); +#endif + + rec->fReservedAlign = 0; + + // Allow the fonthost to modify our rec before we use it as a key into the + // cache. This way if we're asking for something that they will ignore, + // they can modify our rec up front, so we don't create duplicate cache + // entries. + typeface->onFilterRec(rec); + + if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) { + rec->ignoreGamma(); + } + if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) { + rec->setContrast(0); + } + + new (effects) SkScalerContextEffects{paint}; + if (effects->fPathEffect) { + rec->fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion + // seems like we could support kLCD as well at this point... + } + if (effects->fMaskFilter) { + // force antialiasing with maskfilters + rec->fMaskFormat = SkMask::kA8_Format; + // Pre-blend is not currently applied to filtered text. + // The primary filter is blur, for which contrast makes no sense, + // and for which the destination guess error is more visible. + // Also, all existing users of blur have calibrated for linear. + rec->ignorePreBlend(); + } + + // If we're asking for A8, we force the colorlum to be gray, since that + // limits the number of unique entries, and the scaler will only look at + // the lum of one of them. + switch (rec->fMaskFormat) { + case SkMask::kLCD16_Format: { + // filter down the luminance color to a finite number of bits + SkColor color = rec->getLuminanceColor(); + rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); + break; + } + case SkMask::kA8_Format: { + // filter down the luminance to a single component, since A8 can't + // use per-component information + SkColor color = rec->getLuminanceColor(); + U8CPU lum = SkComputeLuminance(SkColorGetR(color), + SkColorGetG(color), + SkColorGetB(color)); + // reduce to our finite number of bits + color = SkColorSetRGB(lum, lum, lum); + rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); + break; + } + case SkMask::kBW_Format: + // No need to differentiate gamma or apply contrast if we're BW + rec->ignorePreBlend(); + break; + } +} + + +SkDescriptor* SkScalerContext::CreateDescriptorAndEffectsUsingPaint( + const SkPaint& paint, const SkSurfaceProps* surfaceProps, + SkScalerContextFlags scalerContextFlags, + const SkMatrix* deviceMatrix, SkAutoDescriptor* ad, + SkScalerContextEffects* effects) { + + SkScalerContextRec rec; + MakeRecAndEffects(paint, surfaceProps, deviceMatrix, scalerContextFlags, &rec, effects); + return AutoDescriptorGivenRecAndEffects(rec, *effects, ad); +} + +static size_t calculate_size_and_flatten( + const SkScalerContextRec& rec, + const SkScalerContextEffects& effects, + SkBinaryWriteBuffer* pathEffectBuffer, + SkBinaryWriteBuffer* maskFilterBuffer) +{ + size_t descSize = sizeof(rec); + int entryCount = 1; + + if (effects.fPathEffect) { + effects.fPathEffect->flatten(*pathEffectBuffer); + descSize += pathEffectBuffer->bytesWritten(); + entryCount += 1; + } + if (effects.fMaskFilter) { + effects.fMaskFilter->flatten(*maskFilterBuffer); + descSize += maskFilterBuffer->bytesWritten(); + entryCount += 1; + } + + descSize += SkDescriptor::ComputeOverhead(entryCount); + return descSize; +} + +#ifdef SK_DEBUG + #define TEST_DESC +#endif + +#ifdef TEST_DESC +static void test_desc(const SkScalerContextRec& rec, + const SkScalerContextEffects& effects, + SkBinaryWriteBuffer* peBuffer, + SkBinaryWriteBuffer* mfBuffer, + const SkDescriptor* desc) { + // Check that we completely write the bytes in desc (our key), and that + // there are no uninitialized bytes. If there were, then we would get + // false-misses (or worse, false-hits) in our fontcache. + // + // We do this buy filling 2 others, one with 0s and the other with 1s + // and create those, and then check that all 3 are identical. + SkAutoDescriptor ad1(desc->getLength()); + SkAutoDescriptor ad2(desc->getLength()); + SkDescriptor* desc1 = ad1.getDesc(); + SkDescriptor* desc2 = ad2.getDesc(); + + memset(desc1, 0x00, desc->getLength()); + memset(desc2, 0xFF, desc->getLength()); + + desc1->init(); + desc2->init(); + desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + + auto add_flattenable = [](SkDescriptor* desc, uint32_t tag, + SkBinaryWriteBuffer* buffer) { + buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr)); + }; + + if (effects.fPathEffect) { + add_flattenable(desc1, kPathEffect_SkDescriptorTag, peBuffer); + add_flattenable(desc2, kPathEffect_SkDescriptorTag, peBuffer); + } + if (effects.fMaskFilter) { + add_flattenable(desc1, kMaskFilter_SkDescriptorTag, mfBuffer); + add_flattenable(desc2, kMaskFilter_SkDescriptorTag, mfBuffer); + } + + SkASSERT(desc->getLength() == desc1->getLength()); + SkASSERT(desc->getLength() == desc2->getLength()); + desc1->computeChecksum(); + desc2->computeChecksum(); + SkASSERT(!memcmp(desc, desc1, desc->getLength())); + SkASSERT(!memcmp(desc, desc2, desc->getLength())); +} +#endif + +void generate_descriptor( + const SkScalerContextRec& rec, + const SkScalerContextEffects& effects, + SkBinaryWriteBuffer* pathEffectBuffer, + SkBinaryWriteBuffer* maskFilterBuffer, + SkDescriptor* desc) +{ + desc->init(); + desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + + auto add = [&desc](uint32_t tag, SkBinaryWriteBuffer* buffer) { + buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr)); + }; + + if (effects.fPathEffect) { + add(kPathEffect_SkDescriptorTag, pathEffectBuffer); + } + if (effects.fMaskFilter) { + add(kMaskFilter_SkDescriptorTag, maskFilterBuffer); + } + + desc->computeChecksum(); +#ifdef TEST_DESC + test_desc(rec, effects, pathEffectBuffer, maskFilterBuffer, desc); +#endif +} + +SkDescriptor* SkScalerContext::AutoDescriptorGivenRecAndEffects( + const SkScalerContextRec& rec, + const SkScalerContextEffects& effects, + SkAutoDescriptor* ad) +{ + SkBinaryWriteBuffer peBuffer, mfBuffer; + + ad->reset(calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer)); + + generate_descriptor(rec, effects, &peBuffer, &mfBuffer, ad->getDesc()); + + return ad->getDesc(); +} + +std::unique_ptr<SkDescriptor> SkScalerContext::DescriptorGivenRecAndEffects( + const SkScalerContextRec& rec, + const SkScalerContextEffects& effects) +{ + SkBinaryWriteBuffer peBuffer, mfBuffer; + + auto desc = SkDescriptor::Alloc(calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer)); + + generate_descriptor(rec, effects, &peBuffer, &mfBuffer, desc.get()); + + return desc; +} + + diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h index 90cac5dc96..05d12637b2 100644 --- a/src/core/SkScalerContext.h +++ b/src/core/SkScalerContext.h @@ -8,6 +8,8 @@ #ifndef SkScalerContext_DEFINED #define SkScalerContext_DEFINED +#include <memory> + #include "SkGlyph.h" #include "SkMask.h" #include "SkMaskFilter.h" @@ -17,6 +19,7 @@ #include "SkTypeface.h" #include "SkWriteBuffer.h" +class SkAutoDescriptor; class SkDescriptor; class SkMaskFilter; class SkPathEffect; @@ -46,7 +49,6 @@ enum SkAxisAlignment { kY_SkAxisAlignment }; - /* * To allow this to be forward-declared, it must be its own typename, rather * than a nested struct inside SkScalerContext (where it started). @@ -280,11 +282,14 @@ public: SkScalerContextRec* rec, SkScalerContextEffects* effects); - template <typename A> - static auto CreateDescriptorGivenRecAndEffects( - const SkScalerContextRec &rec, - const SkScalerContextEffects &effects, - A alloc) -> decltype(alloc((size_t)0)); + static SkDescriptor* AutoDescriptorGivenRecAndEffects( + const SkScalerContextRec& rec, + const SkScalerContextEffects& effects, + SkAutoDescriptor* ad); + + static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects( + const SkScalerContextRec& rec, + const SkScalerContextEffects& effects); static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec& rec); @@ -300,6 +305,12 @@ public: */ SkAxisAlignment computeAxisAlignmentForHText(); + static SkDescriptor* CreateDescriptorAndEffectsUsingPaint( + const SkPaint& paint, const SkSurfaceProps* surfaceProps, + SkScalerContextFlags scalerContextFlags, + const SkMatrix* deviceMatrix, SkAutoDescriptor* ad, + SkScalerContextEffects* effects); + protected: SkScalerContextRec fRec; @@ -353,16 +364,6 @@ protected: void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; } private: - static size_t CalculateSizeAndFlatten(const SkScalerContextRec& rec, - const SkScalerContextEffects& effects, - SkBinaryWriteBuffer* pathEffectBuffer, - SkBinaryWriteBuffer* maskFilterBuffer); - static void GenerateDescriptor(const SkScalerContextRec& rec, - const SkScalerContextEffects& effects, - SkBinaryWriteBuffer* pathEffectBuffer, - SkBinaryWriteBuffer* maskFilterBuffer, - SkDescriptor* desc); - friend class SkRandomScalerContext; // For debug purposes // never null @@ -389,22 +390,6 @@ private: const SkMaskGamma::PreBlend fPreBlendForFilter; }; -template <typename A> -inline auto SkScalerContext::CreateDescriptorGivenRecAndEffects( - const SkScalerContextRec &rec, - const SkScalerContextEffects &effects, - A alloc) -> decltype(alloc((size_t)0)) { - - SkBinaryWriteBuffer peBuffer, mfBuffer; - - auto desc = alloc(CalculateSizeAndFlatten(rec, effects, &peBuffer, &mfBuffer)); - - GenerateDescriptor(rec, effects, &peBuffer, &mfBuffer, &(*desc)); - - return desc; -} - - #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c') #define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e') #define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f') diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp index b47f8c3c13..d3191e2d39 100644 --- a/src/core/SkTypeface.cpp +++ b/src/core/SkTypeface.cpp @@ -341,16 +341,15 @@ bool SkTypeface::onComputeBounds(SkRect* bounds) const { SkScalerContextRec rec; SkScalerContextEffects effects; + SkScalerContext::MakeRecAndEffects( paint, nullptr, nullptr, SkScalerContextFlags::kNone, &rec, &effects); - SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); - SkDescriptor* desc = ad.getDesc(); - desc->init(); - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - + SkAutoDescriptor ad; SkScalerContextEffects noeffects; - std::unique_ptr<SkScalerContext> ctx = this->createScalerContext(noeffects, desc, true); + SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, noeffects, &ad); + + std::unique_ptr<SkScalerContext> ctx = this->createScalerContext(noeffects, ad.getDesc(), true); if (!ctx) { return false; } diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 7fce4ba856..887addd25c 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -59,7 +59,8 @@ SkGlyphCache* GrAtlasTextBlob::setupCache(int runIndex, SkAutoDescriptor* desc = run->fOverrideDescriptor.get() ? run->fOverrideDescriptor.get() : &run->fDescriptor; SkScalerContextEffects effects; - skPaint.getScalerContextDescriptor(&effects, desc, &props, scalerContextFlags, viewMatrix); + SkScalerContext::CreateDescriptorAndEffectsUsingPaint( + skPaint, &props, scalerContextFlags, viewMatrix, desc, &effects); run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); run->fPathEffect = sk_ref_sp(effects.fPathEffect); run->fMaskFilter = sk_ref_sp(effects.fMaskFilter); diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index 41c46466ac..1dce4e0d44 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -602,8 +602,8 @@ void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, SkScalerContextEffects effects; // We apply the fake-gamma by altering the distance in the shader, so we ignore the // passed-in scaler context flags. (It's only used when we fall-back to bitmap text). - skPaint.getScalerContextDescriptor(&effects, &desc, &props, SkScalerContextFlags::kNone, - nullptr); + SkScalerContext::CreateDescriptorAndEffectsUsingPaint( + skPaint, &props, SkScalerContextFlags::kNone, nullptr, &desc, &effects); SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface(), effects, desc.getDesc()); diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp index 2170f0a486..5c45f220ce 100644 --- a/src/gpu/text/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp @@ -605,8 +605,9 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, SkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const { if (!fDetachedGlyphCache) { - fDetachedGlyphCache = fFont.detachCache(nullptr, SkScalerContextFlags::kNone, - nullptr); + fDetachedGlyphCache = SkGlyphCache::DetachCacheUsingPaint(fFont, nullptr, + SkScalerContextFlags::kNone, + nullptr); } return fDetachedGlyphCache; } |