/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkPaint.h" #include "src/core/SkBlenderBase.h" #include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkPaintPriv.h" #include "src/core/SkPicturePriv.h" #include "src/core/SkReadBuffer.h" #include "src/core/SkSafeRange.h" #include "src/core/SkWriteBuffer.h" #include "src/core/SkXfermodePriv.h" #include "src/shaders/SkColorFilterShader.h" #include "src/shaders/SkShaderBase.h" static bool changes_alpha(const SkPaint& paint) { SkColorFilter* cf = paint.getColorFilter(); return cf && !as_CFB(cf)->isAlphaUnchanged(); } bool SkPaintPriv::Overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) { if (!paint) { // No paint means we default to SRC_OVER, so we overwrite iff our shader-override // is opaque, or we don't have one. return overrideOpacity != kNotOpaque_ShaderOverrideOpacity; } SkXfermode::SrcColorOpacity opacityType = SkXfermode::kUnknown_SrcColorOpacity; if (!changes_alpha(*paint)) { const unsigned paintAlpha = paint->getAlpha(); if (0xff == paintAlpha && overrideOpacity != kNotOpaque_ShaderOverrideOpacity && (!paint->getShader() || paint->getShader()->isOpaque())) { opacityType = SkXfermode::kOpaque_SrcColorOpacity; } else if (0 == paintAlpha) { if (overrideOpacity == kNone_ShaderOverrideOpacity && !paint->getShader()) { opacityType = SkXfermode::kTransparentBlack_SrcColorOpacity; } else { opacityType = SkXfermode::kTransparentAlpha_SrcColorOpacity; } } } const auto bm = paint->asBlendMode(); if (!bm) { return false; // don't know for sure, so we play it safe and return false. } return SkXfermode::IsOpaque(bm.value(), opacityType); } bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) { // The paint dither flag can veto. if (!p.isDither()) { return false; } // We always dither 565 or 4444 when requested. if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) { return true; } // Otherwise, dither is only needed for non-const paints. return p.getImageFilter() || p.getMaskFilter() || (p.getShader() && !as_SB(p.getShader())->isConstant()); } // 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 SkPaintPriv::ComputeLuminanceColor(const SkPaint& paint) { SkColor c; if (!just_a_color(paint, &c)) { c = SkColorSetRGB(0x7F, 0x80, 0x7F); } return c; } void SkPaintPriv::RemoveColorFilter(SkPaint* p, SkColorSpace* dstCS) { if (SkColorFilter* filter = p->getColorFilter()) { if (SkShader* shader = p->getShader()) { // SkColorFilterShader will modulate the shader color by paint alpha // before applying the filter, so we'll reset it to opaque. p->setShader(sk_make_sp(sk_ref_sp(shader), p->getAlphaf(), sk_ref_sp(filter))); p->setAlphaf(1.0f); } else { p->setColor(filter->filterColor4f(p->getColor4f(), sk_srgb_singleton(), dstCS), dstCS); } p->setColorFilter(nullptr); } } #ifdef SK_DEBUG static void ASSERT_FITS_IN(uint32_t value, int bitCount) { SkASSERT(bitCount > 0 && bitCount <= 32); uint32_t mask = ~0U; mask >>= (32 - bitCount); SkASSERT(0 == (value & ~mask)); } #else #define ASSERT_FITS_IN(value, bitcount) #endif enum FlatFlags { kHasTypeface_FlatFlag = 0x1, kHasEffects_FlatFlag = 0x2, kFlatFlagMask = 0x3, }; // SkPaint originally defined flags, some of which now apply to SkFont. These are renames // of those flags, split into categories depending on which objects they (now) apply to. template uint32_t shift_bits(T value, unsigned shift, unsigned bits) { SkASSERT(shift + bits <= 32); uint32_t v = static_cast(value); ASSERT_FITS_IN(v, bits); return v << shift; } constexpr uint8_t CUSTOM_BLEND_MODE_SENTINEL = 0xFF; /* Packing the paint flags : 8 // 2... blend : 8 // 30+ cap : 2 // 3 join : 2 // 3 style : 2 // 3 filter: 2 // 4 flat : 8 // 1... total : 32 */ static uint32_t pack_v68(const SkPaint& paint, unsigned flatFlags) { uint32_t packed = 0; const auto bm = paint.asBlendMode(); const unsigned mode = bm ? static_cast(bm.value()) : CUSTOM_BLEND_MODE_SENTINEL; packed |= shift_bits(((unsigned)paint.isDither() << 1) | (unsigned)paint.isAntiAlias(), 0, 8); packed |= shift_bits(mode, 8, 8); packed |= shift_bits(paint.getStrokeCap(), 16, 2); packed |= shift_bits(paint.getStrokeJoin(), 18, 2); packed |= shift_bits(paint.getStyle(), 20, 2); packed |= shift_bits(0, 22, 2); // was filterquality packed |= shift_bits(flatFlags, 24, 8); return packed; } static uint32_t unpack_v68(SkPaint* paint, uint32_t packed, SkSafeRange& safe) { paint->setAntiAlias((packed & 1) != 0); paint->setDither((packed & 2) != 0); packed >>= 8; { unsigned mode = packed & 0xFF; if (mode != CUSTOM_BLEND_MODE_SENTINEL) { // sentinel for custom blender paint->setBlendMode(safe.checkLE(mode, SkBlendMode::kLastMode)); } // else we will unflatten the custom blender } packed >>= 8; paint->setStrokeCap(safe.checkLE(packed & 0x3, SkPaint::kLast_Cap)); packed >>= 2; paint->setStrokeJoin(safe.checkLE(packed & 0x3, SkPaint::kLast_Join)); packed >>= 2; paint->setStyle(safe.checkLE(packed & 0x3, SkPaint::kStrokeAndFill_Style)); packed >>= 2; // skip the (now ignored) filterquality bits packed >>= 2; return packed; } /* To save space/time, we analyze the paint, and write a truncated version of it if there are not tricky elements like shaders, etc. */ void SkPaintPriv::Flatten(const SkPaint& paint, SkWriteBuffer& buffer) { uint8_t flatFlags = 0; if (paint.getPathEffect() || paint.getShader() || paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter() || !paint.asBlendMode()) { flatFlags |= kHasEffects_FlatFlag; } buffer.writeScalar(paint.getStrokeWidth()); buffer.writeScalar(paint.getStrokeMiter()); buffer.writeColor4f(paint.getColor4f()); buffer.write32(pack_v68(paint, flatFlags)); if (flatFlags & kHasEffects_FlatFlag) { buffer.writeFlattenable(paint.getPathEffect()); buffer.writeFlattenable(paint.getShader()); buffer.writeFlattenable(paint.getMaskFilter()); buffer.writeFlattenable(paint.getColorFilter()); buffer.writeFlattenable(paint.getImageFilter()); buffer.writeFlattenable(paint.getBlender()); } } SkPaint SkPaintPriv::Unflatten(SkReadBuffer& buffer) { SkPaint paint; paint.setStrokeWidth(buffer.readScalar()); paint.setStrokeMiter(buffer.readScalar()); { SkColor4f color; buffer.readColor4f(&color); paint.setColor(color, sk_srgb_singleton()); } SkSafeRange safe; unsigned flatFlags = unpack_v68(&paint, buffer.readUInt(), safe); if (!(flatFlags & kHasEffects_FlatFlag)) { // This is a simple SkPaint without any effects, so clear all the effect-related fields. paint.setPathEffect(nullptr); paint.setShader(nullptr); paint.setMaskFilter(nullptr); paint.setColorFilter(nullptr); paint.setImageFilter(nullptr); } else if (buffer.isVersionLT(SkPicturePriv::kSkBlenderInSkPaint)) { // This paint predates the introduction of user blend functions (via SkBlender). paint.setPathEffect(buffer.readPathEffect()); paint.setShader(buffer.readShader()); paint.setMaskFilter(buffer.readMaskFilter()); paint.setColorFilter(buffer.readColorFilter()); (void)buffer.read32(); // was drawLooper (now deprecated) paint.setImageFilter(buffer.readImageFilter()); } else { paint.setPathEffect(buffer.readPathEffect()); paint.setShader(buffer.readShader()); paint.setMaskFilter(buffer.readMaskFilter()); paint.setColorFilter(buffer.readColorFilter()); paint.setImageFilter(buffer.readImageFilter()); paint.setBlender(buffer.readBlender()); } if (!buffer.validate(safe.ok())) { paint.reset(); } return paint; }