Serialize rrect/oval paths as rrects rather than points and verbs.
This is a step towards not trusting deserialized isoval/isrrect for general paths without losing the performance advantages of knowing that a path is a rrect/oval. Change-Id: I1a8c0608c0f29f4bf7a118dfa1d475e2ab5802ea Reviewed-on: https://skia-review.googlesource.com/49761 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
2fbf1bc8c9
commit
1e3b79e0c6
@ -1682,20 +1682,25 @@ enum Direction {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
enum SerializationOffsets {
|
enum SerializationOffsets {
|
||||||
// 1 free bit at 29
|
kType_SerializationShift = 28, // requires 4 bits
|
||||||
kUnused1_SerializationShift = 28, // 1 free bit
|
kDirection_SerializationShift = 26, // requires 2 bits
|
||||||
kDirection_SerializationShift = 26, // requires 2 bits
|
|
||||||
kIsVolatile_SerializationShift = 25, // requires 1 bit
|
kIsVolatile_SerializationShift = 25, // requires 1 bit
|
||||||
// 1 free bit at 24
|
// 1 free bit at 24
|
||||||
kConvexity_SerializationShift = 16, // requires 8 bits
|
kConvexity_SerializationShift = 16, // requires 8 bits
|
||||||
kFillType_SerializationShift = 8, // requires 8 bits
|
kFillType_SerializationShift = 8, // requires 8 bits
|
||||||
// low-8-bits are version
|
// low-8-bits are version
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SerializationVersions {
|
enum SerializationVersions {
|
||||||
kPathPrivFirstDirection_Version = 1,
|
kPathPrivFirstDirection_Version = 1,
|
||||||
kPathPrivLastMoveToIndex_Version = 2,
|
kPathPrivLastMoveToIndex_Version = 2,
|
||||||
kCurrent_Version = 2
|
kPathPrivTypeEnumVersion = 3,
|
||||||
|
kCurrent_Version = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SerializationType {
|
||||||
|
kGeneral = 0,
|
||||||
|
kRRect = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
sk_sp<SkPathRef> fPathRef;
|
sk_sp<SkPathRef> fPathRef;
|
||||||
@ -1717,6 +1722,9 @@ private:
|
|||||||
*/
|
*/
|
||||||
void copyFields(const SkPath& that);
|
void copyFields(const SkPath& that);
|
||||||
|
|
||||||
|
size_t writeToMemoryAsRRect(int32_t packedHeader, void* buffer) const;
|
||||||
|
size_t readFromMemoryAsRRect(const void* buffer) const;
|
||||||
|
|
||||||
friend class Iter;
|
friend class Iter;
|
||||||
friend class SkPathPriv;
|
friend class SkPathPriv;
|
||||||
friend class SkPathStroker;
|
friend class SkPathStroker;
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
class SkPath;
|
class SkPath;
|
||||||
class SkMatrix;
|
class SkMatrix;
|
||||||
|
class SkRBuffer;
|
||||||
|
class SkWBuffer;
|
||||||
|
|
||||||
// Path forward:
|
// Path forward:
|
||||||
// core work
|
// core work
|
||||||
@ -302,6 +304,7 @@ public:
|
|||||||
* a multiple of 4. Return kSizeInMemory.
|
* a multiple of 4. Return kSizeInMemory.
|
||||||
*/
|
*/
|
||||||
size_t writeToMemory(void* buffer) const;
|
size_t writeToMemory(void* buffer) const;
|
||||||
|
void writeToBuffer(SkWBuffer*) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the rrect from the specified buffer
|
* Reads the rrect from the specified buffer
|
||||||
@ -315,6 +318,7 @@ public:
|
|||||||
* 0 if there was not enough memory available
|
* 0 if there was not enough memory available
|
||||||
*/
|
*/
|
||||||
size_t readFromMemory(const void* buffer, size_t length);
|
size_t readFromMemory(const void* buffer, size_t length);
|
||||||
|
bool readFromBuffer(SkRBuffer*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform by the specified matrix, and put the result in dst.
|
* Transform by the specified matrix, and put the result in dst.
|
||||||
|
@ -2040,22 +2040,56 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
|
|||||||
Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]]
|
Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t SkPath::writeToMemory(void* storage) const {
|
size_t SkPath::writeToMemoryAsRRect(int32_t packedHeader, void* storage) const {
|
||||||
SkDEBUGCODE(this->validate();)
|
SkRect oval;
|
||||||
|
SkRRect rrect;
|
||||||
if (nullptr == storage) {
|
bool isCCW;
|
||||||
const int byteCount = sizeof(int32_t) * 2 + fPathRef->writeSize();
|
unsigned start;
|
||||||
return SkAlign4(byteCount);
|
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);
|
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) |
|
int32_t packed = (fConvexity << kConvexity_SerializationShift) |
|
||||||
(fFillType << kFillType_SerializationShift) |
|
(fFillType << kFillType_SerializationShift) |
|
||||||
(fFirstDirection << kDirection_SerializationShift) |
|
(fFirstDirection << kDirection_SerializationShift) |
|
||||||
(fIsVolatile << kIsVolatile_SerializationShift) |
|
(fIsVolatile << kIsVolatile_SerializationShift) |
|
||||||
kCurrent_Version;
|
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(packed);
|
||||||
buffer.write32(fLastMoveToIndex);
|
buffer.write32(fLastMoveToIndex);
|
||||||
|
|
||||||
@ -2081,13 +2115,51 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned version = packed & 0xFF;
|
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)) {
|
if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
|
fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
|
||||||
fFillType = (packed >> kFillType_SerializationShift) & 0x3;
|
fFillType = fillType;
|
||||||
uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
|
|
||||||
fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1;
|
fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1;
|
||||||
SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer);
|
SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer);
|
||||||
if (!pathRef) {
|
if (!pathRef) {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "SkRRect.h"
|
#include "SkRRect.h"
|
||||||
|
#include "SkBuffer.h"
|
||||||
#include "SkMatrix.h"
|
#include "SkMatrix.h"
|
||||||
#include "SkScaleToSides.h"
|
#include "SkScaleToSides.h"
|
||||||
|
|
||||||
@ -461,6 +462,11 @@ size_t SkRRect::writeToMemory(void* buffer) const {
|
|||||||
return kSizeInMemory;
|
return kSizeInMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkRRect::writeToBuffer(SkWBuffer* buffer) const {
|
||||||
|
// Serialize only the rect and corners, but not the derived type tag.
|
||||||
|
buffer->write(this, kSizeInMemory);
|
||||||
|
}
|
||||||
|
|
||||||
size_t SkRRect::readFromMemory(const void* buffer, size_t length) {
|
size_t SkRRect::readFromMemory(const void* buffer, size_t length) {
|
||||||
if (length < kSizeInMemory) {
|
if (length < kSizeInMemory) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -478,6 +484,20 @@ size_t SkRRect::readFromMemory(const void* buffer, size_t length) {
|
|||||||
return kSizeInMemory;
|
return kSizeInMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkRRect::readFromBuffer(SkRBuffer* buffer) {
|
||||||
|
if (buffer->available() < kSizeInMemory) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SkRRect readData;
|
||||||
|
buffer->read(&readData, kSizeInMemory);
|
||||||
|
if (!AreRectAndRadiiValid(readData.fRect, readData.fRadii)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(this, &readData, kSizeInMemory);
|
||||||
|
this->computeType();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#include "SkString.h"
|
#include "SkString.h"
|
||||||
#include "SkStringUtils.h"
|
#include "SkStringUtils.h"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user