diff options
author | Mike Reed <reed@google.com> | 2018-02-21 15:55:14 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-02-21 21:22:37 +0000 |
commit | 267ecccfed954079e9ec37182d6c9aafe3007525 (patch) | |
tree | 4a0fed781314707db9d75efc063330496652557e | |
parent | 528b446889c7967d220d2a679912f698067ff072 (diff) |
change path serialization version to 4
New format should be much simpler:
- only store public data (e.g. points, verbs, filltype)
- deserialize just uses public APIs
Refactor reading code to manage different (older) versions, to make
it clear (hopefully) what we can delete when we can abandon version
3 support.
Bug: skia:
Change-Id: I30465f891cba3f044ae1cb2c13c04f04fdc9da78
Reviewed-on: https://skia-review.googlesource.com/109160
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>
-rw-r--r-- | gn/core.gni | 1 | ||||
-rw-r--r-- | include/core/SkPath.h | 28 | ||||
-rw-r--r-- | src/core/SkBuffer.cpp | 26 | ||||
-rw-r--r-- | src/core/SkBuffer.h | 7 | ||||
-rw-r--r-- | src/core/SkPath.cpp | 145 | ||||
-rw-r--r-- | src/core/SkPath_serial.cpp | 290 | ||||
-rw-r--r-- | src/core/SkSafeMath.h | 2 | ||||
-rw-r--r-- | tests/PathTest.cpp | 119 |
8 files changed, 321 insertions, 297 deletions
diff --git a/gn/core.gni b/gn/core.gni index 72e12c2573..00f6b73f6c 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -213,6 +213,7 @@ skia_core_sources = [ "$_src/core/SkPaintPriv.cpp", "$_src/core/SkPaintPriv.h", "$_src/core/SkPath.cpp", + "$_src/core/SkPath_serial.cpp", "$_src/core/SkPathEffect.cpp", "$_src/core/SkPathMeasure.cpp", "$_src/core/SkPathPriv.h", diff --git a/include/core/SkPath.h b/include/core/SkPath.h index 8e74a0b63e..f3d7953391 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -1617,28 +1617,6 @@ public: #endif private: - enum SerializationOffsets { - kType_SerializationShift = 28, // requires 4 bits - kDirection_SerializationShift = 26, // requires 2 bits, could be reused - ignored on read. - kIsVolatile_SerializationShift = 25, // requires 1 bit - // 1 free bit at 24 - kConvexity_SerializationShift = 16, // requires 8 bits, could be reused - ignored on read. - kFillType_SerializationShift = 8, // requires 8 bits - // low-8-bits are version - }; - - enum SerializationVersions { - // kPathPrivFirstDirection_Version = 1, - kPathPrivLastMoveToIndex_Version = 2, - kPathPrivTypeEnumVersion = 3, - kCurrent_Version = 3 - }; - - enum SerializationType { - kGeneral = 0, - kRRect = 1 - }; - sk_sp<SkPathRef> fPathRef; int fLastMoveToIndex; uint8_t fFillType; @@ -1658,8 +1636,10 @@ private: */ void copyFields(const SkPath& that); - size_t writeToMemoryAsRRect(int32_t packedHeader, void* buffer) const; - size_t readFromMemoryAsRRect(const void* buffer) const; + size_t writeToMemoryAsRRect(void* buffer) const; + size_t readAsRRect(const void*, size_t); + size_t readFromMemory_LE3(const void*, size_t); + size_t readFromMemory_EQ4(const void*, size_t); friend class Iter; friend class SkPathPriv; diff --git a/src/core/SkBuffer.cpp b/src/core/SkBuffer.cpp index 51ab239afe..9dbc49ef9d 100644 --- a/src/core/SkBuffer.cpp +++ b/src/core/SkBuffer.cpp @@ -6,22 +6,27 @@ */ #include "SkBuffer.h" - +#include "SkMalloc.h" #include <string.h> /////////////////////////////////////////////////////////////////////////////////////////////////// -bool SkRBuffer::read(void* buffer, size_t size) { +const void* SkRBuffer::skip(size_t size) { if (fValid && size <= this->available()) { - if (buffer) { - memcpy(buffer, fPos, size); - } + const void* pos = fPos; fPos += size; + return pos; + } + fValid = false; + return nullptr; +} + +bool SkRBuffer::read(void* buffer, size_t size) { + if (const void* src = this->skip(size)) { + sk_careful_memcpy(buffer, src, size); return true; - } else { - fValid = false; - return false; } + return false; } bool SkRBuffer::skipToAlign4() { @@ -46,8 +51,9 @@ void* SkWBuffer::skip(size_t size) { void SkWBuffer::writeNoSizeCheck(const void* buffer, size_t size) { SkASSERT(fData == nullptr || fStop == nullptr || fPos + size <= fStop); - if (fData && buffer) - memcpy(fPos, buffer, size); + if (fData && buffer) { + sk_careful_memcpy(fPos, buffer, size); + } fPos += size; } diff --git a/src/core/SkBuffer.h b/src/core/SkBuffer.h index dd7f95aa3c..7dfe2bb65e 100644 --- a/src/core/SkBuffer.h +++ b/src/core/SkBuffer.h @@ -9,6 +9,7 @@ #ifndef SkBuffer_DEFINED #define SkBuffer_DEFINED +#include "SkSafeMath.h" #include "SkScalar.h" #include "SkTypes.h" @@ -60,6 +61,12 @@ public: bool readS32(int32_t* x) { return this->read(x, 4); } bool readU32(uint32_t* x) { return this->read(x, 4); } + // returns nullptr on failure + const void* skip(size_t bytes); + template <typename T> const T* skipCount(size_t count) { + return static_cast<const T*>(this->skip(SkSafeMath::Mul(count, sizeof(T)))); + } + private: const char* fData; const char* fPos; diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 95fa37f7a6..279615d799 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -16,6 +16,7 @@ #include "SkPathRef.h" #include "SkPointPriv.h" #include "SkRRect.h" +#include "SkSafeMath.h" static float poly_eval(float A, float B, float C, float t) { return (A * t + B) * t + C; @@ -2073,150 +2074,6 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) { /////////////////////////////////////////////////////////////////////////////// -/* - Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]] -*/ - -size_t SkPath::writeToMemoryAsRRect(int32_t packedHeader, void* storage) const { - SkRect oval; - SkRRect rrect; - bool isCCW; - unsigned start; - if (fPathRef->isOval(&oval, &isCCW, &start)) { - rrect.setOval(oval); - // Convert to rrect start indices. - start *= 2; - } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) { - return false; - } - if (!storage) { - // packed header, rrect, start index. - return sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t); - } - - SkWBuffer buffer(storage); - // Rewrite header's first direction based on rrect direction. - uint8_t firstDir = isCCW ? SkPathPriv::kCCW_FirstDirection : SkPathPriv::kCW_FirstDirection; - packedHeader &= ~(0x3 << kDirection_SerializationShift); - packedHeader |= firstDir << kDirection_SerializationShift; - packedHeader |= SerializationType::kRRect << kType_SerializationShift; - buffer.write32(packedHeader); - rrect.writeToBuffer(&buffer); - buffer.write32(SkToS32(start)); - buffer.padToAlign4(); - return buffer.pos(); -} - -size_t SkPath::writeToMemory(void* storage) const { - SkDEBUGCODE(this->validate();) - - int32_t packed = (fConvexity << kConvexity_SerializationShift) | - (fFillType << kFillType_SerializationShift) | - (fFirstDirection << kDirection_SerializationShift) | - (fIsVolatile << kIsVolatile_SerializationShift) | - kCurrent_Version; - if (size_t bytes = this->writeToMemoryAsRRect(packed, storage)) { - return bytes; - } - - SkWBuffer buffer(storage); - - static_assert(0 == SerializationType::kGeneral, "packed has zero in type bits"); - if (nullptr == storage) { - // packed header, pathref, start index - const int byteCount = sizeof(int32_t) * 2 + fPathRef->writeSize(); - return SkAlign4(byteCount); - } - buffer.write32(packed); - buffer.write32(fLastMoveToIndex); - - fPathRef->writeToBuffer(&buffer); - - buffer.padToAlign4(); - return buffer.pos(); -} - -sk_sp<SkData> SkPath::serialize() const { - size_t size = this->writeToMemory(nullptr); - sk_sp<SkData> data = SkData::MakeUninitialized(size); - this->writeToMemory(data->writable_data()); - return data; -} - -size_t SkPath::readFromMemory(const void* storage, size_t length) { - SkRBuffer buffer(storage, length); - - int32_t packed; - if (!buffer.readS32(&packed)) { - return 0; - } - - unsigned version = packed & 0xFF; - uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3; - FillType fillType = static_cast<FillType>((packed >> kFillType_SerializationShift) & 0x3); - if (version >= kPathPrivTypeEnumVersion) { - SerializationType type = - static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF); - switch (type) { - case SerializationType::kRRect: { - Direction rrectDir; - SkRRect rrect; - int32_t start; - switch (dir) { - case SkPathPriv::kCW_FirstDirection: - rrectDir = kCW_Direction; - break; - case SkPathPriv::kCCW_FirstDirection: - rrectDir = kCCW_Direction; - break; - default: - return 0; - } - if (!rrect.readFromBuffer(&buffer)) { - return 0; - } - if (!buffer.readS32(&start) || start != SkTPin(start, 0, 7)) { - return 0; - } - this->reset(); - this->addRRect(rrect, rrectDir, SkToUInt(start)); - this->setFillType(fillType); - buffer.skipToAlign4(); - return buffer.pos(); - } - case SerializationType::kGeneral: - // Fall through to general path deserialization - break; - default: - return 0; - } - } - if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) { - return 0; - } - - // These are written into the serialized data but we no longer use them in the deserialized - // path. If convexity is corrupted it may cause the GPU backend to make incorrect - // rendering choices, possibly crashing. We set them to unknown so that they'll be recomputed if - // requested. - fConvexity = kUnknown_Convexity; - fFirstDirection = SkPathPriv::kUnknown_FirstDirection; - - fFillType = fillType; - fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1; - SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); - if (!pathRef) { - return 0; - } - - fPathRef.reset(pathRef); - SkDEBUGCODE(this->validate();) - buffer.skipToAlign4(); - return buffer.pos(); -} - -/////////////////////////////////////////////////////////////////////////////// - #include "SkString.h" #include "SkStringUtils.h" #include "SkStream.h" diff --git a/src/core/SkPath_serial.cpp b/src/core/SkPath_serial.cpp new file mode 100644 index 0000000000..d4983fc8a7 --- /dev/null +++ b/src/core/SkPath_serial.cpp @@ -0,0 +1,290 @@ +/* + * 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 <cmath> +#include "SkBuffer.h" +#include "SkData.h" +#include "SkMath.h" +#include "SkPathPriv.h" +#include "SkPathRef.h" +#include "SkRRect.h" +#include "SkSafeMath.h" + +enum SerializationOffsets { + kType_SerializationShift = 28, // requires 4 bits + kDirection_SerializationShift = 26, // requires 2 bits + kFillType_SerializationShift = 8, // requires 8 bits + // low-8-bits are version + kVersion_SerializationMask = 0xFF, +}; + +enum SerializationVersions { + // kPathPrivFirstDirection_Version = 1, + kPathPrivLastMoveToIndex_Version = 2, + kPathPrivTypeEnumVersion = 3, + kJustPublicData_Version = 4, + + kCurrent_Version = kJustPublicData_Version +}; + +enum SerializationType { + kGeneral = 0, + kRRect = 1 +}; + +static unsigned extract_version(uint32_t packed) { + return packed & kVersion_SerializationMask; +} + +static SkPath::FillType extract_filltype(uint32_t packed) { + return static_cast<SkPath::FillType>((packed >> kFillType_SerializationShift) & 0x3); +} + +static SerializationType extract_serializationtype(uint32_t packed) { + return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +size_t SkPath::writeToMemoryAsRRect(void* storage) const { + SkRect oval; + SkRRect rrect; + bool isCCW; + unsigned start; + if (fPathRef->isOval(&oval, &isCCW, &start)) { + rrect.setOval(oval); + // Convert to rrect start indices. + start *= 2; + } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) { + return 0; + } + + // packed header, rrect, start index. + const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t); + if (!storage) { + return sizeNeeded; + } + + int firstDir = isCCW ? SkPathPriv::kCCW_FirstDirection : SkPathPriv::kCW_FirstDirection; + int32_t packed = (fFillType << kFillType_SerializationShift) | + (firstDir << kDirection_SerializationShift) | + (SerializationType::kRRect << kType_SerializationShift) | + kCurrent_Version; + + SkWBuffer buffer(storage); + buffer.write32(packed); + rrect.writeToBuffer(&buffer); + buffer.write32(SkToS32(start)); + buffer.padToAlign4(); + SkASSERT(sizeNeeded == buffer.pos()); + return buffer.pos(); +} + +size_t SkPath::writeToMemory(void* storage) const { + SkDEBUGCODE(this->validate();) + + if (size_t bytes = this->writeToMemoryAsRRect(storage)) { + return bytes; + } + + int32_t packed = (fFillType << kFillType_SerializationShift) | + (SerializationType::kGeneral << kType_SerializationShift) | + kCurrent_Version; + + int32_t pts = fPathRef->countPoints(); + int32_t cnx = fPathRef->countWeights(); + int32_t vbs = fPathRef->countVerbs(); + + SkSafeMath safe; + size_t size = 4 * sizeof(int32_t); + size = safe.add(size, safe.mul(pts, sizeof(SkPoint))); + size = safe.add(size, safe.mul(cnx, sizeof(SkScalar))); + size = safe.add(size, safe.mul(vbs, sizeof(uint8_t))); + size = safe.alignUp(size, 4); + if (!safe) { + return 0; + } + if (!storage) { + return size; + } + + SkWBuffer buffer(storage); + buffer.write32(packed); + buffer.write32(pts); + buffer.write32(cnx); + buffer.write32(vbs); + buffer.write(fPathRef->points(), pts * sizeof(SkPoint)); + buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar)); + buffer.write(fPathRef->verbsMemBegin(), vbs * sizeof(uint8_t)); + buffer.padToAlign4(); + + SkASSERT(buffer.pos() == size); + return size; +} + +sk_sp<SkData> SkPath::serialize() const { + size_t size = this->writeToMemory(nullptr); + sk_sp<SkData> data = SkData::MakeUninitialized(size); + this->writeToMemory(data->writable_data()); + return data; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// reading + +size_t SkPath::readFromMemory(const void* storage, size_t length) { + SkRBuffer buffer(storage, length); + uint32_t packed; + if (!buffer.readU32(&packed)) { + return 0; + } + unsigned version = extract_version(packed); + if (version <= kPathPrivTypeEnumVersion) { + return this->readFromMemory_LE3(storage, length); + } + if (version == kJustPublicData_Version) { + return this->readFromMemory_EQ4(storage, length); + } + return 0; +} + +size_t SkPath::readAsRRect(const void* storage, size_t length) { + SkRBuffer buffer(storage, length); + uint32_t packed; + if (!buffer.readU32(&packed)) { + return 0; + } + + SkASSERT(extract_serializationtype(packed) == SerializationType::kRRect); + + uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3; + FillType fillType = extract_filltype(packed); + + Direction rrectDir; + SkRRect rrect; + int32_t start; + switch (dir) { + case SkPathPriv::kCW_FirstDirection: + rrectDir = kCW_Direction; + break; + case SkPathPriv::kCCW_FirstDirection: + rrectDir = kCCW_Direction; + break; + default: + return 0; + } + if (!rrect.readFromBuffer(&buffer)) { + return 0; + } + if (!buffer.readS32(&start) || start != SkTPin(start, 0, 7)) { + return 0; + } + this->reset(); + this->addRRect(rrect, rrectDir, SkToUInt(start)); + this->setFillType(fillType); + buffer.skipToAlign4(); + return buffer.pos(); +} + +size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) { + SkRBuffer buffer(storage, length); + uint32_t packed; + if (!buffer.readU32(&packed)) { + return 0; + } + + SkASSERT(extract_version(packed) == 4); + + switch (extract_serializationtype(packed)) { + case SerializationType::kRRect: + return this->readAsRRect(storage, length); + case SerializationType::kGeneral: + break; // fall through + default: + return 0; + } + + int32_t pts, cnx, vbs; + if (!buffer.readS32(&pts) || !buffer.readS32(&cnx) || !buffer.readS32(&vbs)) { + return 0; + } + + const SkPoint* points = buffer.skipCount<SkPoint>(pts); + const SkScalar* conics = buffer.skipCount<SkScalar>(cnx); + const uint8_t* verbs = buffer.skipCount<uint8_t>(vbs); + buffer.skipToAlign4(); + if (!buffer.isValid()) { + return 0; + } + SkASSERT(buffer.pos() <= length); + + SkPath tmp; + tmp.setFillType(extract_filltype(packed)); + tmp.incReserve(pts); + for (int i = vbs - 1; i >= 0; --i) { + switch (verbs[i]) { + case kMove_Verb: tmp.moveTo(*points++); break; + case kLine_Verb: tmp.lineTo(*points++); break; + case kQuad_Verb: tmp.quadTo(points[0], points[1]); points += 2; break; + case kConic_Verb: tmp.conicTo(points[0], points[1], *conics++); points += 2; break; + case kCubic_Verb: tmp.cubicTo(points[0], points[1], points[2]); points += 3; break; + case kClose_Verb: tmp.close(); break; + default: + return 0; // bad verb + } + } + *this = std::move(tmp); + return buffer.pos(); +} + +size_t SkPath::readFromMemory_LE3(const void* storage, size_t length) { + SkRBuffer buffer(storage, length); + + int32_t packed; + if (!buffer.readS32(&packed)) { + return 0; + } + + unsigned version = extract_version(packed); + SkASSERT(version <= 3); + + FillType fillType = extract_filltype(packed); + if (version >= kPathPrivTypeEnumVersion) { + switch (extract_serializationtype(packed)) { + case SerializationType::kRRect: + return this->readAsRRect(storage, length); + case SerializationType::kGeneral: + // Fall through to general path deserialization + break; + default: + return 0; + } + } + if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) { + return 0; + } + + // These are written into the serialized data but we no longer use them in the deserialized + // path. If convexity is corrupted it may cause the GPU backend to make incorrect + // rendering choices, possibly crashing. We set them to unknown so that they'll be recomputed if + // requested. + fConvexity = kUnknown_Convexity; + fFirstDirection = SkPathPriv::kUnknown_FirstDirection; + + fFillType = fillType; + fIsVolatile = 0; + SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); + if (!pathRef) { + return 0; + } + + fPathRef.reset(pathRef); + SkDEBUGCODE(this->validate();) + buffer.skipToAlign4(); + return buffer.pos(); +} + diff --git a/src/core/SkSafeMath.h b/src/core/SkSafeMath.h index 949e9c4554..0bc0fbfac4 100644 --- a/src/core/SkSafeMath.h +++ b/src/core/SkSafeMath.h @@ -8,6 +8,8 @@ #ifndef SkSafeMath_DEFINED #define SkSafeMath_DEFINED +#include "SkTypes.h" + // SkSafeMath always check that a series of operations do not overflow. // This must be correct for all platforms, because this is a check for safety at runtime. diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index 3b497e50aa..a87b371b5e 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -2528,100 +2528,6 @@ static void write_and_read_back(skiatest::Reporter* reporter, REPORTER_ASSERT(reporter, origBounds == readBackBounds); } -static void test_corrupt_flattening(skiatest::Reporter* reporter) { - SkPath path; - path.moveTo(1, 2); - path.lineTo(3, 2); - path.quadTo(4, 2, 5, 4); - path.conicTo(5, 6, 3, 7, 0.5f); - path.cubicTo(2, 6, 2, 4, 4, 1); - uint8_t buffer[1024]; - - // Make sure these properties are computed prior to serialization. - SkPathPriv::FirstDirection dir; - SkAssertResult(SkPathPriv::CheapComputeFirstDirection(path, &dir)); - bool isConvex = path.isConvex(); - - SkDEBUGCODE(size_t size =) path.writeToMemory(buffer); - SkASSERT(size <= sizeof(buffer)); - - // find where the counts and verbs are stored : from the impl in SkPathRef.cpp - int32_t* vCount = (int32_t*)&buffer[16]; - SkASSERT(*vCount == 5); - int32_t* pCount = (int32_t*)&buffer[20]; - SkASSERT(*pCount == 9); - int32_t* cCount = (int32_t*)&buffer[24]; - SkASSERT(*cCount == 1); - uint8_t* verbs = &buffer[28]; - - REPORTER_ASSERT(reporter, path.readFromMemory(buffer, sizeof(buffer))); - - // check that we detect under/over-flow of counts - - *vCount += 1; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - *vCount -= 1; // restore - - *pCount += 1; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - *pCount -= 2; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - *pCount += 1; // restore - - *cCount += 1; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - *cCount -= 2; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - *cCount += 1; // restore - - // Check that we detect when the verbs indicate more or fewer pts/conics - - uint8_t save = verbs[0]; - SkASSERT(save == SkPath::kCubic_Verb); - verbs[0] = SkPath::kQuad_Verb; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - verbs[0] = save; - - save = verbs[1]; - SkASSERT(save == SkPath::kConic_Verb); - verbs[1] = SkPath::kQuad_Verb; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - verbs[1] = SkPath::kCubic_Verb; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - verbs[1] = save; - - // Check that we detect invalid verbs - save = verbs[1]; - verbs[1] = 17; - REPORTER_ASSERT(reporter, !path.readFromMemory(buffer, sizeof(buffer))); - verbs[1] = save; - - // kConvexity_SerializationShift defined privately in SkPath.h - static constexpr int32_t kConvexityMask = 0x7 << 16; - int32_t* packed = (int32_t*)buffer; - int32_t savedPacked = *packed; - SkPath::Convexity wrongConvexity = - isConvex ? SkPath::kConcave_Convexity : SkPath::kConvex_Convexity; - *packed = (savedPacked & ~kConvexityMask) | (wrongConvexity << 16); - REPORTER_ASSERT(reporter, path.readFromMemory(buffer, sizeof(buffer))); - // We should ignore the stored convexity and recompute from the deserialized data. - REPORTER_ASSERT(reporter, path.isConvex() == isConvex); - *packed = savedPacked; - - // kDirection_SerializationShift defined privately in SkPath.h - static constexpr int32_t kDirectionMask = 0x3 << 26; - SkPathPriv::FirstDirection wrongDir = (dir == SkPathPriv::kCW_FirstDirection) - ? SkPathPriv::kCCW_FirstDirection - : SkPathPriv::kCW_FirstDirection; - *packed = (savedPacked & ~kDirectionMask) | (wrongDir << 26); - REPORTER_ASSERT(reporter, path.readFromMemory(buffer, sizeof(buffer))); - // We should ignore the stored direction and recompute from the deserialized data. - SkPathPriv::FirstDirection newDir; - SkAssertResult(SkPathPriv::CheapComputeFirstDirection(path, &newDir)); - REPORTER_ASSERT(reporter, newDir == dir); - *packed = savedPacked; -} - static void test_flattening(skiatest::Reporter* reporter) { SkPath p; @@ -2670,8 +2576,6 @@ static void test_flattening(skiatest::Reporter* reporter) { write_and_read_back(reporter, oval); } - - test_corrupt_flattening(reporter); } static void test_transform(skiatest::Reporter* reporter) { @@ -4874,29 +4778,6 @@ DEF_TEST(PathRefSerialization, reporter) { REPORTER_ASSERT(reporter, readBack == path); } - // uint32_t[] offset into serialized path. - const size_t verbCountOffset = 4; - const size_t pointCountOffset = 5; - const size_t conicCountOffset = 6; - - // Verify that this test is changing the right values. - const int* writtenValues = static_cast<const int*>(data->data()); - REPORTER_ASSERT(reporter, writtenValues[verbCountOffset] == numVerbs); - REPORTER_ASSERT(reporter, writtenValues[pointCountOffset] == numPoints); - REPORTER_ASSERT(reporter, writtenValues[conicCountOffset] == numConics); - - // Too many verbs, points, or conics fails to deserialize silently. - const int tooManyObjects = INT_MAX; - size_t offsets[] = {verbCountOffset, pointCountOffset, conicCountOffset}; - for (size_t i = 0; i < 3; ++i) { - SkAutoMalloc storage_copy(bytesWritten); - memcpy(storage_copy.get(), data->data(), bytesWritten); - static_cast<int*>(storage_copy.get())[offsets[i]] = tooManyObjects; - SkPath readBack; - size_t bytesRead = readBack.readFromMemory(storage_copy.get(), bytesWritten); - REPORTER_ASSERT(reporter, !bytesRead); - } - // One less byte (rounded down to alignment) than was written will also // fail to be deserialized. { |