Index: src/pipe/SkGPipeWrite.cpp |
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp |
index f361e5ed67ecf092b4fd3a10f41f793e4f5cac69..41b02344805ffceb09c1797367a78355024a7e1d 100644 |
--- a/src/pipe/SkGPipeWrite.cpp |
+++ b/src/pipe/SkGPipeWrite.cpp |
@@ -22,6 +22,7 @@ |
#include "SkPatchUtils.h" |
#include "SkPathEffect.h" |
#include "SkPictureFlat.h" |
+#include "SkPtrRecorder.h" |
#include "SkRasterizer.h" |
#include "SkRRect.h" |
#include "SkShader.h" |
@@ -35,7 +36,7 @@ enum { |
kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector) |
}; |
-static bool isCrossProcess(uint32_t flags) { |
+static bool is_cross_process(uint32_t flags) { |
return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag); |
} |
@@ -338,6 +339,10 @@ private: |
} |
} |
+ typedef SkAutoSTMalloc<128, uint8_t> TypefaceBuffer; |
+ size_t getInProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*); |
+ size_t getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*); |
+ |
// Should be called after any calls to an SkFlatDictionary::findAndReplace |
// if a new SkFlatData was added when in cross process mode |
void flattenFactoryNames(); |
@@ -411,7 +416,7 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { |
fBitmapHeap->endAddingOwnersDeferral(added); |
int index = flat->index(); |
if (added) { |
- if (isCrossProcess(fFlags)) { |
+ if (is_cross_process(fFlags)) { |
this->flattenFactoryNames(); |
} |
size_t flatSize = flat->flatSize(); |
@@ -436,10 +441,10 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, |
SkWriter32* writer, uint32_t flags, |
uint32_t width, uint32_t height) |
: SkCanvas(width, height) |
- , fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL) |
+ , fFactorySet(is_cross_process(flags) ? SkNEW(SkNamedFactorySet) : NULL) |
, fWriter(*writer) |
, fFlags(flags) |
- , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, isCrossProcess(flags)) |
+ , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags)) |
, fFlatDictionary(&fFlattenableHeap) |
{ |
fController = controller; |
@@ -938,23 +943,76 @@ void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const |
} |
} |
+size_t SkGPipeCanvas::getInProcessTypefaces(const SkRefCntSet& typefaceSet, |
+ TypefaceBuffer* buffer) { |
+ // When in-process, we simply write out the typeface pointers. |
+ size_t size = typefaceSet.count() * sizeof(SkTypeface*); |
+ buffer->reset(size); |
+ typefaceSet.copyToArray(reinterpret_cast<SkRefCnt**>(buffer->get())); |
+ |
+ return size; |
+} |
+ |
+size_t SkGPipeCanvas::getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, |
+ TypefaceBuffer* buffer) { |
+ // For cross-process we use typeface IDs. |
+ size_t size = typefaceSet.count() * sizeof(uint32_t); |
+ buffer->reset(size); |
+ |
+ uint32_t* idBuffer = reinterpret_cast<uint32_t*>(buffer->get()); |
+ SkRefCntSet::Iter iter(typefaceSet); |
+ int i = 0; |
+ |
+ for (void* setPtr = iter.next(); setPtr; setPtr = iter.next()) { |
+ idBuffer[i++] = this->getTypefaceID(reinterpret_cast<SkTypeface*>(setPtr)); |
+ } |
+ |
+ SkASSERT(i == typefaceSet.count()); |
+ |
+ return size; |
+} |
+ |
void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, |
const SkPaint& paint) { |
NOTIFY_SETUP(this); |
this->writePaint(paint); |
// FIXME: this is inefficient but avoids duplicating the blob serialization logic. |
+ SkRefCntSet typefaceSet; |
SkWriteBuffer blobBuffer; |
+ blobBuffer.setTypefaceRecorder(&typefaceSet); |
blob->flatten(blobBuffer); |
- size_t size = sizeof(uint32_t) + 2 * sizeof(SkScalar) + blobBuffer.bytesWritten(); |
+ // Unlike most draw ops (which only use one paint/typeface), text blobs may reference |
+ // an arbitrary number of typefaces. Since the one-paint-per-op model is not applicable, |
+ // we need to serialize these explicitly. |
+ TypefaceBuffer typefaceBuffer; |
+ size_t typefaceSize = is_cross_process(fFlags) |
+ ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer) |
+ : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer); |
+ |
+ // blob byte count + typeface count + x + y + blob data + an index (cross-process) |
+ // or pointer (in-process) for each typeface |
+ size_t size = 2 * sizeof(uint32_t) |
+ + 2 * sizeof(SkScalar) |
+ + blobBuffer.bytesWritten() |
+ + typefaceSize; |
+ |
if (this->needOpBytes(size)) { |
this->writeOp(kDrawTextBlob_DrawOp); |
+ SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();) |
+ |
fWriter.writeScalar(x); |
fWriter.writeScalar(y); |
+ |
+ fWriter.write32(typefaceSet.count()); |
+ fWriter.write(typefaceBuffer.get(), typefaceSize); |
+ |
fWriter.write32(SkToU32(blobBuffer.bytesWritten())); |
uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten()); |
blobBuffer.writeToMemory(pad); |
+ |
+ SkASSERT(initialOffset + size == fWriter.bytesWritten()); |
} |
} |
@@ -1197,7 +1255,7 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) { |
} |
if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { |
- if (isCrossProcess(fFlags)) { |
+ if (is_cross_process(fFlags)) { |
uint32_t id = this->getTypefaceID(paint.getTypeface()); |
*ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); |
} else if (this->needOpBytes(sizeof(void*))) { |