summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/core/SkPaintPriv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/core/SkPaintPriv.cpp')
-rw-r--r--gfx/skia/skia/src/core/SkPaintPriv.cpp274
1 files changed, 274 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkPaintPriv.cpp b/gfx/skia/skia/src/core/SkPaintPriv.cpp
new file mode 100644
index 0000000000..5dc4e67049
--- /dev/null
+++ b/gfx/skia/skia/src/core/SkPaintPriv.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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;
+ }
+
+ if (dstCT == kUnknown_SkColorType) {
+ 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);
+ }
+}
+
+#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 <typename T> uint32_t shift_bits(T value, unsigned shift, unsigned bits) {
+ SkASSERT(shift + bits <= 32);
+ uint32_t v = static_cast<uint32_t>(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<unsigned>(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;
+}