summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/skia/src/core/SkPicturePlayback.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/skia/src/core/SkPicturePlayback.cpp')
-rw-r--r--chromium/third_party/skia/src/core/SkPicturePlayback.cpp892
1 files changed, 561 insertions, 331 deletions
diff --git a/chromium/third_party/skia/src/core/SkPicturePlayback.cpp b/chromium/third_party/skia/src/core/SkPicturePlayback.cpp
index 82c7a03bcd2..16887107fb5 100644
--- a/chromium/third_party/skia/src/core/SkPicturePlayback.cpp
+++ b/chromium/third_party/skia/src/core/SkPicturePlayback.cpp
@@ -1,19 +1,22 @@
-
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#include "SkPicturePlayback.h"
-#include "SkPictureRecord.h"
-#include "SkTypeface.h"
-#include "SkOrderedReadBuffer.h"
-#include "SkOrderedWriteBuffer.h"
#include <new>
#include "SkBBoxHierarchy.h"
+#include "SkPicturePlayback.h"
+#include "SkPictureRecord.h"
#include "SkPictureStateTree.h"
+#include "SkReadBuffer.h"
+#include "SkTypeface.h"
#include "SkTSort.h"
+#include "SkWriteBuffer.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#endif
template <typename T> int SafeCount(const T* obj) {
return obj ? obj->count() : 0;
@@ -24,11 +27,51 @@ template <typename T> int SafeCount(const T* obj) {
*/
#define SPEW_CLIP_SKIPPINGx
-SkPicturePlayback::SkPicturePlayback() {
+SkPicturePlayback::PlaybackReplacements::ReplacementInfo*
+SkPicturePlayback::PlaybackReplacements::push() {
+ SkDEBUGCODE(this->validate());
+ return fReplacements.push();
+}
+
+void SkPicturePlayback::PlaybackReplacements::freeAll() {
+ for (int i = 0; i < fReplacements.count(); ++i) {
+ SkDELETE(fReplacements[i].fBM);
+ }
+ fReplacements.reset();
+}
+
+#ifdef SK_DEBUG
+void SkPicturePlayback::PlaybackReplacements::validate() const {
+ // Check that the ranges are monotonically increasing and non-overlapping
+ if (fReplacements.count() > 0) {
+ SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop);
+
+ for (int i = 1; i < fReplacements.count(); ++i) {
+ SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop);
+ SkASSERT(fReplacements[i-1].fStop < fReplacements[i].fStart);
+ }
+ }
+}
+#endif
+
+SkPicturePlayback::SkPicturePlayback(const SkPictInfo& info)
+ : fInfo(info) {
this->init();
}
-SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCopy) {
+void SkPicturePlayback::initForPlayback() const {
+ // ensure that the paths bounds are pre-computed
+ if (NULL != fPathHeap.get()) {
+ for (int i = 0; i < fPathHeap->count(); i++) {
+ (*fPathHeap.get())[i].updateBoundsCache();
+ }
+ }
+}
+
+SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record,
+ const SkPictInfo& info,
+ bool deepCopyOps)
+ : fInfo(info) {
#ifdef SK_DEBUG_SIZE
size_t overallBytes, bitmapBytes, matricesBytes,
paintBytes, pathBytes, pictureBytes, regionBytes;
@@ -66,61 +109,39 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCop
record.dumpPaints();
#endif
- record.validate(record.writeStream().bytesWritten(), 0);
- const SkWriter32& writer = record.writeStream();
- init();
- if (writer.bytesWritten() == 0) {
- fOpData = SkData::NewEmpty();
- return;
- }
+ this->init();
+
+ fOpData = record.opData(deepCopyOps);
fBoundingHierarchy = record.fBoundingHierarchy;
fStateTree = record.fStateTree;
SkSafeRef(fBoundingHierarchy);
SkSafeRef(fStateTree);
+ fContentInfo.set(record.fContentInfo);
if (NULL != fBoundingHierarchy) {
fBoundingHierarchy->flushDeferredInserts();
}
- {
- size_t size = writer.bytesWritten();
- void* buffer = sk_malloc_throw(size);
- writer.flatten(buffer);
- SkASSERT(!fOpData);
- fOpData = SkData::NewFromMalloc(buffer, size);
- }
-
// copy over the refcnt dictionary to our reader
record.fFlattenableHeap.setupPlaybacks();
fBitmaps = record.fBitmapHeap->extractBitmaps();
- fMatrices = record.fMatrices.unflattenToArray();
fPaints = record.fPaints.unflattenToArray();
- fRegions = record.fRegions.unflattenToArray();
fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
- fPathHeap.reset(SkSafeRef(record.fPathHeap));
+ fPathHeap.reset(SkSafeRef(record.pathHeap()));
- // ensure that the paths bounds are pre-computed
- if (fPathHeap.get()) {
- for (int i = 0; i < fPathHeap->count(); i++) {
- (*fPathHeap)[i].updateBoundsCache();
- }
- }
+ this->initForPlayback();
- const SkTDArray<SkPicture* >& pictures = record.getPictureRefs();
+ const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
fPictureCount = pictures.count();
if (fPictureCount > 0) {
- fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
+ fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
for (int i = 0; i < fPictureCount; i++) {
- if (deepCopy) {
- fPictureRefs[i] = pictures[i]->clone();
- } else {
- fPictureRefs[i] = pictures[i];
- fPictureRefs[i]->ref();
- }
+ fPictureRefs[i] = pictures[i];
+ fPictureRefs[i]->ref();
}
}
@@ -146,96 +167,39 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCop
#endif
}
-static bool needs_deep_copy(const SkPaint& paint) {
- /*
- * These fields are known to be immutable, and so can be shallow-copied
- *
- * getTypeface()
- * getAnnotation()
- * paint.getColorFilter()
- * getXfermode()
- */
-
- return paint.getPathEffect() ||
- paint.getShader() ||
- paint.getMaskFilter() ||
- paint.getRasterizer() ||
- paint.getLooper() ||
- paint.getImageFilter();
-}
-
-SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo) {
+SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo)
+ : fInfo(src.fInfo) {
this->init();
fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get()));
fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
- fMatrices = SkSafeRef(src.fMatrices);
- fRegions = SkSafeRef(src.fRegions);
fOpData = SkSafeRef(src.fOpData);
fBoundingHierarchy = src.fBoundingHierarchy;
fStateTree = src.fStateTree;
+ fContentInfo.set(src.fContentInfo);
SkSafeRef(fBoundingHierarchy);
SkSafeRef(fStateTree);
if (deepCopyInfo) {
+ SkASSERT(deepCopyInfo->initialized);
+
int paintCount = SafeCount(src.fPaints);
if (src.fBitmaps) {
fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count());
}
- if (!deepCopyInfo->initialized) {
- /* The alternative to doing this is to have a clone method on the paint and have it make
- * the deep copy of its internal structures as needed. The holdup to doing that is at
- * this point we would need to pass the SkBitmapHeap so that we don't unnecessarily
- * flatten the pixels in a bitmap shader.
- */
- deepCopyInfo->paintData.setCount(paintCount);
-
- /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is one,
- * use it. If this SkPicturePlayback was created from a stream, fBitmapHeap will be
- * NULL, so create a new one.
- */
- if (fBitmapHeap.get() == NULL) {
- // FIXME: Put this on the stack inside SkPicture::clone. Further, is it possible to
- // do the rest of this initialization in SkPicture::clone as well?
- SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
- deepCopyInfo->controller.setBitmapStorage(heap);
- heap->unref();
- } else {
- deepCopyInfo->controller.setBitmapStorage(fBitmapHeap);
- }
-
- SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());)
- for (int i = 0; i < paintCount; i++) {
- if (needs_deep_copy(src.fPaints->at(i))) {
- deepCopyInfo->paintData[i] = SkFlatData::Create(&deepCopyInfo->controller,
- &src.fPaints->at(i), 0,
- &SkFlattenObjectProc<SkPaint>);
- } else {
- // this is our sentinel, which we use in the unflatten loop
- deepCopyInfo->paintData[i] = NULL;
- }
- }
- SkASSERT(SafeCount(fBitmapHeap.get()) == heapSize);
-
- // needed to create typeface playback
- deepCopyInfo->controller.setupPlaybacks();
- deepCopyInfo->initialized = true;
- }
-
fPaints = SkTRefArray<SkPaint>::Create(paintCount);
SkASSERT(deepCopyInfo->paintData.count() == paintCount);
SkBitmapHeap* bmHeap = deepCopyInfo->controller.getBitmapHeap();
SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
for (int i = 0; i < paintCount; i++) {
if (deepCopyInfo->paintData[i]) {
- deepCopyInfo->paintData[i]->unflatten(&fPaints->writableAt(i),
- &SkUnflattenObjectProc<SkPaint>,
- bmHeap, tfPlayback);
+ deepCopyInfo->paintData[i]->unflatten<SkPaint::FlatteningTraits>(
+ &fPaints->writableAt(i), bmHeap, tfPlayback);
} else {
// needs_deep_copy was false, so just need to assign
fPaints->writableAt(i) = src.fPaints->at(i);
@@ -248,7 +212,7 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
}
fPictureCount = src.fPictureCount;
- fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
+ fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
for (int i = 0; i < fPictureCount; i++) {
if (deepCopyInfo) {
fPictureRefs[i] = src.fPictureRefs[i]->clone();
@@ -261,27 +225,31 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
void SkPicturePlayback::init() {
fBitmaps = NULL;
- fMatrices = NULL;
fPaints = NULL;
fPictureRefs = NULL;
- fRegions = NULL;
fPictureCount = 0;
fOpData = NULL;
fFactoryPlayback = NULL;
fBoundingHierarchy = NULL;
fStateTree = NULL;
+ fCachedActiveOps = NULL;
+ fCurOffset = 0;
+ fUseBBH = true;
+ fStart = 0;
+ fStop = 0;
+ fReplacements = NULL;
}
SkPicturePlayback::~SkPicturePlayback() {
- fOpData->unref();
+ SkSafeUnref(fOpData);
SkSafeUnref(fBitmaps);
- SkSafeUnref(fMatrices);
SkSafeUnref(fPaints);
- SkSafeUnref(fRegions);
SkSafeUnref(fBoundingHierarchy);
SkSafeUnref(fStateTree);
+ SkDELETE(fCachedActiveOps);
+
for (int i = 0; i < fPictureCount; i++) {
fPictureRefs[i]->unref();
}
@@ -291,13 +259,12 @@ SkPicturePlayback::~SkPicturePlayback() {
}
void SkPicturePlayback::dumpSize() const {
- SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] matrices=%d [%d] paints=%d [%d] paths=%d regions=%d\n",
+ SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] paints=%d [%d]\n",
fOpData->size(),
SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap),
- SafeCount(fMatrices), SafeCount(fMatrices) * sizeof(SkMatrix),
- SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint),
- SafeCount(fPathHeap.get()),
- SafeCount(fRegions));
+ SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint));
+ SkDebugf("--- picture size: paths=%d\n",
+ SafeCount(fPathHeap.get()));
}
bool SkPicturePlayback::containsBitmaps() const {
@@ -315,63 +282,58 @@ bool SkPicturePlayback::containsBitmaps() const {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-#define PICT_READER_TAG SkSetFourByteTag('r', 'e', 'a', 'd')
-#define PICT_FACTORY_TAG SkSetFourByteTag('f', 'a', 'c', 't')
-#define PICT_TYPEFACE_TAG SkSetFourByteTag('t', 'p', 'f', 'c')
-#define PICT_PICTURE_TAG SkSetFourByteTag('p', 'c', 't', 'r')
-
-// This tag specifies the size of the ReadBuffer, needed for the following tags
-#define PICT_BUFFER_SIZE_TAG SkSetFourByteTag('a', 'r', 'a', 'y')
-// these are all inside the ARRAYS tag
-#define PICT_BITMAP_BUFFER_TAG SkSetFourByteTag('b', 't', 'm', 'p')
-#define PICT_MATRIX_BUFFER_TAG SkSetFourByteTag('m', 't', 'r', 'x')
-#define PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ')
-#define PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ')
-#define PICT_REGION_BUFFER_TAG SkSetFourByteTag('r', 'g', 'n', ' ')
-
-// Always write this guy last (with no length field afterwards)
-#define PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ')
-
#include "SkStream.h"
-static void writeTagSize(SkOrderedWriteBuffer& buffer, uint32_t tag,
- uint32_t size) {
- buffer.writeUInt(tag);
- buffer.writeUInt(size);
-}
+static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
+ size_t size = 4; // for 'count'
+
+ for (int i = 0; i < count; i++) {
+ const char* name = SkFlattenable::FactoryToName(array[i]);
+ if (NULL == name || 0 == *name) {
+ size += SkWStream::SizeOfPackedUInt(0);
+ } else {
+ size_t len = strlen(name);
+ size += SkWStream::SizeOfPackedUInt(len);
+ size += len;
+ }
+ }
-static void writeTagSize(SkWStream* stream, uint32_t tag,
- uint32_t size) {
- stream->write32(tag);
- stream->write32(size);
+ return size;
}
-static void writeFactories(SkWStream* stream, const SkFactorySet& rec) {
+void SkPicturePlayback::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
int count = rec.count();
- writeTagSize(stream, PICT_FACTORY_TAG, count);
-
SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
rec.copyToArray(array);
+ size_t size = compute_chunk_size(array, count);
+
+ // TODO: write_tag_size should really take a size_t
+ SkPicture::WriteTagSize(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
+ SkDEBUGCODE(size_t start = stream->bytesWritten());
+ stream->write32(count);
+
for (int i = 0; i < count; i++) {
const char* name = SkFlattenable::FactoryToName(array[i]);
// SkDebugf("---- write factories [%d] %p <%s>\n", i, array[i], name);
if (NULL == name || 0 == *name) {
stream->writePackedUInt(0);
} else {
- uint32_t len = strlen(name);
+ size_t len = strlen(name);
stream->writePackedUInt(len);
stream->write(name, len);
}
}
+
+ SkASSERT(size == (stream->bytesWritten() - start));
}
-static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
+void SkPicturePlayback::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
int count = rec.count();
- writeTagSize(stream, PICT_TYPEFACE_TAG, count);
+ SkPicture::WriteTagSize(stream, SK_PICT_TYPEFACE_TAG, count);
SkAutoSTMalloc<16, SkTypeface*> storage(count);
SkTypeface** array = (SkTypeface**)storage.get();
@@ -382,51 +344,36 @@ static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
}
}
-void SkPicturePlayback::flattenToBuffer(SkOrderedWriteBuffer& buffer) const {
+void SkPicturePlayback::flattenToBuffer(SkWriteBuffer& buffer) const {
int i, n;
if ((n = SafeCount(fBitmaps)) > 0) {
- writeTagSize(buffer, PICT_BITMAP_BUFFER_TAG, n);
+ SkPicture::WriteTagSize(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
for (i = 0; i < n; i++) {
buffer.writeBitmap((*fBitmaps)[i]);
}
}
- if ((n = SafeCount(fMatrices)) > 0) {
- writeTagSize(buffer, PICT_MATRIX_BUFFER_TAG, n);
- for (i = 0; i < n; i++) {
- buffer.writeMatrix((*fMatrices)[i]);
- }
-
- }
-
if ((n = SafeCount(fPaints)) > 0) {
- writeTagSize(buffer, PICT_PAINT_BUFFER_TAG, n);
+ SkPicture::WriteTagSize(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
for (i = 0; i < n; i++) {
buffer.writePaint((*fPaints)[i]);
}
}
if ((n = SafeCount(fPathHeap.get())) > 0) {
- writeTagSize(buffer, PICT_PATH_BUFFER_TAG, n);
+ SkPicture::WriteTagSize(buffer, SK_PICT_PATH_BUFFER_TAG, n);
fPathHeap->flatten(buffer);
}
-
- if ((n = SafeCount(fRegions)) > 0) {
- writeTagSize(buffer, PICT_REGION_BUFFER_TAG, n);
- for (i = 0; i < n; i++) {
- buffer.writeRegion((*fRegions)[i]);
- }
- }
}
void SkPicturePlayback::serialize(SkWStream* stream,
SkPicture::EncodeBitmap encoder) const {
- writeTagSize(stream, PICT_READER_TAG, fOpData->size());
+ SkPicture::WriteTagSize(stream, SK_PICT_READER_TAG, fOpData->size());
stream->write(fOpData->bytes(), fOpData->size());
if (fPictureCount > 0) {
- writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount);
+ SkPicture::WriteTagSize(stream, SK_PICT_PICTURE_TAG, fPictureCount);
for (int i = 0; i < fPictureCount; i++) {
fPictureRefs[i]->serialize(stream, encoder);
}
@@ -438,32 +385,46 @@ void SkPicturePlayback::serialize(SkWStream* stream,
SkRefCntSet typefaceSet;
SkFactorySet factSet;
- SkOrderedWriteBuffer buffer(1024);
-
- buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
+ SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
buffer.setTypefaceRecorder(&typefaceSet);
buffer.setFactoryRecorder(&factSet);
buffer.setBitmapEncoder(encoder);
this->flattenToBuffer(buffer);
- // We have to write these to sets into the stream *before* we write
+ // We have to write these two sets into the stream *before* we write
// the buffer, since parsing that buffer will require that we already
// have these sets available to use.
- writeFactories(stream, factSet);
- writeTypefaces(stream, typefaceSet);
+ WriteFactories(stream, factSet);
+ WriteTypefaces(stream, typefaceSet);
- writeTagSize(stream, PICT_BUFFER_SIZE_TAG, buffer.size());
+ SkPicture::WriteTagSize(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
buffer.writeToStream(stream);
}
- stream->write32(PICT_EOF_TAG);
+ stream->write32(SK_PICT_EOF_TAG);
+}
+
+void SkPicturePlayback::flatten(SkWriteBuffer& buffer) const {
+ SkPicture::WriteTagSize(buffer, SK_PICT_READER_TAG, fOpData->size());
+ buffer.writeByteArray(fOpData->bytes(), fOpData->size());
+
+ if (fPictureCount > 0) {
+ SkPicture::WriteTagSize(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
+ for (int i = 0; i < fPictureCount; i++) {
+ fPictureRefs[i]->flatten(buffer);
+ }
+ }
+
+ // Write this picture playback's data into a writebuffer
+ this->flattenToBuffer(buffer);
+ buffer.write32(SK_PICT_EOF_TAG);
}
///////////////////////////////////////////////////////////////////////////////
/**
- * Return the corresponding SkFlattenableReadBuffer flags, given a set of
+ * Return the corresponding SkReadBuffer flags, given a set of
* SkPictInfo flags.
*/
static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
@@ -471,9 +432,9 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
uint32_t fSrc;
uint32_t fDst;
} gSD[] = {
- { SkPictInfo::kCrossProcess_Flag, SkFlattenableReadBuffer::kCrossProcess_Flag },
- { SkPictInfo::kScalarIsFloat_Flag, SkFlattenableReadBuffer::kScalarIsFloat_Flag },
- { SkPictInfo::kPtrIs64Bit_Flag, SkFlattenableReadBuffer::kPtrIs64Bit_Flag },
+ { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
+ { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
+ { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
};
uint32_t rbMask = 0;
@@ -485,8 +446,10 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
return rbMask;
}
-bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info, uint32_t tag,
- size_t size, SkPicture::InstallPixelRefProc proc) {
+bool SkPicturePlayback::parseStreamTag(SkStream* stream,
+ uint32_t tag,
+ uint32_t size,
+ SkPicture::InstallPixelRefProc proc) {
/*
* By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
* its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
@@ -499,7 +462,7 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
SkDEBUGCODE(bool haveBuffer = false;)
switch (tag) {
- case PICT_READER_TAG: {
+ case SK_PICT_READER_TAG: {
SkAutoMalloc storage(size);
if (stream->read(storage.get(), size) != size) {
return false;
@@ -507,8 +470,19 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
SkASSERT(NULL == fOpData);
fOpData = SkData::NewFromMalloc(storage.detach(), size);
} break;
- case PICT_FACTORY_TAG: {
+ case SK_PICT_FACTORY_TAG: {
SkASSERT(!haveBuffer);
+ // Remove this code when v21 and below are no longer supported. At the
+ // same time add a new 'count' variable and use it rather then reusing 'size'.
+#ifndef DISABLE_V21_COMPATIBILITY_CODE
+ if (fInfo.fVersion >= 22) {
+ // in v22 this tag's size represents the size of the chunk in bytes
+ // and the number of factory strings is written out separately
+#endif
+ size = stream->readU32();
+#ifndef DISABLE_V21_COMPATIBILITY_CODE
+ }
+#endif
fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
for (size_t i = 0; i < size; i++) {
SkString str;
@@ -520,10 +494,11 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
}
} break;
- case PICT_TYPEFACE_TAG: {
+ case SK_PICT_TYPEFACE_TAG: {
SkASSERT(!haveBuffer);
- fTFPlayback.setCount(size);
- for (size_t i = 0; i < size; i++) {
+ const int count = SkToInt(size);
+ fTFPlayback.setCount(count);
+ for (int i = 0; i < count; i++) {
SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
if (!tf.get()) { // failed to deserialize
// fTFPlayback asserts it never has a null, so we plop in
@@ -533,9 +508,9 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
fTFPlayback.set(i, tf);
}
} break;
- case PICT_PICTURE_TAG: {
+ case SK_PICT_PICTURE_TAG: {
fPictureCount = size;
- fPictureRefs = SkNEW_ARRAY(SkPicture*, fPictureCount);
+ fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
bool success = true;
int i = 0;
for ( ; i < fPictureCount; i++) {
@@ -556,14 +531,15 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
return false;
}
} break;
- case PICT_BUFFER_SIZE_TAG: {
+ case SK_PICT_BUFFER_SIZE_TAG: {
SkAutoMalloc storage(size);
if (stream->read(storage.get(), size) != size) {
return false;
}
- SkOrderedReadBuffer buffer(storage.get(), size);
- buffer.setFlags(pictInfoFlagsToReadBufferFlags(info.fFlags));
+ SkReadBuffer buffer(storage.get(), size);
+ buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
+ buffer.setVersion(fInfo.fVersion);
fFactoryPlayback->setupBuffer(buffer);
fTFPlayback.setupBuffer(buffer);
@@ -582,38 +558,63 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
return true; // success
}
-bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
- uint32_t tag, size_t size) {
+bool SkPicturePlayback::parseBufferTag(SkReadBuffer& buffer,
+ uint32_t tag, uint32_t size) {
switch (tag) {
- case PICT_BITMAP_BUFFER_TAG: {
+ case SK_PICT_BITMAP_BUFFER_TAG: {
+ const int count = SkToInt(size);
fBitmaps = SkTRefArray<SkBitmap>::Create(size);
- for (size_t i = 0; i < size; ++i) {
+ for (int i = 0; i < count; ++i) {
SkBitmap* bm = &fBitmaps->writableAt(i);
buffer.readBitmap(bm);
bm->setImmutable();
}
} break;
- case PICT_MATRIX_BUFFER_TAG:
- fMatrices = SkTRefArray<SkMatrix>::Create(size);
- for (size_t i = 0; i < size; ++i) {
- buffer.readMatrix(&fMatrices->writableAt(i));
- }
- break;
- case PICT_PAINT_BUFFER_TAG: {
+ case SK_PICT_PAINT_BUFFER_TAG: {
+ const int count = SkToInt(size);
fPaints = SkTRefArray<SkPaint>::Create(size);
- for (size_t i = 0; i < size; ++i) {
+ for (int i = 0; i < count; ++i) {
buffer.readPaint(&fPaints->writableAt(i));
}
} break;
- case PICT_PATH_BUFFER_TAG:
+ case SK_PICT_PATH_BUFFER_TAG:
if (size > 0) {
fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
}
break;
- case PICT_REGION_BUFFER_TAG: {
- fRegions = SkTRefArray<SkRegion>::Create(size);
- for (size_t i = 0; i < size; ++i) {
- buffer.readRegion(&fRegions->writableAt(i));
+ case SK_PICT_READER_TAG: {
+ SkAutoMalloc storage(size);
+ if (!buffer.readByteArray(storage.get(), size) ||
+ !buffer.validate(NULL == fOpData)) {
+ return false;
+ }
+ SkASSERT(NULL == fOpData);
+ fOpData = SkData::NewFromMalloc(storage.detach(), size);
+ } break;
+ case SK_PICT_PICTURE_TAG: {
+ if (!buffer.validate((0 == fPictureCount) && (NULL == fPictureRefs))) {
+ return false;
+ }
+ fPictureCount = size;
+ fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
+ bool success = true;
+ int i = 0;
+ for ( ; i < fPictureCount; i++) {
+ fPictureRefs[i] = SkPicture::CreateFromBuffer(buffer);
+ if (NULL == fPictureRefs[i]) {
+ success = false;
+ break;
+ }
+ }
+ if (!success) {
+ // Delete all of the pictures that were already created (up to but excluding i):
+ for (int j = 0; j < i; j++) {
+ fPictureRefs[j]->unref();
+ }
+ // Delete the array
+ SkDELETE_ARRAY(fPictureRefs);
+ fPictureCount = 0;
+ return false;
}
} break;
default:
@@ -626,24 +627,50 @@ bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer,
SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkStream* stream,
const SkPictInfo& info,
SkPicture::InstallPixelRefProc proc) {
- SkAutoTDelete<SkPicturePlayback> playback(SkNEW(SkPicturePlayback));
+ SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (info)));
- if (!playback->parseStream(stream, info, proc)) {
+ if (!playback->parseStream(stream, proc)) {
return NULL;
}
return playback.detach();
}
-bool SkPicturePlayback::parseStream(SkStream* stream, const SkPictInfo& info,
+SkPicturePlayback* SkPicturePlayback::CreateFromBuffer(SkReadBuffer& buffer,
+ const SkPictInfo& info) {
+ SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (info)));
+ buffer.setVersion(info.fVersion);
+
+ if (!playback->parseBuffer(buffer)) {
+ return NULL;
+ }
+ return playback.detach();
+}
+
+bool SkPicturePlayback::parseStream(SkStream* stream,
SkPicture::InstallPixelRefProc proc) {
for (;;) {
uint32_t tag = stream->readU32();
- if (PICT_EOF_TAG == tag) {
+ if (SK_PICT_EOF_TAG == tag) {
break;
}
uint32_t size = stream->readU32();
- if (!this->parseStreamTag(stream, info, tag, size, proc)) {
+ if (!this->parseStreamTag(stream, tag, size, proc)) {
+ return false; // we're invalid
+ }
+ }
+ return true;
+}
+
+bool SkPicturePlayback::parseBuffer(SkReadBuffer& buffer) {
+ for (;;) {
+ uint32_t tag = buffer.readUInt();
+ if (SK_PICT_EOF_TAG == tag) {
+ break;
+ }
+
+ uint32_t size = buffer.readUInt();
+ if (!this->parseBufferTag(buffer, tag, size)) {
return false; // we're invalid
}
}
@@ -702,13 +729,81 @@ static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) {
return (DrawType) op;
}
+uint32_t SkPicturePlayback::CachedOperationList::offset(int index) const {
+ SkASSERT(index < fOps.count());
+ return ((SkPictureStateTree::Draw*)fOps[index])->fOffset;
+}
+
+const SkMatrix& SkPicturePlayback::CachedOperationList::matrix(int index) const {
+ SkASSERT(index < fOps.count());
+ return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix;
+}
+
+const SkPicture::OperationList& SkPicturePlayback::getActiveOps(const SkIRect& query) {
+ if (NULL == fStateTree || NULL == fBoundingHierarchy) {
+ return SkPicture::OperationList::InvalidList();
+ }
+
+ if (NULL == fCachedActiveOps) {
+ fCachedActiveOps = SkNEW(CachedOperationList);
+ }
+
+ if (query == fCachedActiveOps->fCacheQueryRect) {
+ return *fCachedActiveOps;
+ }
+
+ fCachedActiveOps->fOps.rewind();
+
+ fBoundingHierarchy->search(query, &(fCachedActiveOps->fOps));
+ if (0 != fCachedActiveOps->fOps.count()) {
+ SkTQSort<SkPictureStateTree::Draw>(
+ reinterpret_cast<SkPictureStateTree::Draw**>(fCachedActiveOps->fOps.begin()),
+ reinterpret_cast<SkPictureStateTree::Draw**>(fCachedActiveOps->fOps.end()-1));
+ }
+
+ fCachedActiveOps->fCacheQueryRect = query;
+ return *fCachedActiveOps;
+}
+
+class SkAutoResetOpID {
+public:
+ SkAutoResetOpID(SkPicturePlayback* playback) : fPlayback(playback) { }
+ ~SkAutoResetOpID() {
+ if (NULL != fPlayback) {
+ fPlayback->resetOpID();
+ }
+ }
+
+private:
+ SkPicturePlayback* fPlayback;
+};
+
+// TODO: Replace with hash or pass in "lastLookedUp" hint
+SkPicturePlayback::PlaybackReplacements::ReplacementInfo*
+SkPicturePlayback::PlaybackReplacements::lookupByStart(size_t start) {
+ SkDEBUGCODE(this->validate());
+ for (int i = 0; i < fReplacements.count(); ++i) {
+ if (start == fReplacements[i].fStart) {
+ return &fReplacements[i];
+ } else if (start < fReplacements[i].fStart) {
+ return NULL; // the ranges are monotonically increasing and non-overlapping
+ }
+ }
+
+ return NULL;
+}
+
void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
+ SkAutoResetOpID aroi(this);
+ SkASSERT(0 == fCurOffset);
+
#ifdef ENABLE_TIME_DRAW
SkAutoTime at("SkPicture::draw", 50);
#endif
#ifdef SPEW_CLIP_SKIPPING
- SkipClipRec skipRect, skipRRect, skipRegion, skipPath;
+ SkipClipRec skipRect, skipRRect, skipRegion, skipPath, skipCull;
+ int opCount = 0;
#endif
#ifdef SK_BUILD_FOR_ANDROID
@@ -721,29 +816,44 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
SkReader32 reader(fOpData->bytes(), fOpData->size());
TextContainer text;
- SkTDArray<void*> results;
-
- if (NULL != fStateTree && NULL != fBoundingHierarchy) {
- SkRect clipBounds;
- if (canvas.getClipBounds(&clipBounds)) {
- SkIRect query;
- clipBounds.roundOut(&query);
- fBoundingHierarchy->search(query, &results);
- if (results.count() == 0) {
- return;
+ const SkTDArray<void*>* activeOps = NULL;
+
+ // When draw limits are enabled (i.e., 0 != fStart || 0 != fStop) the state
+ // tree isn't used to pick and choose the draw operations
+ if (0 == fStart && 0 == fStop) {
+ if (fUseBBH && NULL != fStateTree && NULL != fBoundingHierarchy) {
+ SkRect clipBounds;
+ if (canvas.getClipBounds(&clipBounds)) {
+ SkIRect query;
+ clipBounds.roundOut(&query);
+
+ const SkPicture::OperationList& activeOpsList = this->getActiveOps(query);
+ if (activeOpsList.valid()) {
+ if (0 == activeOpsList.numOps()) {
+ return; // nothing to draw
+ }
+
+ // Since the opList is valid we know it is our derived class
+ activeOps = &((const CachedOperationList&)activeOpsList).fOps;
+ }
}
- SkTQSort<SkPictureStateTree::Draw>(
- reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
- reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
}
}
- SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
+ SkPictureStateTree::Iterator it = (NULL == activeOps) ?
SkPictureStateTree::Iterator() :
- fStateTree->getIterator(results, &canvas);
+ fStateTree->getIterator(*activeOps, &canvas);
+
+ if (0 != fStart || 0 != fStop) {
+ reader.setOffset(fStart);
+ uint32_t size;
+ SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
+ SkASSERT(SAVE_LAYER == op);
+ reader.setOffset(fStart+size);
+ }
if (it.isValid()) {
- uint32_t skipTo = it.draw();
+ uint32_t skipTo = it.nextDraw();
if (kDrawComplete == skipTo) {
return;
}
@@ -752,7 +862,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
// Record this, so we can concat w/ it if we encounter a setMatrix()
SkMatrix initialMatrix = canvas.getTotalMatrix();
- int originalSaveCount = canvas.getSaveCount();
+
+ SkAutoCanvasRestore acr(&canvas, false);
#ifdef SK_BUILD_FOR_ANDROID
fAbortCurrentPlayback = false;
@@ -764,7 +875,6 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
while (!reader.eof()) {
if (callback && callback->abortDrawing()) {
- canvas.restoreToCount(originalSaveCount);
return;
}
#ifdef SK_BUILD_FOR_ANDROID
@@ -772,19 +882,92 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
return;
}
#endif
+ if (0 != fStart || 0 != fStop) {
+ size_t offset = reader.offset() ;
+ if (offset >= fStop) {
+ uint32_t size;
+ SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
+ SkASSERT(RESTORE == op);
+ return;
+ }
+ }
- size_t curOffset = reader.offset();
+ if (NULL != fReplacements) {
+ // Potentially replace a block of operations with a single drawBitmap call
+ SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp =
+ fReplacements->lookupByStart(reader.offset());
+ if (NULL != temp) {
+ SkASSERT(NULL != temp->fBM);
+ SkASSERT(NULL != temp->fPaint);
+ canvas.save();
+ canvas.setMatrix(initialMatrix);
+ canvas.drawBitmap(*temp->fBM, temp->fPos.fX, temp->fPos.fY, temp->fPaint);
+ canvas.restore();
+
+ if (it.isValid()) {
+ // This save is needed since the BBH will automatically issue
+ // a restore to balanced the saveLayer we're skipping
+ canvas.save();
+
+ // At this point we know that the PictureStateTree was aiming
+ // for some draw op within temp's saveLayer (although potentially
+ // in a separate saveLayer nested inside it).
+ // We need to skip all the operations inside temp's range
+ // along with all the associated state changes but update
+ // the state tree to the first operation outside temp's range.
+
+ uint32_t skipTo;
+ do {
+ skipTo = it.nextDraw();
+ if (kDrawComplete == skipTo) {
+ break;
+ }
+
+ if (skipTo <= temp->fStop) {
+ reader.setOffset(skipTo);
+ uint32_t size;
+ DrawType op = read_op_and_size(&reader, &size);
+ // Since we are relying on the normal SkPictureStateTree
+ // playback we need to convert any nested saveLayer calls
+ // it may issue into saves (so that all its internal
+ // restores will be balanced).
+ if (SAVE_LAYER == op) {
+ canvas.save();
+ }
+ }
+ } while (skipTo <= temp->fStop);
+
+ if (kDrawComplete == skipTo) {
+ break;
+ }
+
+ reader.setOffset(skipTo);
+ } else {
+ reader.setOffset(temp->fStop);
+ uint32_t size;
+ SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
+ SkASSERT(RESTORE == op);
+ }
+ continue;
+ }
+ }
+
+#ifdef SPEW_CLIP_SKIPPING
+ opCount++;
+#endif
+
+ fCurOffset = reader.offset();
uint32_t size;
DrawType op = read_op_and_size(&reader, &size);
size_t skipTo = 0;
if (NOOP == op) {
// NOOPs are to be ignored - do not propagate them any further
- skipTo = curOffset + size;
+ skipTo = fCurOffset + size;
#ifdef SK_DEVELOPER
} else {
opIndex++;
if (this->preDraw(opIndex, op)) {
- skipTo = curOffset + size;
+ skipTo = fCurOffset + size;
}
#endif
}
@@ -795,7 +978,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
// iterator until at or after skipTo
uint32_t adjustedSkipTo;
do {
- adjustedSkipTo = it.draw();
+ adjustedSkipTo = it.nextDraw();
} while (adjustedSkipTo < skipTo);
skipTo = adjustedSkipTo;
}
@@ -815,7 +998,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
size_t offsetToRestore = reader.readInt();
SkASSERT(!offsetToRestore || \
offsetToRestore >= reader.offset());
- if (!canvas.clipPath(path, regionOp, doAA) && offsetToRestore) {
+ canvas.clipPath(path, regionOp, doAA);
+ if (canvas.isClipEmpty() && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipPath.recordSkip(offsetToRestore - reader.offset());
#endif
@@ -823,13 +1007,15 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
}
} break;
case CLIP_REGION: {
- const SkRegion& region = getRegion(reader);
+ SkRegion region;
+ this->getRegion(reader, &region);
uint32_t packed = reader.readInt();
SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
size_t offsetToRestore = reader.readInt();
SkASSERT(!offsetToRestore || \
offsetToRestore >= reader.offset());
- if (!canvas.clipRegion(region, regionOp) && offsetToRestore) {
+ canvas.clipRegion(region, regionOp);
+ if (canvas.isClipEmpty() && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipRegion.recordSkip(offsetToRestore - reader.offset());
#endif
@@ -844,7 +1030,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
size_t offsetToRestore = reader.readInt();
SkASSERT(!offsetToRestore || \
offsetToRestore >= reader.offset());
- if (!canvas.clipRect(rect, regionOp, doAA) && offsetToRestore) {
+ canvas.clipRect(rect, regionOp, doAA);
+ if (canvas.isClipEmpty() && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipRect.recordSkip(offsetToRestore - reader.offset());
#endif
@@ -858,27 +1045,45 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
bool doAA = ClipParams_unpackDoAA(packed);
size_t offsetToRestore = reader.readInt();
- SkASSERT(!offsetToRestore || \
- offsetToRestore >= reader.offset());
- if (!canvas.clipRRect(rrect, regionOp, doAA) && offsetToRestore) {
+ SkASSERT(!offsetToRestore || offsetToRestore >= reader.offset());
+ canvas.clipRRect(rrect, regionOp, doAA);
+ if (canvas.isClipEmpty() && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipRRect.recordSkip(offsetToRestore - reader.offset());
#endif
reader.setOffset(offsetToRestore);
}
} break;
- case CONCAT:
- canvas.concat(*getMatrix(reader));
+ case PUSH_CULL: {
+ const SkRect& cullRect = reader.skipT<SkRect>();
+ size_t offsetToRestore = reader.readInt();
+ if (offsetToRestore && canvas.quickReject(cullRect)) {
+#ifdef SPEW_CLIP_SKIPPING
+ skipCull.recordSkip(offsetToRestore - reader.offset());
+#endif
+ reader.setOffset(offsetToRestore);
+ } else {
+ canvas.pushCull(cullRect);
+ }
+ } break;
+ case POP_CULL:
+ canvas.popCull();
+ break;
+ case CONCAT: {
+ SkMatrix matrix;
+ this->getMatrix(reader, &matrix);
+ canvas.concat(matrix);
break;
+ }
case DRAW_BITMAP: {
- const SkPaint* paint = getPaint(reader);
- const SkBitmap& bitmap = getBitmap(reader);
+ const SkPaint* paint = this->getPaint(reader);
+ const SkBitmap& bitmap = this->getBitmap(reader);
const SkPoint& loc = reader.skipT<SkPoint>();
canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
} break;
case DRAW_BITMAP_RECT_TO_RECT: {
- const SkPaint* paint = getPaint(reader);
- const SkBitmap& bitmap = getBitmap(reader);
+ const SkPaint* paint = this->getPaint(reader);
+ const SkBitmap& bitmap = this->getBitmap(reader);
const SkRect* src = this->getRectPtr(reader); // may be null
const SkRect& dst = reader.skipT<SkRect>(); // required
SkCanvas::DrawBitmapRectFlags flags;
@@ -886,14 +1091,15 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
canvas.drawBitmapRectToRect(bitmap, src, dst, paint, flags);
} break;
case DRAW_BITMAP_MATRIX: {
- const SkPaint* paint = getPaint(reader);
- const SkBitmap& bitmap = getBitmap(reader);
- const SkMatrix* matrix = getMatrix(reader);
- canvas.drawBitmapMatrix(bitmap, *matrix, paint);
+ const SkPaint* paint = this->getPaint(reader);
+ const SkBitmap& bitmap = this->getBitmap(reader);
+ SkMatrix matrix;
+ this->getMatrix(reader, &matrix);
+ canvas.drawBitmapMatrix(bitmap, matrix, paint);
} break;
case DRAW_BITMAP_NINE: {
- const SkPaint* paint = getPaint(reader);
- const SkBitmap& bitmap = getBitmap(reader);
+ const SkPaint* paint = this->getPaint(reader);
+ const SkBitmap& bitmap = this->getBitmap(reader);
const SkIRect& src = reader.skipT<SkIRect>();
const SkRect& dst = reader.skipT<SkRect>();
canvas.drawBitmapNine(bitmap, src, dst, paint);
@@ -906,6 +1112,13 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
canvas.drawData(reader.skip(length), length);
// skip handles padding the read out to a multiple of 4
} break;
+ case DRAW_DRRECT: {
+ const SkPaint& paint = *this->getPaint(reader);
+ SkRRect outer, inner;
+ reader.readRRect(&outer);
+ reader.readRRect(&inner);
+ canvas.drawDRRect(outer, inner, paint);
+ } break;
case BEGIN_COMMENT_GROUP: {
const char* desc = reader.readString();
canvas.beginCommentGroup(desc);
@@ -919,35 +1132,35 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
canvas.endCommentGroup();
} break;
case DRAW_OVAL: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
canvas.drawOval(reader.skipT<SkRect>(), paint);
} break;
case DRAW_PAINT:
- canvas.drawPaint(*getPaint(reader));
+ canvas.drawPaint(*this->getPaint(reader));
break;
case DRAW_PATH: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
canvas.drawPath(getPath(reader), paint);
} break;
case DRAW_PICTURE:
- canvas.drawPicture(getPicture(reader));
+ canvas.drawPicture(this->getPicture(reader));
break;
case DRAW_POINTS: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
SkCanvas::PointMode mode = (SkCanvas::PointMode)reader.readInt();
size_t count = reader.readInt();
const SkPoint* pts = (const SkPoint*)reader.skip(sizeof(SkPoint) * count);
canvas.drawPoints(mode, count, pts, paint);
} break;
case DRAW_POS_TEXT: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
getText(reader, &text);
size_t points = reader.readInt();
const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
canvas.drawPosText(text.text(), text.length(), pos, paint);
} break;
case DRAW_POS_TEXT_TOP_BOTTOM: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
getText(reader, &text);
size_t points = reader.readInt();
const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
@@ -958,7 +1171,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
}
} break;
case DRAW_POS_TEXT_H: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
getText(reader, &text);
size_t xCount = reader.readInt();
const SkScalar constY = reader.readScalar();
@@ -967,7 +1180,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
paint);
} break;
case DRAW_POS_TEXT_H_TOP_BOTTOM: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
getText(reader, &text);
size_t xCount = reader.readInt();
const SkScalar* xpos = (const SkScalar*)reader.skip((3 + xCount) * sizeof(SkScalar));
@@ -980,32 +1193,32 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
}
} break;
case DRAW_RECT: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
canvas.drawRect(reader.skipT<SkRect>(), paint);
} break;
case DRAW_RRECT: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
SkRRect rrect;
reader.readRRect(&rrect);
canvas.drawRRect(rrect, paint);
} break;
case DRAW_SPRITE: {
- const SkPaint* paint = getPaint(reader);
- const SkBitmap& bitmap = getBitmap(reader);
+ const SkPaint* paint = this->getPaint(reader);
+ const SkBitmap& bitmap = this->getBitmap(reader);
int left = reader.readInt();
int top = reader.readInt();
canvas.drawSprite(bitmap, left, top, paint);
} break;
case DRAW_TEXT: {
- const SkPaint& paint = *getPaint(reader);
- getText(reader, &text);
+ const SkPaint& paint = *this->getPaint(reader);
+ this->getText(reader, &text);
SkScalar x = reader.readScalar();
SkScalar y = reader.readScalar();
canvas.drawText(text.text(), text.length(), x, y, paint);
} break;
case DRAW_TEXT_TOP_BOTTOM: {
- const SkPaint& paint = *getPaint(reader);
- getText(reader, &text);
+ const SkPaint& paint = *this->getPaint(reader);
+ this->getText(reader, &text);
const SkScalar* ptr = (const SkScalar*)reader.skip(4 * sizeof(SkScalar));
// ptr[0] == x
// ptr[1] == y
@@ -1017,15 +1230,16 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
}
} break;
case DRAW_TEXT_ON_PATH: {
- const SkPaint& paint = *getPaint(reader);
+ const SkPaint& paint = *this->getPaint(reader);
getText(reader, &text);
- const SkPath& path = getPath(reader);
- const SkMatrix* matrix = getMatrix(reader);
- canvas.drawTextOnPath(text.text(), text.length(), path,
- matrix, paint);
+ const SkPath& path = this->getPath(reader);
+ SkMatrix matrix;
+ this->getMatrix(reader, &matrix);
+ canvas.drawTextOnPath(text.text(), text.length(), path, &matrix, paint);
} break;
case DRAW_VERTICES: {
- const SkPaint& paint = *getPaint(reader);
+ SkAutoTUnref<SkXfermode> xfer;
+ const SkPaint& paint = *this->getPaint(reader);
DrawVertexFlags flags = (DrawVertexFlags)reader.readInt();
SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader.readInt();
int vCount = reader.readInt();
@@ -1048,7 +1262,14 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
indices = (const uint16_t*)reader.skip(
iCount * sizeof(uint16_t));
}
- canvas.drawVertices(vmode, vCount, verts, texs, colors, NULL,
+ if (flags & DRAW_VERTICES_HAS_XFER) {
+ int mode = reader.readInt();
+ if (mode < 0 || mode > SkXfermode::kLastMode) {
+ mode = SkXfermode::kModulate_Mode;
+ }
+ xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
+ }
+ canvas.drawVertices(vmode, vCount, verts, texs, colors, xfer,
indices, iCount, paint);
} break;
case RESTORE:
@@ -1061,8 +1282,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
canvas.save((SkCanvas::SaveFlags) reader.readInt());
break;
case SAVE_LAYER: {
- const SkRect* boundsPtr = getRectPtr(reader);
- const SkPaint* paint = getPaint(reader);
+ const SkRect* boundsPtr = this->getRectPtr(reader);
+ const SkPaint* paint = this->getPaint(reader);
canvas.saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader.readInt());
} break;
case SCALE: {
@@ -1072,7 +1293,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
} break;
case SET_MATRIX: {
SkMatrix matrix;
- matrix.setConcat(initialMatrix, *getMatrix(reader));
+ this->getMatrix(reader, &matrix);
+ matrix.postConcat(initialMatrix);
canvas.setMatrix(matrix);
} break;
case SKEW: {
@@ -1094,7 +1316,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
#endif
if (it.isValid()) {
- uint32_t skipTo = it.draw();
+ uint32_t skipTo = it.nextDraw();
if (kDrawComplete == skipTo) {
break;
}
@@ -1104,15 +1326,65 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
#ifdef SPEW_CLIP_SKIPPING
{
- size_t size = skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize;
- SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d\n",
+ size_t size = skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize +
+ skipCull.fSize;
+ SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d cull:%d\n",
size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount,
- skipPath.fCount, skipRegion.fCount);
+ skipPath.fCount, skipRegion.fCount, skipCull.fCount);
+ SkDebugf("--- Total ops: %d\n", opCount);
}
#endif
// this->dumpSize();
}
+
+#if SK_SUPPORT_GPU
+bool SkPicturePlayback::suitableForGpuRasterization(GrContext* context, const char **reason,
+ int sampleCount) const {
+ // TODO: the heuristic used here needs to be refined
+ static const int kNumPaintWithPathEffectUsesTol = 1;
+ static const int kNumAAConcavePaths = 5;
+
+ SkASSERT(fContentInfo.numAAHairlineConcavePaths() <= fContentInfo.numAAConcavePaths());
+
+ int numNonDashedPathEffects = fContentInfo.numPaintWithPathEffectUses() -
+ fContentInfo.numFastPathDashEffects();
+
+ bool suitableForDash = (0 == fContentInfo.numPaintWithPathEffectUses()) ||
+ (numNonDashedPathEffects < kNumPaintWithPathEffectUsesTol
+ && 0 == sampleCount);
+
+ bool ret = suitableForDash &&
+ (fContentInfo.numAAConcavePaths() - fContentInfo.numAAHairlineConcavePaths())
+ < kNumAAConcavePaths;
+ if (!ret && NULL != reason) {
+ if (!suitableForDash) {
+ if (0 != sampleCount) {
+ *reason = "Can't use multisample on dash effect.";
+ } else {
+ *reason = "Too many non dashed path effects.";
+ }
+ } else if ((fContentInfo.numAAConcavePaths() - fContentInfo.numAAHairlineConcavePaths())
+ >= kNumAAConcavePaths)
+ *reason = "Too many anti-aliased concave paths.";
+ else
+ *reason = "Unknown reason for GPU unsuitability.";
+ }
+ return ret;
+}
+
+bool SkPicturePlayback::suitableForGpuRasterization(GrContext* context, const char **reason,
+ GrPixelConfig config, SkScalar dpi) const {
+
+ if (context != NULL) {
+ return this->suitableForGpuRasterization(context, reason,
+ context->getRecommendedSampleCount(config, dpi));
+ } else {
+ return this->suitableForGpuRasterization(NULL, reason);
+ }
+}
+
+#endif
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG_SIZE
@@ -1155,16 +1427,6 @@ int SkPicturePlayback::paths(size_t* size) {
*size = result;
return fPathCount;
}
-
-int SkPicturePlayback::regions(size_t* size) {
- size_t result = 0;
- for (int index = 0; index < fRegionCount; index++) {
- // const SkRegion& region = fRegions[index];
- result += sizeof(SkRegion); // region->size();
- }
- *size = result;
- return fRegionCount;
-}
#endif
#ifdef SK_DEBUG_DUMP
@@ -1217,11 +1479,11 @@ void dumpMatrix(const SkMatrix& matrix) const {
SkScalar perspX = matrix.getPerspX();
if (perspX != defaultMatrix.getPerspX())
bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
- "{kPerspX, %g}, ", SkFractToFloat(perspX));
+ "{kPerspX, %g}, ", perspX);
SkScalar perspY = matrix.getPerspY();
if (perspY != defaultMatrix.getPerspY())
bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
- "{kPerspY, %g}, ", SkFractToFloat(perspY));
+ "{kPerspY, %g}, ", perspY);
SkDebugf("%s{0}};\n", pBuffer);
}
@@ -1464,7 +1726,6 @@ void SkPicturePlayback::dumpStream() {
DUMP_INT(offsetToRestore);
} break;
case CLIP_REGION: {
- DUMP_PTR(SkRegion, &getRegion());
DUMP_INT(SkRegion::Op);
DUMP_INT(offsetToRestore);
} break;
@@ -1474,7 +1735,6 @@ void SkPicturePlayback::dumpStream() {
DUMP_INT(offsetToRestore);
} break;
case CONCAT:
- DUMP_PTR(SkMatrix, getMatrix());
break;
case DRAW_BITMAP: {
DUMP_PTR(SkPaint, getPaint());
@@ -1536,7 +1796,6 @@ void SkPicturePlayback::dumpStream() {
DUMP_PTR(SkPaint, getPaint());
DUMP_TEXT();
DUMP_PTR(SkPath, &getPath());
- DUMP_PTR(SkMatrix, getMatrix());
} break;
case RESTORE:
break;
@@ -1589,21 +1848,6 @@ void SkPicturePlayback::dump() const {
if (fBitmapCount > 0)
SkDebugf("%s0};\n", pBuffer);
- if (fMatrixCount > 0)
- SkDebugf("// matrices (%d)\n", fMatrixCount);
- for (index = 0; index < fMatrixCount; index++) {
- const SkMatrix& matrix = fMatrices[index];
- dumpMatrix(matrix);
- }
- bufferPtr = pBuffer;
- if (fMatrixCount > 0)
- bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
- "Matrices matrices = {");
- for (index = 0; index < fMatrixCount; index++)
- bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
- "matrix%p, ", &fMatrices[index]);
- if (fMatrixCount > 0)
- SkDebugf("%s0};\n", pBuffer);
if (fPaintCount > 0)
SkDebugf("// paints (%d)\n", fPaintCount);
@@ -1648,20 +1892,6 @@ void SkPicturePlayback::dump() const {
if (fPictureCount > 0)
SkDebugf("%s0};\n", pBuffer);
- for (index = 0; index < fRegionCount; index++) {
- const SkRegion& region = fRegions[index];
- dumpRegion(region);
- }
- bufferPtr = pBuffer;
- if (fRegionCount > 0)
- bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
- "Regions regions = {");
- for (index = 0; index < fRegionCount; index++)
- bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer),
- "region%p, ", &fRegions[index]);
- if (fRegionCount > 0)
- SkDebugf("%s0};\n", pBuffer);
-
const_cast<SkPicturePlayback*>(this)->dumpStream();
}