| /* |
| * 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/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<SkColorFilterShader>(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); |
| } |
| } |
| |
| SkScalar SkPaintPriv::ComputeResScaleForStroking(const SkMatrix& matrix) { |
| // Not sure how to handle perspective differently, so we just don't try (yet) |
| SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); |
| SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); |
| if (SkScalarsAreFinite(sx, sy)) { |
| SkScalar scale = std::max(sx, sy); |
| if (scale > 0) { |
| return scale; |
| } |
| } |
| return 1; |
| } |