| /* |
| * Copyright 2018 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkPaint.h" |
| #include "SkColorFilter.h" |
| #include "SkDraw.h" |
| #include "SkFontDescriptor.h" |
| #include "SkFontPriv.h" |
| #include "SkGraphics.h" |
| #include "SkPaintDefaults.h" |
| #include "SkPaintPriv.h" |
| #include "SkPathEffect.h" |
| #include "SkSafeRange.h" |
| #include "SkScalar.h" |
| #include "SkScalerContext.h" |
| #include "SkShader.h" |
| #include "SkShaderBase.h" |
| #include "SkStrike.h" |
| #include "SkStringUtils.h" |
| #include "SkTLazy.h" |
| #include "SkTextBlob.h" |
| #include "SkTextBlobPriv.h" |
| #include "SkTextFormatParams.h" |
| #include "SkTo.h" |
| #include "SkTypeface.h" |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| static SkScalar mag2(SkScalar x, SkScalar y) { |
| return x * x + y * y; |
| } |
| |
| static bool tooBig(const SkMatrix& m, SkScalar ma2max) { |
| return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max |
| || |
| mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max; |
| } |
| |
| bool SkFontPriv::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(maxLimit)); |
| } |
| |
| SkScalar SkFontPriv::MaxCacheSize2(SkScalar maxLimit) { |
| // we have a self-imposed maximum, just for memory-usage sanity |
| const int limit = SkMin32(SkGraphics::GetFontCachePointSizeLimit(), maxLimit); |
| const SkScalar maxSize = SkIntToScalar(limit); |
| return maxSize * maxSize; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "SkUtils.h" |
| |
| static const SkGlyph& sk_getMetrics_utf8_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| return cache->getUnicharMetrics(SkUTF::NextUTF8(text, stop)); |
| } |
| |
| static const SkGlyph& sk_getMetrics_utf16_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| return cache->getUnicharMetrics( |
| SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop)); |
| } |
| |
| static const SkGlyph& sk_getMetrics_utf32_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| return cache->getUnicharMetrics(SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop)); |
| } |
| |
| static const SkGlyph& sk_getMetrics_glyph_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| const uint16_t* ptr = *(const uint16_t**)text; |
| unsigned glyphID = *ptr; |
| ptr += 1; |
| *text = (const char*)ptr; |
| return cache->getGlyphIDMetrics(glyphID); |
| } |
| |
| static const SkGlyph& sk_getAdvance_utf8_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| return cache->getUnicharAdvance(SkUTF::NextUTF8(text, stop)); |
| } |
| |
| static const SkGlyph& sk_getAdvance_utf16_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| return cache->getUnicharAdvance( |
| SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop)); |
| } |
| |
| static const SkGlyph& sk_getAdvance_utf32_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| return cache->getUnicharAdvance(SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop)); |
| } |
| |
| static const SkGlyph& sk_getAdvance_glyph_next(SkStrike* cache, |
| const char** text, |
| const char* stop) { |
| SkASSERT(cache != nullptr); |
| SkASSERT(text != nullptr); |
| |
| const uint16_t* ptr = *(const uint16_t**)text; |
| unsigned glyphID = *ptr; |
| ptr += 1; |
| *text = (const char*)ptr; |
| return cache->getGlyphIDAdvance(glyphID); |
| } |
| |
| SkFontPriv::GlyphCacheProc SkFontPriv::GetGlyphCacheProc(SkTextEncoding encoding, |
| bool needFullMetrics) { |
| static const GlyphCacheProc gGlyphCacheProcs[] = { |
| sk_getMetrics_utf8_next, |
| sk_getMetrics_utf16_next, |
| sk_getMetrics_utf32_next, |
| sk_getMetrics_glyph_next, |
| |
| sk_getAdvance_utf8_next, |
| sk_getAdvance_utf16_next, |
| sk_getAdvance_utf32_next, |
| sk_getAdvance_glyph_next, |
| }; |
| |
| unsigned index = static_cast<unsigned>(encoding); |
| |
| if (!needFullMetrics) { |
| index += 4; |
| } |
| |
| SkASSERT(index < SK_ARRAY_COUNT(gGlyphCacheProcs)); |
| return gGlyphCacheProcs[index]; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // 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 just_a_color(const SkPaint& paint, SkColor* color) { |
| SkColor c = paint.getColor(); |
| |
| const auto* shader = as_SB(paint.getShader()); |
| if (shader && !shader->asLuminanceColor(&c)) { |
| return false; |
| } |
| if (paint.getColorFilter()) { |
| c = paint.getColorFilter()->filterColor(c); |
| } |
| if (color) { |
| *color = c; |
| } |
| return true; |
| } |
| |
| SkColor SkPaint::computeLuminanceColor() const { |
| SkColor c; |
| if (!just_a_color(*this, &c)) { |
| c = SkColorSetRGB(0x7F, 0x80, 0x7F); |
| } |
| return c; |
| } |