aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkPaint.cpp
diff options
context:
space:
mode:
authorGravatar Herb Derby <herb@google.com>2018-01-23 13:39:21 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-23 21:55:50 +0000
commit980a48de64baf2f974f6c99096391280d1c1d22c (patch)
tree8268924145dd50b4e6ce3e2e01bb36fb536ca948 /src/core/SkPaint.cpp
parent27059d36d63284b1af2c25e0e5a52c17485c54d7 (diff)
Move glyph cache and descriptor functions off of SkPaint
BUG=skia:7515 Change-Id: If17b157db1077a9a3c0f9efd03929f62a3486419 Reviewed-on: https://skia-review.googlesource.com/98841 Reviewed-by: Mike Klein <mtklein@chromium.org> Commit-Queue: Herb Derby <herb@google.com>
Diffstat (limited to 'src/core/SkPaint.cpp')
-rw-r--r--src/core/SkPaint.cpp432
1 files changed, 10 insertions, 422 deletions
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;