diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 9e29197afb..1e60cb6009 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -266,10 +266,11 @@ private: // V65: Float4 paint color // V66: Add saveBehind // V67: Blobs serialize fonts instead of paints + // V68: Paint doesn't serialize font-related stuff // Only SKPs within the min/current picture version range (inclusive) can be read. static const uint32_t MIN_PICTURE_VERSION = 56; // august 2017 - static const uint32_t CURRENT_PICTURE_VERSION = 67; + static const uint32_t CURRENT_PICTURE_VERSION = 68; static_assert(MIN_PICTURE_VERSION <= 62, "Remove kFontAxes_bad from SkFontDescriptor.cpp"); diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 2b39c38bbe..930899c832 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -357,14 +357,6 @@ static uintptr_t asint(const void* p) { return reinterpret_cast(p); } -static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) { - SkASSERT(a == (uint8_t)a); - SkASSERT(b == (uint8_t)b); - SkASSERT(c == (uint8_t)c); - SkASSERT(d == (uint8_t)d); - return (a << 24) | (b << 16) | (c << 8) | d; -} - #ifdef SK_DEBUG static void ASSERT_FITS_IN(uint32_t value, int bitCount) { SkASSERT(bitCount > 0 && bitCount <= 32); @@ -394,20 +386,6 @@ static inline int BPF_Mask(int bits) { return (1 << bits) - 1; } -static uint32_t pack_paint_flags(unsigned flags, unsigned hint, unsigned filter, - unsigned flatFlags) { - ASSERT_FITS_IN(flags, kFlags_BPF); - ASSERT_FITS_IN(hint, kHint_BPF); - ASSERT_FITS_IN(filter, kFilter_BPF); - ASSERT_FITS_IN(flatFlags, kFlatFlags_BPF); - - unsigned was_align = 0; // used to be textalign [0..2] - - // left-align the fields of "known" size, and right-align the last (flatFlags) so it can easly - // add more bits in the future. - return (flags << 16) | (hint << 14) | (was_align << 12) | (filter << 10) | flatFlags; -} - static FlatFlags unpack_paint_flags(SkPaint* paint, uint32_t packed) { paint->setFlags(packed >> 16); paint->setHinting((SkFontHinting)((packed >> 14) & BPF_Mask(kHint_BPF))); @@ -415,16 +393,58 @@ static FlatFlags unpack_paint_flags(SkPaint* paint, uint32_t packed) { return (FlatFlags)(packed & kFlatFlagMask); } +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; +} + +/* 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; + packed |= shift_bits(((unsigned)paint.isDither() << 1) | + (unsigned)paint.isAntiAlias(), 0, 8); + packed |= shift_bits(paint.getBlendMode(), 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(paint.getFilterQuality(), 22, 2); + 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; + paint->setBlendMode(safe.checkLE(packed & 0xFF, SkBlendMode::kLastMode)); + 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; + paint->setFilterQuality(safe.checkLE(packed & 0x3, kLast_SkFilterQuality)); + 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) { - // We force recording our typeface, even if its "default" since the receiver process - // may have a different notion of default. - SkTypeface* tf = SkPaintPriv::GetTypefaceOrDefault(paint); - SkASSERT(tf); - - uint8_t flatFlags = kHasTypeface_FlatFlag; + uint8_t flatFlags = 0; if (asint(paint.getPathEffect()) | asint(paint.getShader()) | @@ -435,33 +455,23 @@ void SkPaintPriv::Flatten(const SkPaint& paint, SkWriteBuffer& buffer) { flatFlags |= kHasEffects_FlatFlag; } - buffer.writeScalar(paint.getTextSize()); - buffer.writeScalar(paint.getTextScaleX()); - buffer.writeScalar(paint.getTextSkewX()); buffer.writeScalar(paint.getStrokeWidth()); buffer.writeScalar(paint.getStrokeMiter()); buffer.writeColor4f(paint.getColor4f()); - buffer.writeUInt(pack_paint_flags(paint.getFlags(), static_cast(paint.getHinting()), - paint.getFilterQuality(), flatFlags)); - buffer.writeUInt(pack_4(paint.getStrokeCap(), paint.getStrokeJoin(), - (paint.getStyle() << 4) | (unsigned)paint.getTextEncoding(), - paint.fBlendMode)); - - buffer.writeTypeface(tf); + 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.write32(0); // use to be SkRasterizer buffer.writeFlattenable(paint.getLooper()); buffer.writeFlattenable(paint.getImageFilter()); } } -bool SkPaintPriv::Unflatten(SkPaint* paint, SkReadBuffer& buffer) { +bool SkPaintPriv::Unflatten_PreV68(SkPaint* paint, SkReadBuffer& buffer) { SkSafeRange safe; paint->setTextSize(buffer.readScalar()); @@ -516,6 +526,46 @@ bool SkPaintPriv::Unflatten(SkPaint* paint, SkReadBuffer& buffer) { return true; } +bool SkPaintPriv::Unflatten(SkPaint* paint, SkReadBuffer& buffer) { + if (buffer.isVersionLT(SkReadBuffer::kPaintDoesntSerializeFonts_Version)) { + return Unflatten_PreV68(paint, buffer); + } + + SkSafeRange safe; + + paint->setStrokeWidth(buffer.readScalar()); + paint->setStrokeMiter(buffer.readScalar()); + { + SkColor4f color; + buffer.readColor4f(&color); + paint->setColor4f(color, sk_srgb_singleton()); + } + + unsigned flatFlags = unpack_v68(paint, buffer.readUInt(), safe); + + if (flatFlags & kHasEffects_FlatFlag) { + paint->setPathEffect(buffer.readPathEffect()); + paint->setShader(buffer.readShader()); + paint->setMaskFilter(buffer.readMaskFilter()); + paint->setColorFilter(buffer.readColorFilter()); + paint->setLooper(buffer.readDrawLooper()); + paint->setImageFilter(buffer.readImageFilter()); + } else { + paint->setPathEffect(nullptr); + paint->setShader(nullptr); + paint->setMaskFilter(nullptr); + paint->setColorFilter(nullptr); + paint->setLooper(nullptr); + paint->setImageFilter(nullptr); + } + + if (!buffer.validate(safe)) { + paint->reset(); + return false; + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, diff --git a/src/core/SkPaintPriv.h b/src/core/SkPaintPriv.h index d3a0c352d4..a5f182d78b 100644 --- a/src/core/SkPaintPriv.h +++ b/src/core/SkPaintPriv.h @@ -97,6 +97,8 @@ public: */ static bool Unflatten(SkPaint* paint, SkReadBuffer& buffer); +private: + static bool Unflatten_PreV68(SkPaint* paint, SkReadBuffer& buffer); }; #endif diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h index bbb036f0ad..254ff6f514 100644 --- a/src/core/SkReadBuffer.h +++ b/src/core/SkReadBuffer.h @@ -45,6 +45,7 @@ public: kFloat4PaintColor_Version = 65, kSaveBehind_Version = 66, kSerializeFonts_Version = 67, + kPaintDoesntSerializeFonts_Version = 68, }; /** @@ -249,6 +250,7 @@ public: kFloat4PaintColor_Version = 65, kSaveBehind_Version = 66, kSerializeFonts_Version = 67, + kPaintDoesntSerializeFonts_Version = 68, }; bool isVersionLT(Version) const { return false; } diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp index 261740db2e..d4fabde229 100644 --- a/tests/PaintTest.cpp +++ b/tests/PaintTest.cpp @@ -202,12 +202,6 @@ DEF_TEST(Paint_flattening, reporter) { kMedium_SkFilterQuality, kHigh_SkFilterQuality, }; - const SkFontHinting hinting[] = { - kNo_SkFontHinting, - kSlight_SkFontHinting, - kNormal_SkFontHinting, - kFull_SkFontHinting, - }; const SkPaint::Cap caps[] = { SkPaint::kButt_Cap, SkPaint::kRound_Cap, @@ -218,12 +212,6 @@ DEF_TEST(Paint_flattening, reporter) { SkPaint::kRound_Join, SkPaint::kBevel_Join, }; - const SkTextEncoding encodings[] = { - kUTF8_SkTextEncoding, - kUTF16_SkTextEncoding, - kUTF32_SkTextEncoding, - kGlyphID_SkTextEncoding, - }; const SkPaint::Style styles[] = { SkPaint::kFill_Style, SkPaint::kStroke_Style, @@ -232,16 +220,16 @@ DEF_TEST(Paint_flattening, reporter) { #define FOR_SETUP(index, array, setter) \ for (size_t index = 0; index < SK_ARRAY_COUNT(array); ++index) { \ - paint.setter(array[index]); \ + paint.setter(array[index]); SkPaint paint; - paint.setFlags(0x1234); + paint.setAntiAlias(true); + + // we don't serialize hinting or encoding -- soon to be removed from paint FOR_SETUP(i, levels, setFilterQuality) - FOR_SETUP(j, hinting, setHinting) FOR_SETUP(l, caps, setStrokeCap) FOR_SETUP(m, joins, setStrokeJoin) - FOR_SETUP(n, encodings, setTextEncoding) FOR_SETUP(p, styles, setStyle) SkBinaryWriteBuffer writer; @@ -255,7 +243,7 @@ DEF_TEST(Paint_flattening, reporter) { SkPaintPriv::Unflatten(&paint2, reader); REPORTER_ASSERT(reporter, paint2 == paint); - }}}}}} + }}}} #undef FOR_SETUP } @@ -297,8 +285,6 @@ DEF_TEST(Paint_MoreFlattening, r) { // No matter the encoding, these must always hold. ASSERT(other.getColor() == paint.getColor()); - ASSERT(other.getTextScaleX() == paint.getTextScaleX()); - ASSERT(other.getTextSize() == paint.getTextSize()); ASSERT(other.getLooper() == paint.getLooper()); ASSERT(other.getBlendMode() == paint.getBlendMode()); }