SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, SkWriter32* writer, uint32_t flags, uint32_t width, uint32_t height) : SkCanvas(width, height) , fFactorySet(is_cross_process(flags) ? SkNEW(SkNamedFactorySet) : NULL) , fWriter(*writer) , fFlags(flags) , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags)) , fFlatDictionary(&fFlattenableHeap) { fController = controller; fDone = false; fBlockSize = 0; // need first block from controller fBytesNotified = 0; sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); // Tell the reader the appropriate flags to use. if (this->needOpBytes()) { this->writeOp(kReportFlags_DrawOp, fFlags, 0); } if (shouldFlattenBitmaps(flags)) { fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this))); fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO_KEEP)); } else { fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (BITMAPS_TO_KEEP, controller->numberOfReaders())); if (this->needOpBytes(sizeof(void*))) { this->writeOp(kShareBitmapHeap_DrawOp); fWriter.writePtr(static_cast<void*>(fBitmapHeap)); } } fFlattenableHeap.setBitmapStorage(fBitmapHeap); this->doNotify(); }
// return 0 for nullptr (or unflattenable obj), or index-base-1 // return ~(index-base-1) if an old flattenable was replaced int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { SkASSERT(!fDone && fBitmapHeap != nullptr); if (nullptr == obj) { return 0; } fBitmapHeap->deferAddingOwners(); bool added, replaced; const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHeap.flatToReplace(), &added, &replaced); fBitmapHeap->endAddingOwnersDeferral(added); int index = flat->index(); if (added) { if (is_cross_process(fFlags)) { this->flattenFactoryNames(); } size_t flatSize = flat->flatSize(); if (this->needOpBytes(flatSize)) { this->writeOp(kDef_Flattenable_DrawOp, paintflat, index); fWriter.write(flat->data(), flatSize); } } if (replaced) { index = ~index; } return index; }
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); // 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();)