aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2018-02-21 15:55:14 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-02-21 21:22:37 +0000
commit267ecccfed954079e9ec37182d6c9aafe3007525 (patch)
tree4a0fed781314707db9d75efc063330496652557e
parent528b446889c7967d220d2a679912f698067ff072 (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.gni1
-rw-r--r--include/core/SkPath.h28
-rw-r--r--src/core/SkBuffer.cpp26
-rw-r--r--src/core/SkBuffer.h7
-rw-r--r--src/core/SkPath.cpp145
-rw-r--r--src/core/SkPath_serial.cpp290
-rw-r--r--src/core/SkSafeMath.h2
-rw-r--r--tests/PathTest.cpp119
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.
{