return (uint32_t*)(fData + offset);
}
- // Read or write 4 bytes at offset, which must be a multiple of 4 <= size().
- uint32_t read32At(size_t offset) {
+ /**
+ * Read a T record at offset, which must be a multiple of 4. Only legal if the record
+ * was writtern atomically using the write methods below.
+ */
+ template<typename T>
+ const T& readTAt(size_t offset) const {
SkASSERT(SkAlign4(offset) == offset);
SkASSERT(offset < fUsed);
- return *(uint32_t*)(fData + offset);
+ return *(T*)(fData + offset);
}
- void write32At(size_t offset, uint32_t val) {
+ /**
+ * Overwrite a T record at offset, which must be a multiple of 4. Only legal if the record
+ * was writtern atomically using the write methods below.
+ */
+ template<typename T>
+ void overwriteTAt(size_t offset, const T& value) {
SkASSERT(SkAlign4(offset) == offset);
SkASSERT(offset < fUsed);
- *(uint32_t*)(fData + offset) = val;
+ *(T*)(fData + offset) = value;
}
bool writeBool(bool value) {
* filled in with zeroes.
*/
uint32_t* reservePad(size_t size) {
- uint32_t* p = this->reserve(SkAlign4(size));
- uint8_t* tail = (uint8_t*)p + size;
- switch (SkAlign4(size) - size) {
- default: SkDEBUGFAIL("SkAlign4(x) - x should always be 0, 1, 2, or 3.");
- case 3: *tail++ = 0x00; // fallthrough is intentional
- case 2: *tail++ = 0x00; // fallthrough is intentional
- case 1: *tail++ = 0x00;
- case 0: ;/*nothing to do*/
+ size_t alignedSize = SkAlign4(size);
+ uint32_t* p = this->reserve(alignedSize);
+ if (alignedSize != size) {
+ SkASSERT(alignedSize >= 4);
+ p[alignedSize / 4 - 1] = 0;
}
return p;
}
}
// SkDEBUGCODE(uint32_t peek = writer->read32At(curClip.fOffset);)
// SkASSERT(-1 == peek);
- writer->write32At(curClip.fOffset, restoreOffset);
+ writer->overwriteTAt(curClip.fOffset, restoreOffset);
SkDEBUGCODE(curClip.fOffset = -1;)
}
}
* Read the op code from 'offset' in 'writer' and extract the size too.
*/
static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
- uint32_t peek = writer->read32At(offset);
+ uint32_t peek = writer->readTAt<uint32_t>(offset);
uint32_t op;
UNPACK_8_24(peek, op, *size);
if (MASK_24 == *size) {
// size required its own slot right after the op code
- *size = writer->read32At(offset+kUInt32Size);
+ *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
}
return (DrawType) op;
}
// back up to the save block
// TODO: add a stack to track save*/restore offsets rather than searching backwards
while (offset > 0) {
- offset = writer->read32At(offset);
+ offset = writer->readTAt<uint32_t>(offset);
}
int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
* field alone so the NOOP can be skipped later.
*/
static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
- uint32_t command = writer->read32At(offset);
- writer->write32At(offset, (command & MASK_24) | (NOOP << 24));
+ uint32_t command = writer->readTAt<uint32_t>(offset);
+ writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
}
/*
uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
// we have a match, now we need to get the paints involved
- uint32_t dbmPaintId = writer->read32At(dbmInfo.fOffset+dbmPaintOffset);
- uint32_t saveLayerPaintId = writer->read32At(saveLayerInfo.fOffset+slPaintOffset);
+ uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
+ uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
if (0 == saveLayerPaintId) {
// In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
// In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
// and signal the caller (by returning true) to not add the RESTORE op
convert_command_to_noop(writer, saveLayerInfo.fOffset);
- writer->write32At(dbmInfo.fOffset+dbmPaintOffset, saveLayerPaintId);
+ writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
return true;
}
// kill the saveLayer and alter the DBMR2R's paint to be the modified one
convert_command_to_noop(writer, saveLayerInfo.fOffset);
- writer->write32At(dbmInfo.fOffset+dbmPaintOffset, data->index());
+ writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
return true;
}
// back up to the save block
// TODO: add a stack to track save*/restore offsets rather than searching backwards
while (offset > 0) {
- offset = writer->read32At(offset);
+ offset = writer->readTAt<uint32_t>(offset);
}
int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
// back up to the save block
while (offset > 0) {
- offset = writer->read32At(offset);
+ offset = writer->readTAt<uint32_t>(offset);
}
// now offset points to a save
SkASSERT(kSaveSize == opSize);
// get the save flag (last 4-bytes of the space allocated for the opSize)
- SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->read32At(offset+4);
+ SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
// This function's optimization is only correct for kMatrixClip style saves.
// TODO: set checkMatrix & checkClip booleans here and then check for the
void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
int32_t offset = fRestoreOffsetStack.top();
while (offset > 0) {
- uint32_t peek = fWriter.read32At(offset);
- fWriter.write32At(offset, restoreOffset);
+ uint32_t peek = fWriter.readTAt<uint32_t>(offset);
+ fWriter.overwriteTAt(offset, restoreOffset);
offset = peek;
}
flattenable->flatten(*this);
size_t objSize = fWriter.bytesWritten() - offset;
// record the obj's size
- fWriter.write32At(offset - sizeof(uint32_t), SkToU32(objSize));
+ fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize));
}
if ((long)len < 0) {
len = strlen(str);
}
- this->write32(len);
- // add 1 since we also write a terminating 0
- size_t alignedLen = SkAlign4(len + 1);
- char* ptr = (char*)this->reserve(alignedLen);
- {
- // Write the terminating 0 and fill in the rest with zeroes
- uint32_t* padding = (uint32_t*)(ptr + (alignedLen - 4));
- *padding = 0;
- }
- // Copy the string itself.
- memcpy(ptr, str, len);
+
+ // [ 4 byte len ] [ str ... ] [1 - 4 \0s]
+ uint32_t* ptr = this->reservePad(sizeof(uint32_t) + len + 1);
+ *ptr = len;
+ char* chars = (char*)(ptr + 1);
+ memcpy(chars, str, len);
+ chars[len] = '\0';
}
size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) {
REPORTER_ASSERT(reporter, i*4 == writer->bytesWritten());
writer->write32(data[i]);
- REPORTER_ASSERT(reporter, data[i] == writer->read32At(i*4));
+ REPORTER_ASSERT(reporter, data[i] == writer->readTAt<uint32_t>(i * 4));
}
char buffer[sizeof(data)];
}
}
+static void testOverwriteT(skiatest::Reporter* reporter, SkWriter32* writer) {
+ const size_t padding = 64;
+
+ const uint32_t uint1 = 0x12345678;
+ const uint32_t uint2 = 0x98765432;
+ const SkScalar scalar1 = 1234.5678f;
+ const SkScalar scalar2 = 9876.5432f;
+ const SkRect rect1 = SkRect::MakeXYWH(1, 2, 3, 4);
+ const SkRect rect2 = SkRect::MakeXYWH(5, 6, 7, 8);
+
+ for (size_t i = 0; i < (padding / 4); ++i) {
+ writer->write32(0);
+ }
+
+ writer->write32(uint1);
+ writer->writeRect(rect1);
+ writer->writeScalar(scalar1);
+
+ for (size_t i = 0; i < (padding / 4); ++i) {
+ writer->write32(0);
+ }
+
+ REPORTER_ASSERT(reporter, writer->readTAt<uint32_t>(padding) == uint1);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkRect>(padding + sizeof(uint32_t)) == rect1);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkScalar>(
+ padding + sizeof(uint32_t) + sizeof(SkRect)) == scalar1);
+
+ writer->overwriteTAt(padding, uint2);
+ writer->overwriteTAt(padding + sizeof(uint32_t), rect2);
+ writer->overwriteTAt(padding + sizeof(uint32_t) + sizeof(SkRect), scalar2);
+
+ REPORTER_ASSERT(reporter, writer->readTAt<uint32_t>(padding) == uint2);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkRect>(padding + sizeof(uint32_t)) == rect2);
+ REPORTER_ASSERT(reporter, writer->readTAt<SkScalar>(
+ padding + sizeof(uint32_t) + sizeof(SkRect)) == scalar2);
+}
+
DEF_TEST(Writer32_dynamic, reporter) {
SkWriter32 writer;
test1(reporter, &writer);
writer.reset();
testWritePad(reporter, &writer);
+
+ writer.reset();
+ testOverwriteT(reporter, &writer);
}
DEF_TEST(Writer32_contiguous, reporter) {
writer.reset();
testWritePad(reporter, &writer);
+
+ writer.reset();
+ testOverwriteT(reporter, &writer);
}
DEF_TEST(Writer32_large, reporter) {
writer.reset();
testWritePad(reporter, &writer);
+
+ writer.reset();
+ testOverwriteT(reporter, &writer);
}
DEF_TEST(Writer32_misc, reporter) {