Chromium Code Reviews| Index: src/pipe/SkGPipeWrite.cpp |
| diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp |
| index f361e5ed67ecf092b4fd3a10f41f793e4f5cac69..c99b6259bd3498d689261be1de1fc3a135f4a3b1 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,9 @@ private: |
| } |
| } |
| + size_t prepareInProcessTypefaceBuffer(const SkRefCntSet& typefaceSet, void* buffer); |
| + size_t prepareCrossProcessTypefaceBuffer(const SkRefCntSet& typefaceSet, void* buffer); |
| + |
| // 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 +415,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 +440,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 +942,68 @@ void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const |
| } |
| } |
| +size_t SkGPipeCanvas::prepareInProcessTypefaceBuffer(const SkRefCntSet& typefaceSet, void* buffer) { |
| + // When in-process, we simply write out the typeface pointers. |
| + typefaceSet.copyToArray((SkRefCnt**)buffer); |
| + |
| + return typefaceSet.count() * sizeof(SkTypeface*); |
| +} |
| + |
| +size_t SkGPipeCanvas::prepareCrossProcessTypefaceBuffer(const SkRefCntSet& typefaceSet, |
| + void* buffer) { |
| + // For cross-process we use typeface IDs. |
| + typefaceSet.copyToArray((SkRefCnt**)buffer); |
|
mtklein
2014/09/15 22:13:14
Is there any hope for writing typefaceSet.copyIDsT
|
| + |
| + uint32_t* ids = reinterpret_cast<uint32_t*>(buffer); |
| + SkTypeface** typefaces = reinterpret_cast<SkTypeface**>(buffer); |
| + for (int i = 0; i < typefaceSet.count(); ++i) { |
| + ids[i] = this->getTypefaceID(typefaces[i]); |
| + } |
| + |
| + return typefaceSet.count() * sizeof(uint32_t); |
| +} |
| + |
| 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. |
| + SkAutoSTMalloc<128, uint8_t> storage(typefaceSet.count() * sizeof(SkTypeface*)); |
| + size_t typefaceSize = is_cross_process(fFlags) |
| + ? this->prepareCrossProcessTypefaceBuffer(typefaceSet, storage.get()) |
| + : this->prepareInProcessTypefaceBuffer(typefaceSet, storage.get()); |
| + |
| + // 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(storage.get(), typefaceSize); |
| + |
| fWriter.write32(SkToU32(blobBuffer.bytesWritten())); |
| uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten()); |
| blobBuffer.writeToMemory(pad); |
| + |
| + SkASSERT(initialOffset + size == fWriter.bytesWritten()); |
| } |
| } |
| @@ -1197,7 +1246,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*))) { |