aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkReader32.h9
-rw-r--r--include/core/SkWriter32.h17
-rw-r--r--include/pipe/SkGPipe.h9
-rw-r--r--samplecode/SampleApp.cpp4
-rw-r--r--src/core/SkWriter32.cpp69
-rw-r--r--src/pipe/SkGPipePriv.h2
-rw-r--r--src/pipe/SkGPipeRead.cpp26
-rw-r--r--src/pipe/SkGPipeWrite.cpp34
-rw-r--r--tests/Reader32Test.cpp93
-rw-r--r--tests/Writer32Test.cpp90
-rw-r--r--tests/tests_files.mk2
11 files changed, 345 insertions, 10 deletions
diff --git a/include/core/SkReader32.h b/include/core/SkReader32.h
index 03a34c7ca6..654ebd5f19 100644
--- a/include/core/SkReader32.h
+++ b/include/core/SkReader32.h
@@ -101,7 +101,14 @@ public:
uint16_t readU16() { return (uint16_t)this->readInt(); }
int32_t readS32() { return this->readInt(); }
uint32_t readU32() { return this->readInt(); }
-
+
+ /**
+ * Read the length of a string written by SkWriter32::writeString()
+ * (if len is not NULL) and return the null-ternimated address of the
+ * string.
+ */
+ const char* readString(size_t* len = NULL);
+
private:
// these are always 4-byte aligned
const char* fCurr; // current position within buffer
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index 8e133c2202..c8ebb6a6ef 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -100,7 +100,22 @@ public:
}
void writePad(const void* src, size_t size);
-
+
+ /**
+ * Writes a string to the writer, which can be retrieved with
+ * SkReader32::readString().
+ * The length can be specified, or if -1 is passed, it will be computed by
+ * calling strlen(). The length must be < 0xFFFF
+ */
+ void writeString(const char* str, size_t len = (size_t)-1);
+
+ /**
+ * Computes the size (aligned to multiple of 4) need to write the string
+ * in a call to writeString(). If the length is not specified, it will be
+ * computed by calling strlen().
+ */
+ static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
+
// return the current offset (will always be a multiple of 4)
uint32_t size() const { return fSize; }
void reset();
diff --git a/include/pipe/SkGPipe.h b/include/pipe/SkGPipe.h
index e9f850260e..0ca66ab9cb 100644
--- a/include/pipe/SkGPipe.h
+++ b/include/pipe/SkGPipe.h
@@ -19,6 +19,7 @@
#define SkGPipe_DEFINED
#include "SkWriter32.h"
+#include "SkFlattenable.h"
class SkCanvas;
@@ -74,7 +75,12 @@ public:
~SkGPipeWriter();
bool isRecording() const { return NULL != fCanvas; }
- SkCanvas* startRecording(SkGPipeController*);
+
+ enum Flags {
+ kCrossProcess_Flag = 1 << 0,
+ };
+
+ SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0);
// called in destructor, but can be called sooner once you know there
// should be no more drawing calls made into the recording canvas.
@@ -83,6 +89,7 @@ public:
private:
class SkGPipeCanvas* fCanvas;
SkGPipeController* fController;
+ SkFactorySet fFactorySet;
SkWriter32 fWriter;
};
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 76f4da1e26..fe998ee732 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1470,7 +1470,9 @@ void SampleView::onDraw(SkCanvas* canvas) {
SimplePC controller(canvas);
SkGPipeWriter writer;
if (fUsePipe) {
- canvas = writer.startRecording(&controller);
+ uint32_t flags = SkGPipeWriter::kCrossProcess_Flag;
+// flags = 0;
+ canvas = writer.startRecording(&controller, flags);
}
#endif
diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp
index 141f751982..9a60b8e66f 100644
--- a/src/core/SkWriter32.cpp
+++ b/src/core/SkWriter32.cpp
@@ -185,3 +185,72 @@ bool SkWriter32::writeToStream(SkWStream* stream) {
return true;
}
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkReader32.h"
+
+const char* SkReader32::readString(size_t* outLen) {
+ // we need to read at least 1-4 bytes
+ SkASSERT(this->isAvailable(4));
+ const uint8_t* base = (const uint8_t*)this->peek();
+ const uint8_t* ptr = base;
+
+ size_t len = *ptr++;
+ if (0xFF == len) {
+ len = (ptr[0] << 8) | ptr[1];
+ ptr += 2;
+ SkASSERT(len < 0xFFFF);
+ }
+
+ // skip what we've read, and 0..3 pad bytes
+ // add 1 for the terminating 0 that writeString() included
+ size_t alignedSize = SkAlign4(len + (ptr - base) + 1);
+ this->skip(alignedSize);
+
+ if (outLen) {
+ *outLen = len;
+ }
+ return (const char*)ptr;
+}
+
+void SkWriter32::writeString(const char str[], size_t len) {
+ if ((long)len < 0) {
+ SkASSERT(str);
+ len = strlen(str);
+ }
+ size_t lenBytes = 1;
+ if (len >= 0xFF) {
+ lenBytes = 3;
+ SkASSERT(len < 0xFFFF);
+ }
+ // add 1 since we also write a terminating 0
+ size_t alignedLen = SkAlign4(lenBytes + len + 1);
+ uint8_t* ptr = (uint8_t*)this->reserve(alignedLen);
+ if (1 == lenBytes) {
+ *ptr++ = SkToU8(len);
+ } else {
+ *ptr++ = 0xFF;
+ *ptr++ = SkToU8(len >> 8);
+ *ptr++ = len & 0xFF;
+ }
+ memcpy(ptr, str, len);
+ ptr[len] = 0;
+ // we may have left 0,1,2,3 bytes uninitialized, since we reserved align4
+ // number of bytes. That's ok, since the reader will know to skip those
+}
+
+size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
+ if ((long)len < 0) {
+ SkASSERT(str);
+ len = strlen(str);
+ }
+ size_t lenBytes = 1;
+ if (len >= 0xFF) {
+ lenBytes = 3;
+ SkASSERT(len < 0xFFFF);
+ }
+ // add 1 since we also write a terminating 0
+ return SkAlign4(lenBytes + len + 1);
+}
+
+
diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index 06ba7b6aaa..fb1553693d 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -75,6 +75,8 @@ enum DrawOps {
kDef_Typeface_DrawOp,
kDef_Flattenable_DrawOp,
+ kName_Flattenable_DrawOp, // index <--> name
+
// these are signals to playback, not drawing verbs
kDone_DrawOp,
};
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 5e6c632b91..c72aa572d4 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -70,7 +70,10 @@ public:
SkGPipeState();
~SkGPipeState();
- void setReader(SkFlattenableReadBuffer* reader) { fReader = reader; }
+ void setReader(SkFlattenableReadBuffer* reader) {
+ fReader = reader;
+ fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count());
+ }
const SkPaint& paint() const { return fPaint; }
SkPaint* editPaint() { return &fPaint; }
@@ -83,11 +86,21 @@ public:
}
void defFlattenable(PaintFlats pf, unsigned index) {
+ SkASSERT(index == fFlatArray.count() + 1);
SkFlattenable* obj = fReader->readFlattenable();
*fFlatArray.append() = obj;
- SkASSERT(index == fFlatArray.count());
}
+ void nameFlattenable(PaintFlats pf, unsigned index) {
+ SkASSERT(index == fFactoryArray.count() + 1);
+ const char* name = fReader->readString();
+ SkFlattenable::Factory fact = SkFlattenable::NameToFactory(name);
+ *fFactoryArray.append() = fact;
+
+ // update this each time we grow the array
+ fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count());
+ }
+
void addTypeface() {
size_t size = fReader->readU32();
const void* data = fReader->skip(SkAlign4(size));
@@ -104,6 +117,7 @@ private:
SkPaint fPaint;
SkTDArray<SkFlattenable*> fFlatArray;
SkTDArray<SkTypeface*> fTypefaces;
+ SkTDArray<SkFlattenable::Factory> fFactoryArray;
};
///////////////////////////////////////////////////////////////////////////////
@@ -430,6 +444,13 @@ static void def_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32,
state->defFlattenable(pf, index);
}
+static void name_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32,
+ SkGPipeState* state) {
+ PaintFlats pf = (PaintFlats)DrawOp_unpackFlags(op32);
+ unsigned index = DrawOp_unpackData(op32);
+ state->nameFlattenable(pf, index);
+}
+
///////////////////////////////////////////////////////////////////////////////
static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
@@ -476,6 +497,7 @@ static const ReadProc gReadTable[] = {
paintOp_rp,
def_Typeface_rp,
def_PaintFlat_rp,
+ name_PaintFlat_rp,
done_rp
};
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index aa6ed821b6..5e8ba3dd2a 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -77,7 +77,7 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
class SkGPipeCanvas : public SkCanvas {
public:
- SkGPipeCanvas(SkGPipeController*, SkWriter32*);
+ SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
virtual ~SkGPipeCanvas();
void finish() {
@@ -133,6 +133,7 @@ public:
virtual void drawData(const void*, size_t);
private:
+ SkFactorySet* fFactorySet; // optional, only used if cross-process
SkGPipeController* fController;
SkWriter32& fWriter;
size_t fBlockSize; // amount allocated for writer
@@ -201,7 +202,27 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
return 0;
}
+ if (fFactorySet) {
+ uint32_t id = fFactorySet->find((void*)fact);
+ if (0 == id) {
+ const char* name = SkFlattenable::FactoryToName(fact);
+ if (NULL == name) {
+ return 0;
+ }
+ size_t len = strlen(name);
+ size_t size = SkWriter32::WriteStringSize(name, len);
+ if (!this->needOpBytes(size)) {
+ return 0;
+ }
+ unsigned id = fFactorySet->add(fact);
+ this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
+ fWriter.writeString(name, len);
+ }
+ }
+
SkFlattenableWriteBuffer tmpWriter(1024);
+ tmpWriter.setFactoryRecorder(fFactorySet);
+
tmpWriter.writeFlattenable(obj);
size_t len = tmpWriter.size();
size_t allocSize = len + sizeof(FlatData);
@@ -236,7 +257,8 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
#define MIN_BLOCK_SIZE (16 * 1024)
SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
- SkWriter32* writer) : fWriter(*writer) {
+ SkWriter32* writer, SkFactorySet* fset)
+ : fWriter(*writer), fFactorySet(fset) {
fController = controller;
fDone = false;
fBlockSize = 0; // need first block from controller
@@ -768,10 +790,14 @@ SkGPipeWriter::~SkGPipeWriter() {
SkSafeUnref(fCanvas);
}
-SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller) {
+SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
+ uint32_t flags) {
if (NULL == fCanvas) {
fWriter.reset(NULL, 0);
- fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter));
+ fFactorySet.reset();
+ fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
+ (flags & kCrossProcess_Flag) ?
+ &fFactorySet : NULL));
}
return fCanvas;
}
diff --git a/tests/Reader32Test.cpp b/tests/Reader32Test.cpp
new file mode 100644
index 0000000000..f57df71d53
--- /dev/null
+++ b/tests/Reader32Test.cpp
@@ -0,0 +1,93 @@
+/*
+ Copyright 2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+
+#include "SkReader32.h"
+#include "Test.h"
+
+static void assert_eof(skiatest::Reporter* reporter, const SkReader32& reader) {
+ REPORTER_ASSERT(reporter, reader.eof());
+ REPORTER_ASSERT(reporter, reader.size() == reader.offset());
+ REPORTER_ASSERT(reporter, (const char*)reader.peek() ==
+ (const char*)reader.base() + reader.size());
+}
+
+static void assert_start(skiatest::Reporter* reporter, const SkReader32& reader) {
+ REPORTER_ASSERT(reporter, 0 == reader.offset());
+ REPORTER_ASSERT(reporter, reader.size() == reader.available());
+ REPORTER_ASSERT(reporter, reader.isAvailable(reader.size()));
+ REPORTER_ASSERT(reporter, !reader.isAvailable(reader.size() + 1));
+ REPORTER_ASSERT(reporter, reader.peek() == reader.base());
+}
+
+static void assert_empty(skiatest::Reporter* reporter, const SkReader32& reader) {
+ REPORTER_ASSERT(reporter, 0 == reader.size());
+ REPORTER_ASSERT(reporter, 0 == reader.offset());
+ REPORTER_ASSERT(reporter, 0 == reader.available());
+ REPORTER_ASSERT(reporter, !reader.isAvailable(1));
+ assert_eof(reporter, reader);
+ assert_start(reporter, reader);
+}
+
+static void Tests(skiatest::Reporter* reporter) {
+ SkReader32 reader;
+ assert_empty(reporter, reader);
+ REPORTER_ASSERT(reporter, NULL == reader.base());
+ REPORTER_ASSERT(reporter, NULL == reader.peek());
+
+ size_t i;
+
+ const int32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ const SkScalar data2[] = { 0, SK_Scalar1, -SK_Scalar1, SK_Scalar1/2 };
+ char buffer[SkMax32(sizeof(data), sizeof(data2))];
+
+ reader.setMemory(data, sizeof(data));
+ for (i = 0; i < SK_ARRAY_COUNT(data); ++i) {
+ REPORTER_ASSERT(reporter, sizeof(data) == reader.size());
+ REPORTER_ASSERT(reporter, i*4 == reader.offset());
+ REPORTER_ASSERT(reporter, (const void*)data == reader.base());
+ REPORTER_ASSERT(reporter, (const void*)&data[i] == reader.peek());
+ REPORTER_ASSERT(reporter, data[i] == reader.readInt());
+ }
+ assert_eof(reporter, reader);
+ reader.rewind();
+ assert_start(reporter, reader);
+ reader.read(buffer, sizeof(buffer));
+ REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(buffer)));
+
+ reader.setMemory(data2, sizeof(data2));
+ for (i = 0; i < SK_ARRAY_COUNT(data2); ++i) {
+ REPORTER_ASSERT(reporter, sizeof(data2) == reader.size());
+ REPORTER_ASSERT(reporter, i*4 == reader.offset());
+ REPORTER_ASSERT(reporter, (const void*)data2 == reader.base());
+ REPORTER_ASSERT(reporter, (const void*)&data2[i] == reader.peek());
+ REPORTER_ASSERT(reporter, data2[i] == reader.readScalar());
+ }
+ assert_eof(reporter, reader);
+ reader.rewind();
+ assert_start(reporter, reader);
+ reader.read(buffer, sizeof(buffer));
+ REPORTER_ASSERT(reporter, !memcmp(data2, buffer, sizeof(buffer)));
+
+ reader.setMemory(NULL, 0);
+ assert_empty(reporter, reader);
+ REPORTER_ASSERT(reporter, NULL == reader.base());
+ REPORTER_ASSERT(reporter, NULL == reader.peek());
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Reader32", Reader32Class, Tests)
+
diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp
new file mode 100644
index 0000000000..63b1209e98
--- /dev/null
+++ b/tests/Writer32Test.cpp
@@ -0,0 +1,90 @@
+/*
+ Copyright 2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+
+#include "SkReader32.h"
+#include "SkWriter32.h"
+#include "Test.h"
+
+static void test1(skiatest::Reporter* reporter, SkWriter32* writer) {
+ const uint32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) {
+ REPORTER_ASSERT(reporter, i*4 == writer->size());
+ writer->write32(data[i]);
+ uint32_t* addr = writer->peek32(i * 4);
+ REPORTER_ASSERT(reporter, data[i] == *addr);
+ }
+
+ char buffer[sizeof(data)];
+ REPORTER_ASSERT(reporter, sizeof(buffer) == writer->size());
+ writer->flatten(buffer);
+ REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(buffer)));
+}
+
+static void test2(skiatest::Reporter* reporter, SkWriter32* writer) {
+ static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz";
+ size_t i;
+
+ size_t len = 0;
+ for (i = 0; i <= 26; ++i) {
+ len += SkWriter32::WriteStringSize(gStr, i);
+ writer->writeString(gStr, i);
+ }
+ REPORTER_ASSERT(reporter, writer->size() == len);
+
+ SkAutoMalloc storage(len);
+ writer->flatten(storage.get());
+
+ SkReader32 reader;
+ reader.setMemory(storage.get(), len);
+ for (i = 0; i <= 26; ++i) {
+ REPORTER_ASSERT(reporter, !reader.eof());
+ const char* str = reader.readString(&len);
+ REPORTER_ASSERT(reporter, i == len);
+ REPORTER_ASSERT(reporter, strlen(str) == len);
+ REPORTER_ASSERT(reporter, !memcmp(str, gStr, len));
+ }
+ REPORTER_ASSERT(reporter, reader.eof());
+}
+
+static void Tests(skiatest::Reporter* reporter) {
+ // dynamic allocator
+ {
+ SkWriter32 writer(256 * 4);
+ REPORTER_ASSERT(reporter, NULL == writer.getSingleBlock());
+ test1(reporter, &writer);
+
+ writer.reset();
+ test2(reporter, &writer);
+ }
+
+ // single-block
+ {
+ SkWriter32 writer(0);
+ uint32_t storage[256];
+ REPORTER_ASSERT(reporter, NULL == writer.getSingleBlock());
+ writer.reset(storage, sizeof(storage));
+ REPORTER_ASSERT(reporter, (void*)storage == writer.getSingleBlock());
+ test1(reporter, &writer);
+
+ writer.reset(storage, sizeof(storage));
+ test2(reporter, &writer);
+ }
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Writer32", Writer32Class, Tests)
+
diff --git a/tests/tests_files.mk b/tests/tests_files.mk
index 28d5fe75f9..9b90179c7e 100644
--- a/tests/tests_files.mk
+++ b/tests/tests_files.mk
@@ -22,6 +22,7 @@ SOURCE := \
ParsePathTest.cpp \
PathMeasureTest.cpp \
PathTest.cpp \
+ Reader32Test.cpp \
RefDictTest.cpp \
RegionTest.cpp \
Sk64Test.cpp \
@@ -33,4 +34,5 @@ SOURCE := \
Test.cpp \
TestSize.cpp \
UtilsTest.cpp \
+ Writer32Test.cpp \
XfermodeTest.cpp