diff options
-rw-r--r-- | expectations/gm/ignored-tests.txt | 3 | ||||
-rw-r--r-- | gm/textblob.cpp | 8 | ||||
-rw-r--r-- | src/core/SkPtrRecorder.h | 21 | ||||
-rw-r--r-- | src/pipe/SkGPipeRead.cpp | 18 | ||||
-rw-r--r-- | src/pipe/SkGPipeWrite.cpp | 70 |
5 files changed, 109 insertions, 11 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index 377575edad..0e6ef7918f 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -41,3 +41,6 @@ multipicturedraw_pathclip_tiled # rileya - https://codereview.chromium.org/516463005/ will rebaseline after bots cycle yuv_to_rgb_effect + +# fmalita - added typeface to test pipe serialization +textblob diff --git a/gm/textblob.cpp b/gm/textblob.cpp index 6837363898..a0340071f7 100644 --- a/gm/textblob.cpp +++ b/gm/textblob.cpp @@ -66,8 +66,10 @@ const SkScalar kFontSize = 16; class TextBlobGM : public skiagm::GM { public: - TextBlobGM(const char* txt) { + TextBlobGM(const char* txt) + : fTypeface(sk_tool_utils::create_portable_typeface("Times", SkTypeface::kNormal)) { SkPaint p; + p.setTypeface(fTypeface); size_t txtLen = strlen(txt); int glyphCount = p.textToGlyphs(txt, txtLen, NULL); @@ -111,6 +113,7 @@ private: font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); font.setAntiAlias(true); font.setSubpixelText(true); + font.setTypeface(fTypeface); for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) { unsigned currentGlyph = 0; @@ -173,7 +176,8 @@ private: return builder.build(); } - SkTDArray<uint16_t> fGlyphs; + SkTDArray<uint16_t> fGlyphs; + SkAutoTUnref<SkTypeface> fTypeface; typedef skiagm::GM INHERITED; }; diff --git a/src/core/SkPtrRecorder.h b/src/core/SkPtrRecorder.h index 06e14ab6ec..83200f5275 100644 --- a/src/core/SkPtrRecorder.h +++ b/src/core/SkPtrRecorder.h @@ -58,6 +58,27 @@ public: */ void reset(); + /** + * Set iterator. + */ + class Iter { + public: + Iter(const SkPtrSet& set) + : fSet(set) + , fIndex(0) {} + + /** + * Return the next ptr in the set or null if the end was reached. + */ + void* next() { + return fIndex < fSet.fList.count() ? fSet.fList[fIndex++].fPtr : NULL; + } + + private: + const SkPtrSet& fSet; + int fIndex; + }; + protected: virtual void incPtr(void*) {} virtual void decPtr(void*) {} diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp index 4bd4fa6a5c..8cb0e34d0a 100644 --- a/src/pipe/SkGPipeRead.cpp +++ b/src/pipe/SkGPipeRead.cpp @@ -194,8 +194,8 @@ public: *fTypefaces.append() = SkTypeface::Deserialize(&stream); } - void setTypeface(SkPaint* paint, unsigned id) { - paint->setTypeface(id ? fTypefaces[id - 1] : NULL); + SkTypeface* getTypeface(unsigned id) const { + return id ? fTypefaces[id - 1] : NULL; } private: @@ -676,11 +676,22 @@ static void drawTextBlob_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkScalar x = reader->readScalar(); SkScalar y = reader->readScalar(); + int typefaceCount = reader->readU32(); + SkAutoSTMalloc<16, SkTypeface*> typefaceArray(typefaceCount); + if (state->getFlags() & SkGPipeWriter::kCrossProcess_Flag) { + for (int i = 0; i < typefaceCount; ++i) { + typefaceArray[i] = state->getTypeface(reader->readU32()); + } + } else { + reader->read(typefaceArray.get(), typefaceCount * sizeof(SkTypeface*)); + } + size_t blobSize = reader->readU32(); const void* data = reader->skip(SkAlign4(blobSize)); if (state->shouldDraw()) { SkReadBuffer blobBuffer(data, blobSize); + blobBuffer.setTypefaceArray(typefaceArray.get(), typefaceCount); SkAutoTUnref<const SkTextBlob> blob(SkTextBlob::CreateFromBuffer(blobBuffer)); SkASSERT(blob.get()); @@ -731,7 +742,8 @@ static void paintOp_rp(SkCanvas*, SkReader32* reader, uint32_t op32, case kTypeface_PaintOp: SkASSERT(SkToBool(state->getFlags() & SkGPipeWriter::kCrossProcess_Flag)); - state->setTypeface(p, data); break; + p->setTypeface(state->getTypeface(data)); + break; default: SkDEBUGFAIL("bad paintop"); return; } SkASSERT(reader->offset() <= stop); diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp index f361e5ed67..41b0234480 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*))) { |