michael@0: michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkAnnotation.h" michael@0: #include "SkBitmapDevice.h" michael@0: #include "SkBitmapHeap.h" michael@0: #include "SkCanvas.h" michael@0: #include "SkColorFilter.h" michael@0: #include "SkData.h" michael@0: #include "SkDrawLooper.h" michael@0: #include "SkGPipe.h" michael@0: #include "SkGPipePriv.h" michael@0: #include "SkImageFilter.h" michael@0: #include "SkMaskFilter.h" michael@0: #include "SkWriteBuffer.h" michael@0: #include "SkPaint.h" michael@0: #include "SkPathEffect.h" michael@0: #include "SkPictureFlat.h" michael@0: #include "SkRasterizer.h" michael@0: #include "SkRRect.h" michael@0: #include "SkShader.h" michael@0: #include "SkStream.h" michael@0: #include "SkTSearch.h" michael@0: #include "SkTypeface.h" michael@0: #include "SkWriter32.h" michael@0: michael@0: enum { michael@0: kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector) michael@0: }; michael@0: michael@0: static bool isCrossProcess(uint32_t flags) { michael@0: return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag); michael@0: } michael@0: michael@0: static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) { michael@0: SkASSERT(paintFlat < kCount_PaintFlats); michael@0: switch (paintFlat) { michael@0: case kColorFilter_PaintFlat: return paint.getColorFilter(); michael@0: case kDrawLooper_PaintFlat: return paint.getLooper(); michael@0: case kMaskFilter_PaintFlat: return paint.getMaskFilter(); michael@0: case kPathEffect_PaintFlat: return paint.getPathEffect(); michael@0: case kRasterizer_PaintFlat: return paint.getRasterizer(); michael@0: case kShader_PaintFlat: return paint.getShader(); michael@0: case kImageFilter_PaintFlat: return paint.getImageFilter(); michael@0: case kXfermode_PaintFlat: return paint.getXfermode(); michael@0: } michael@0: SkDEBUGFAIL("never gets here"); michael@0: return NULL; michael@0: } michael@0: michael@0: static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { michael@0: SkASSERT(typeface); michael@0: SkDynamicMemoryWStream stream; michael@0: typeface->serialize(&stream); michael@0: size_t size = stream.getOffset(); michael@0: if (writer) { michael@0: writer->write32(size); michael@0: SkAutoDataUnref data(stream.copyToData()); michael@0: writer->writePad(data->data(), size); michael@0: } michael@0: return 4 + SkAlign4(size); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class FlattenableHeap : public SkFlatController { michael@0: public: michael@0: FlattenableHeap(int numFlatsToKeep, SkNamedFactorySet* fset, bool isCrossProcess) michael@0: : INHERITED(isCrossProcess ? SkWriteBuffer::kCrossProcess_Flag : 0) michael@0: , fNumFlatsToKeep(numFlatsToKeep) { michael@0: SkASSERT((isCrossProcess && fset != NULL) || (!isCrossProcess && NULL == fset)); michael@0: if (isCrossProcess) { michael@0: this->setNamedFactorySet(fset); michael@0: } michael@0: } michael@0: michael@0: ~FlattenableHeap() { michael@0: fPointers.freeAll(); michael@0: } michael@0: michael@0: virtual void* allocThrow(size_t bytes) SK_OVERRIDE; michael@0: michael@0: virtual void unalloc(void* ptr) SK_OVERRIDE; michael@0: michael@0: void setBitmapStorage(SkBitmapHeap* heap) { michael@0: this->setBitmapHeap(heap); michael@0: } michael@0: michael@0: const SkFlatData* flatToReplace() const; michael@0: michael@0: // Mark an SkFlatData as one that should not be returned by flatToReplace. michael@0: // Takes the result of SkFlatData::index() as its parameter. michael@0: void markFlatForKeeping(int index) { michael@0: *fFlatsThatMustBeKept.append() = index; michael@0: } michael@0: michael@0: void markAllFlatsSafeToDelete() { michael@0: fFlatsThatMustBeKept.reset(); michael@0: } michael@0: michael@0: private: michael@0: // Keep track of the indices (i.e. the result of SkFlatData::index()) of michael@0: // flats that must be kept, since they are on the current paint. michael@0: SkTDArray fFlatsThatMustBeKept; michael@0: SkTDArray fPointers; michael@0: const int fNumFlatsToKeep; michael@0: michael@0: typedef SkFlatController INHERITED; michael@0: }; michael@0: michael@0: void FlattenableHeap::unalloc(void* ptr) { michael@0: int indexToRemove = fPointers.rfind(ptr); michael@0: if (indexToRemove >= 0) { michael@0: sk_free(ptr); michael@0: fPointers.remove(indexToRemove); michael@0: } michael@0: } michael@0: michael@0: void* FlattenableHeap::allocThrow(size_t bytes) { michael@0: void* ptr = sk_malloc_throw(bytes); michael@0: *fPointers.append() = ptr; michael@0: return ptr; michael@0: } michael@0: michael@0: const SkFlatData* FlattenableHeap::flatToReplace() const { michael@0: // First, determine whether we should replace one. michael@0: if (fPointers.count() > fNumFlatsToKeep) { michael@0: // Look through the flattenable heap. michael@0: // TODO: Return the LRU flat. michael@0: for (int i = 0; i < fPointers.count(); i++) { michael@0: SkFlatData* potential = (SkFlatData*)fPointers[i]; michael@0: // Make sure that it is not one that must be kept. michael@0: bool mustKeep = false; michael@0: for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) { michael@0: if (potential->index() == fFlatsThatMustBeKept[j]) { michael@0: mustKeep = true; michael@0: break; michael@0: } michael@0: } michael@0: if (!mustKeep) { michael@0: return potential; michael@0: } michael@0: } michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: struct SkFlattenableTraits { michael@0: static void Flatten(SkWriteBuffer& buffer, const SkFlattenable& flattenable) { michael@0: buffer.writeFlattenable(&flattenable); michael@0: } michael@0: // No need to define unflatten if we never call it. michael@0: }; michael@0: typedef SkFlatDictionary FlatDictionary; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * If SkBitmaps are to be flattened to send to the reader, this class is michael@0: * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so. michael@0: */ michael@0: class BitmapShuttle : public SkBitmapHeap::ExternalStorage { michael@0: public: michael@0: BitmapShuttle(SkGPipeCanvas*); michael@0: michael@0: ~BitmapShuttle(); michael@0: michael@0: virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE; michael@0: michael@0: /** michael@0: * Remove the SkGPipeCanvas used for insertion. After this, calls to michael@0: * insert will crash. michael@0: */ michael@0: void removeCanvas(); michael@0: michael@0: private: michael@0: SkGPipeCanvas* fCanvas; michael@0: }; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class SkGPipeCanvas : public SkCanvas { michael@0: public: michael@0: SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags, michael@0: uint32_t width, uint32_t height); michael@0: virtual ~SkGPipeCanvas(); michael@0: michael@0: /** michael@0: * Called when nothing else is to be written to the stream. Any repeated michael@0: * calls are ignored. michael@0: * michael@0: * @param notifyReaders Whether to send a message to the reader(s) that michael@0: * the writer is through sending commands. Should generally be true, michael@0: * unless there is an error which prevents further messages from michael@0: * being sent. michael@0: */ michael@0: void finish(bool notifyReaders) { michael@0: if (fDone) { michael@0: return; michael@0: } michael@0: if (notifyReaders && this->needOpBytes()) { michael@0: this->writeOp(kDone_DrawOp); michael@0: this->doNotify(); michael@0: } michael@0: if (shouldFlattenBitmaps(fFlags)) { michael@0: // The following circular references exist: michael@0: // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalStorage -> fCanvas michael@0: // fBitmapHeap -> fExternalStorage -> fCanvas michael@0: // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas michael@0: michael@0: // Break them all by destroying the final link to this SkGPipeCanvas. michael@0: fBitmapShuttle->removeCanvas(); michael@0: } michael@0: fDone = true; michael@0: } michael@0: michael@0: void flushRecording(bool detachCurrentBlock); michael@0: size_t freeMemoryIfPossible(size_t bytesToFree); michael@0: michael@0: size_t storageAllocatedForRecording() { michael@0: return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated(); michael@0: } michael@0: michael@0: // overrides from SkCanvas michael@0: virtual bool isDrawingToLayer() const SK_OVERRIDE; michael@0: virtual void clear(SkColor) SK_OVERRIDE; michael@0: virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; michael@0: virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], michael@0: const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawOval(const SkRect&, const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, michael@0: const SkPaint*) SK_OVERRIDE; michael@0: virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, michael@0: const SkRect& dst, const SkPaint* paint, michael@0: DrawBitmapRectFlags flags) SK_OVERRIDE; michael@0: virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, michael@0: const SkPaint*) SK_OVERRIDE; michael@0: virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, michael@0: const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE; michael@0: virtual void drawSprite(const SkBitmap&, int left, int top, michael@0: const SkPaint*) SK_OVERRIDE; michael@0: virtual void drawText(const void* text, size_t byteLength, SkScalar x, michael@0: SkScalar y, const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawPosText(const void* text, size_t byteLength, michael@0: const SkPoint pos[], const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawPosTextH(const void* text, size_t byteLength, michael@0: const SkScalar xpos[], SkScalar constY, michael@0: const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawTextOnPath(const void* text, size_t byteLength, michael@0: const SkPath& path, const SkMatrix* matrix, michael@0: const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawPicture(SkPicture& picture) SK_OVERRIDE; michael@0: virtual void drawVertices(VertexMode, int vertexCount, michael@0: const SkPoint vertices[], const SkPoint texs[], michael@0: const SkColor colors[], SkXfermode*, michael@0: const uint16_t indices[], int indexCount, michael@0: const SkPaint&) SK_OVERRIDE; michael@0: virtual void drawData(const void*, size_t) SK_OVERRIDE; michael@0: virtual void beginCommentGroup(const char* description) SK_OVERRIDE; michael@0: virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE; michael@0: virtual void endCommentGroup() SK_OVERRIDE; michael@0: michael@0: /** michael@0: * Flatten an SkBitmap to send to the reader, where it will be referenced michael@0: * according to slot. michael@0: */ michael@0: bool shuttleBitmap(const SkBitmap&, int32_t slot); michael@0: michael@0: protected: michael@0: virtual void willSave(SaveFlags) SK_OVERRIDE; michael@0: virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE; michael@0: virtual void willRestore() SK_OVERRIDE; michael@0: michael@0: virtual void didTranslate(SkScalar, SkScalar) SK_OVERRIDE; michael@0: virtual void didScale(SkScalar, SkScalar) SK_OVERRIDE; michael@0: virtual void didRotate(SkScalar) SK_OVERRIDE; michael@0: virtual void didSkew(SkScalar, SkScalar) SK_OVERRIDE; michael@0: virtual void didConcat(const SkMatrix&) SK_OVERRIDE; michael@0: virtual void didSetMatrix(const SkMatrix&) SK_OVERRIDE; michael@0: michael@0: virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE; michael@0: michael@0: virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; michael@0: virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; michael@0: virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; michael@0: virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE; michael@0: michael@0: private: michael@0: enum { michael@0: kNoSaveLayer = -1, michael@0: }; michael@0: SkNamedFactorySet* fFactorySet; michael@0: int fFirstSaveLayerStackLevel; michael@0: SkBitmapHeap* fBitmapHeap; michael@0: SkGPipeController* fController; michael@0: SkWriter32& fWriter; michael@0: size_t fBlockSize; // amount allocated for writer michael@0: size_t fBytesNotified; michael@0: bool fDone; michael@0: const uint32_t fFlags; michael@0: michael@0: SkRefCntSet fTypefaceSet; michael@0: michael@0: uint32_t getTypefaceID(SkTypeface*); michael@0: michael@0: inline void writeOp(DrawOps op, unsigned flags, unsigned data) { michael@0: fWriter.write32(DrawOp_packOpFlagData(op, flags, data)); michael@0: } michael@0: michael@0: inline void writeOp(DrawOps op) { michael@0: fWriter.write32(DrawOp_packOpFlagData(op, 0, 0)); michael@0: } michael@0: michael@0: bool needOpBytes(size_t size = 0); michael@0: michael@0: inline void doNotify() { michael@0: if (!fDone) { michael@0: size_t bytes = fWriter.bytesWritten() - fBytesNotified; michael@0: if (bytes > 0) { michael@0: fController->notifyWritten(bytes); michael@0: fBytesNotified += bytes; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Should be called after any calls to an SkFlatDictionary::findAndReplace michael@0: // if a new SkFlatData was added when in cross process mode michael@0: void flattenFactoryNames(); michael@0: michael@0: FlattenableHeap fFlattenableHeap; michael@0: FlatDictionary fFlatDictionary; michael@0: SkAutoTUnref fBitmapShuttle; michael@0: int fCurrFlatIndex[kCount_PaintFlats]; michael@0: michael@0: int flattenToIndex(SkFlattenable* obj, PaintFlats); michael@0: michael@0: // Common code used by drawBitmap*. Behaves differently depending on the michael@0: // type of SkBitmapHeap being used, which is determined by the flags used. michael@0: bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags, michael@0: size_t opBytesNeeded, const SkPaint* paint); michael@0: michael@0: SkPaint fPaint; michael@0: void writePaint(const SkPaint&); michael@0: michael@0: class AutoPipeNotify { michael@0: public: michael@0: AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {} michael@0: ~AutoPipeNotify() { fCanvas->doNotify(); } michael@0: private: michael@0: SkGPipeCanvas* fCanvas; michael@0: }; michael@0: friend class AutoPipeNotify; michael@0: michael@0: typedef SkCanvas INHERITED; michael@0: }; michael@0: michael@0: void SkGPipeCanvas::flattenFactoryNames() { michael@0: const char* name; michael@0: while ((name = fFactorySet->getNextAddedFactoryName()) != NULL) { michael@0: size_t len = strlen(name); michael@0: if (this->needOpBytes(len)) { michael@0: this->writeOp(kDef_Factory_DrawOp); michael@0: fWriter.writeString(name, len); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) { michael@0: SkASSERT(shouldFlattenBitmaps(fFlags)); michael@0: SkWriteBuffer buffer; michael@0: buffer.setNamedFactoryRecorder(fFactorySet); michael@0: buffer.writeBitmap(bm); michael@0: this->flattenFactoryNames(); michael@0: uint32_t size = buffer.bytesWritten(); michael@0: if (this->needOpBytes(size)) { michael@0: this->writeOp(kDef_Bitmap_DrawOp, 0, slot); michael@0: void* dst = static_cast(fWriter.reserve(size)); michael@0: buffer.writeToMemory(dst); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // return 0 for NULL (or unflattenable obj), or index-base-1 michael@0: // return ~(index-base-1) if an old flattenable was replaced michael@0: int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { michael@0: SkASSERT(!fDone && fBitmapHeap != NULL); michael@0: if (NULL == obj) { michael@0: return 0; michael@0: } michael@0: michael@0: fBitmapHeap->deferAddingOwners(); michael@0: bool added, replaced; michael@0: const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHeap.flatToReplace(), michael@0: &added, &replaced); michael@0: fBitmapHeap->endAddingOwnersDeferral(added); michael@0: int index = flat->index(); michael@0: if (added) { michael@0: if (isCrossProcess(fFlags)) { michael@0: this->flattenFactoryNames(); michael@0: } michael@0: size_t flatSize = flat->flatSize(); michael@0: if (this->needOpBytes(flatSize)) { michael@0: this->writeOp(kDef_Flattenable_DrawOp, paintflat, index); michael@0: fWriter.write(flat->data(), flatSize); michael@0: } michael@0: } michael@0: if (replaced) { michael@0: index = ~index; michael@0: } michael@0: return index; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define MIN_BLOCK_SIZE (16 * 1024) michael@0: #define BITMAPS_TO_KEEP 5 michael@0: #define FLATTENABLES_TO_KEEP 10 michael@0: michael@0: SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, michael@0: SkWriter32* writer, uint32_t flags, michael@0: uint32_t width, uint32_t height) michael@0: : SkCanvas(width, height) michael@0: , fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL) michael@0: , fWriter(*writer) michael@0: , fFlags(flags) michael@0: , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, isCrossProcess(flags)) michael@0: , fFlatDictionary(&fFlattenableHeap) michael@0: { michael@0: fController = controller; michael@0: fDone = false; michael@0: fBlockSize = 0; // need first block from controller michael@0: fBytesNotified = 0; michael@0: fFirstSaveLayerStackLevel = kNoSaveLayer; michael@0: sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); michael@0: michael@0: // Tell the reader the appropriate flags to use. michael@0: if (this->needOpBytes()) { michael@0: this->writeOp(kReportFlags_DrawOp, fFlags, 0); michael@0: } michael@0: michael@0: if (shouldFlattenBitmaps(flags)) { michael@0: fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this))); michael@0: fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO_KEEP)); michael@0: } else { michael@0: fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, michael@0: (BITMAPS_TO_KEEP, controller->numberOfReaders())); michael@0: if (this->needOpBytes(sizeof(void*))) { michael@0: this->writeOp(kShareBitmapHeap_DrawOp); michael@0: fWriter.writePtr(static_cast(fBitmapHeap)); michael@0: } michael@0: } michael@0: fFlattenableHeap.setBitmapStorage(fBitmapHeap); michael@0: this->doNotify(); michael@0: } michael@0: michael@0: SkGPipeCanvas::~SkGPipeCanvas() { michael@0: this->finish(true); michael@0: SkSafeUnref(fFactorySet); michael@0: SkSafeUnref(fBitmapHeap); michael@0: } michael@0: michael@0: bool SkGPipeCanvas::needOpBytes(size_t needed) { michael@0: if (fDone) { michael@0: return false; michael@0: } michael@0: michael@0: needed += 4; // size of DrawOp atom michael@0: if (fWriter.bytesWritten() + needed > fBlockSize) { michael@0: // Before we wipe out any data that has already been written, read it michael@0: // out. michael@0: this->doNotify(); michael@0: size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed); michael@0: void* block = fController->requestBlock(blockSize, &fBlockSize); michael@0: if (NULL == block) { michael@0: // Do not notify the readers, which would call this function again. michael@0: this->finish(false); michael@0: return false; michael@0: } michael@0: SkASSERT(SkIsAlign4(fBlockSize)); michael@0: fWriter.reset(block, fBlockSize); michael@0: fBytesNotified = 0; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) { michael@0: uint32_t id = 0; // 0 means default/null typeface michael@0: if (face) { michael@0: id = fTypefaceSet.find(face); michael@0: if (0 == id) { michael@0: id = fTypefaceSet.add(face); michael@0: size_t size = writeTypeface(NULL, face); michael@0: if (this->needOpBytes(size)) { michael@0: this->writeOp(kDef_Typeface_DrawOp); michael@0: writeTypeface(&fWriter, face); michael@0: } michael@0: } michael@0: } michael@0: return id; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define NOTIFY_SETUP(canvas) \ michael@0: AutoPipeNotify apn(canvas) michael@0: michael@0: void SkGPipeCanvas::willSave(SaveFlags flags) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes()) { michael@0: this->writeOp(kSave_DrawOp, 0, flags); michael@0: } michael@0: michael@0: this->INHERITED::willSave(flags); michael@0: } michael@0: michael@0: SkCanvas::SaveLayerStrategy SkGPipeCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, michael@0: SaveFlags saveFlags) { michael@0: NOTIFY_SETUP(this); michael@0: size_t size = 0; michael@0: unsigned opFlags = 0; michael@0: michael@0: if (bounds) { michael@0: opFlags |= kSaveLayer_HasBounds_DrawOpFlag; michael@0: size += sizeof(SkRect); michael@0: } michael@0: if (paint) { michael@0: opFlags |= kSaveLayer_HasPaint_DrawOpFlag; michael@0: this->writePaint(*paint); michael@0: } michael@0: michael@0: if (this->needOpBytes(size)) { michael@0: this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags); michael@0: if (bounds) { michael@0: fWriter.writeRect(*bounds); michael@0: } michael@0: } michael@0: michael@0: if (kNoSaveLayer == fFirstSaveLayerStackLevel){ michael@0: fFirstSaveLayerStackLevel = this->getSaveCount(); michael@0: } michael@0: michael@0: this->INHERITED::willSaveLayer(bounds, paint, saveFlags); michael@0: // we don't create a layer michael@0: return kNoLayer_SaveLayerStrategy; michael@0: } michael@0: michael@0: void SkGPipeCanvas::willRestore() { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes()) { michael@0: this->writeOp(kRestore_DrawOp); michael@0: } michael@0: michael@0: if (this->getSaveCount() - 1 == fFirstSaveLayerStackLevel){ michael@0: fFirstSaveLayerStackLevel = kNoSaveLayer; michael@0: } michael@0: michael@0: this->INHERITED::willRestore(); michael@0: } michael@0: michael@0: bool SkGPipeCanvas::isDrawingToLayer() const { michael@0: return kNoSaveLayer != fFirstSaveLayerStackLevel; michael@0: } michael@0: michael@0: void SkGPipeCanvas::didTranslate(SkScalar dx, SkScalar dy) { michael@0: if (dx || dy) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(2 * sizeof(SkScalar))) { michael@0: this->writeOp(kTranslate_DrawOp); michael@0: fWriter.writeScalar(dx); michael@0: fWriter.writeScalar(dy); michael@0: } michael@0: } michael@0: this->INHERITED::didTranslate(dx, dy); michael@0: } michael@0: michael@0: void SkGPipeCanvas::didScale(SkScalar sx, SkScalar sy) { michael@0: if (sx || sy) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(2 * sizeof(SkScalar))) { michael@0: this->writeOp(kScale_DrawOp); michael@0: fWriter.writeScalar(sx); michael@0: fWriter.writeScalar(sy); michael@0: } michael@0: } michael@0: this->INHERITED::didScale(sx, sy); michael@0: } michael@0: michael@0: void SkGPipeCanvas::didRotate(SkScalar degrees) { michael@0: if (degrees) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(sizeof(SkScalar))) { michael@0: this->writeOp(kRotate_DrawOp); michael@0: fWriter.writeScalar(degrees); michael@0: } michael@0: } michael@0: this->INHERITED::didRotate(degrees); michael@0: } michael@0: michael@0: void SkGPipeCanvas::didSkew(SkScalar sx, SkScalar sy) { michael@0: if (sx || sy) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(2 * sizeof(SkScalar))) { michael@0: this->writeOp(kSkew_DrawOp); michael@0: fWriter.writeScalar(sx); michael@0: fWriter.writeScalar(sy); michael@0: } michael@0: } michael@0: this->INHERITED::didSkew(sx, sy); michael@0: } michael@0: michael@0: void SkGPipeCanvas::didConcat(const SkMatrix& matrix) { michael@0: if (!matrix.isIdentity()) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(matrix.writeToMemory(NULL))) { michael@0: this->writeOp(kConcat_DrawOp); michael@0: fWriter.writeMatrix(matrix); michael@0: } michael@0: } michael@0: this->INHERITED::didConcat(matrix); michael@0: } michael@0: michael@0: void SkGPipeCanvas::didSetMatrix(const SkMatrix& matrix) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(matrix.writeToMemory(NULL))) { michael@0: this->writeOp(kSetMatrix_DrawOp); michael@0: fWriter.writeMatrix(matrix); michael@0: } michael@0: this->INHERITED::didSetMatrix(matrix); michael@0: } michael@0: michael@0: void SkGPipeCanvas::onClipRect(const SkRect& rect, SkRegion::Op rgnOp, michael@0: ClipEdgeStyle edgeStyle) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(sizeof(SkRect))) { michael@0: unsigned flags = 0; michael@0: if (kSoft_ClipEdgeStyle == edgeStyle) { michael@0: flags = kClip_HasAntiAlias_DrawOpFlag; michael@0: } michael@0: this->writeOp(kClipRect_DrawOp, flags, rgnOp); michael@0: fWriter.writeRect(rect); michael@0: } michael@0: this->INHERITED::onClipRect(rect, rgnOp, edgeStyle); michael@0: } michael@0: michael@0: void SkGPipeCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op rgnOp, michael@0: ClipEdgeStyle edgeStyle) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(kSizeOfFlatRRect)) { michael@0: unsigned flags = 0; michael@0: if (kSoft_ClipEdgeStyle == edgeStyle) { michael@0: flags = kClip_HasAntiAlias_DrawOpFlag; michael@0: } michael@0: this->writeOp(kClipRRect_DrawOp, flags, rgnOp); michael@0: fWriter.writeRRect(rrect); michael@0: } michael@0: this->INHERITED::onClipRRect(rrect, rgnOp, edgeStyle); michael@0: } michael@0: michael@0: void SkGPipeCanvas::onClipPath(const SkPath& path, SkRegion::Op rgnOp, michael@0: ClipEdgeStyle edgeStyle) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(path.writeToMemory(NULL))) { michael@0: unsigned flags = 0; michael@0: if (kSoft_ClipEdgeStyle == edgeStyle) { michael@0: flags = kClip_HasAntiAlias_DrawOpFlag; michael@0: } michael@0: this->writeOp(kClipPath_DrawOp, flags, rgnOp); michael@0: fWriter.writePath(path); michael@0: } michael@0: // we just pass on the bounds of the path michael@0: this->INHERITED::onClipRect(path.getBounds(), rgnOp, edgeStyle); michael@0: } michael@0: michael@0: void SkGPipeCanvas::onClipRegion(const SkRegion& region, SkRegion::Op rgnOp) { michael@0: NOTIFY_SETUP(this); michael@0: if (this->needOpBytes(region.writeToMemory(NULL))) { michael@0: this->writeOp(kClipRegion_DrawOp, 0, rgnOp); michael@0: fWriter.writeRegion(region); michael@0: } michael@0: this->INHERITED::onClipRegion(region, rgnOp); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: void SkGPipeCanvas::clear(SkColor color) { michael@0: NOTIFY_SETUP(this); michael@0: unsigned flags = 0; michael@0: if (color) { michael@0: flags |= kClear_HasColor_DrawOpFlag; michael@0: } michael@0: if (this->needOpBytes(sizeof(SkColor))) { michael@0: this->writeOp(kDrawClear_DrawOp, flags, 0); michael@0: if (color) { michael@0: fWriter.write32(color); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawPaint(const SkPaint& paint) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes()) { michael@0: this->writeOp(kDrawPaint_DrawOp); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawPoints(PointMode mode, size_t count, michael@0: const SkPoint pts[], const SkPaint& paint) { michael@0: if (count) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(4 + count * sizeof(SkPoint))) { michael@0: this->writeOp(kDrawPoints_DrawOp, mode, 0); michael@0: fWriter.write32(count); michael@0: fWriter.write(pts, count * sizeof(SkPoint)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawOval(const SkRect& rect, const SkPaint& paint) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(sizeof(SkRect))) { michael@0: this->writeOp(kDrawOval_DrawOp); michael@0: fWriter.writeRect(rect); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(sizeof(SkRect))) { michael@0: this->writeOp(kDrawRect_DrawOp); michael@0: fWriter.writeRect(rect); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(kSizeOfFlatRRect)) { michael@0: this->writeOp(kDrawRRect_DrawOp); michael@0: fWriter.writeRRect(rrect); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, michael@0: const SkPaint& paint) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(kSizeOfFlatRRect * 2)) { michael@0: this->writeOp(kDrawDRRect_DrawOp); michael@0: fWriter.writeRRect(outer); michael@0: fWriter.writeRRect(inner); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(path.writeToMemory(NULL))) { michael@0: this->writeOp(kDrawPath_DrawOp); michael@0: fWriter.writePath(path); michael@0: } michael@0: } michael@0: michael@0: bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op, michael@0: unsigned flags, michael@0: size_t opBytesNeeded, michael@0: const SkPaint* paint) { michael@0: if (paint != NULL) { michael@0: flags |= kDrawBitmap_HasPaint_DrawOpFlag; michael@0: this->writePaint(*paint); michael@0: } michael@0: if (this->needOpBytes(opBytesNeeded)) { michael@0: SkASSERT(fBitmapHeap != NULL); michael@0: int32_t bitmapIndex = fBitmapHeap->insert(bm); michael@0: if (SkBitmapHeap::INVALID_SLOT == bitmapIndex) { michael@0: return false; michael@0: } michael@0: this->writeOp(op, flags, bitmapIndex); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top, michael@0: const SkPaint* paint) { michael@0: NOTIFY_SETUP(this); michael@0: size_t opBytesNeeded = sizeof(SkScalar) * 2; michael@0: michael@0: if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint)) { michael@0: fWriter.writeScalar(left); michael@0: fWriter.writeScalar(top); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawBitmapRectToRect(const SkBitmap& bm, const SkRect* src, michael@0: const SkRect& dst, const SkPaint* paint, michael@0: DrawBitmapRectFlags dbmrFlags) { michael@0: NOTIFY_SETUP(this); michael@0: size_t opBytesNeeded = sizeof(SkRect); michael@0: bool hasSrc = src != NULL; michael@0: unsigned flags; michael@0: if (hasSrc) { michael@0: flags = kDrawBitmap_HasSrcRect_DrawOpFlag; michael@0: opBytesNeeded += sizeof(int32_t) * 4; michael@0: } else { michael@0: flags = 0; michael@0: } michael@0: if (dbmrFlags & kBleed_DrawBitmapRectFlag) { michael@0: flags |= kDrawBitmap_Bleed_DrawOpFlag; michael@0: } michael@0: michael@0: if (this->commonDrawBitmap(bm, kDrawBitmapRectToRect_DrawOp, flags, opBytesNeeded, paint)) { michael@0: if (hasSrc) { michael@0: fWriter.writeRect(*src); michael@0: } michael@0: fWriter.writeRect(dst); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap& bm, const SkMatrix& matrix, michael@0: const SkPaint* paint) { michael@0: NOTIFY_SETUP(this); michael@0: size_t opBytesNeeded = matrix.writeToMemory(NULL); michael@0: michael@0: if (this->commonDrawBitmap(bm, kDrawBitmapMatrix_DrawOp, 0, opBytesNeeded, paint)) { michael@0: fWriter.writeMatrix(matrix); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center, michael@0: const SkRect& dst, const SkPaint* paint) { michael@0: NOTIFY_SETUP(this); michael@0: size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect); michael@0: michael@0: if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, paint)) { michael@0: fWriter.write32(center.fLeft); michael@0: fWriter.write32(center.fTop); michael@0: fWriter.write32(center.fRight); michael@0: fWriter.write32(center.fBottom); michael@0: fWriter.writeRect(dst); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top, michael@0: const SkPaint* paint) { michael@0: NOTIFY_SETUP(this); michael@0: size_t opBytesNeeded = sizeof(int32_t) * 2; michael@0: michael@0: if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) { michael@0: fWriter.write32(left); michael@0: fWriter.write32(top); michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x, michael@0: SkScalar y, const SkPaint& paint) { michael@0: if (byteLength) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) { michael@0: this->writeOp(kDrawText_DrawOp); michael@0: fWriter.write32(byteLength); michael@0: fWriter.writePad(text, byteLength); michael@0: fWriter.writeScalar(x); michael@0: fWriter.writeScalar(y); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength, michael@0: const SkPoint pos[], const SkPaint& paint) { michael@0: if (byteLength) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: int count = paint.textToGlyphs(text, byteLength, NULL); michael@0: if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) { michael@0: this->writeOp(kDrawPosText_DrawOp); michael@0: fWriter.write32(byteLength); michael@0: fWriter.writePad(text, byteLength); michael@0: fWriter.write32(count); michael@0: fWriter.write(pos, count * sizeof(SkPoint)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength, michael@0: const SkScalar xpos[], SkScalar constY, michael@0: const SkPaint& paint) { michael@0: if (byteLength) { michael@0: NOTIFY_SETUP(this); michael@0: this->writePaint(paint); michael@0: int count = paint.textToGlyphs(text, byteLength, NULL); michael@0: if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) { michael@0: this->writeOp(kDrawPosTextH_DrawOp); michael@0: fWriter.write32(byteLength); michael@0: fWriter.writePad(text, byteLength); michael@0: fWriter.write32(count); michael@0: fWriter.write(xpos, count * sizeof(SkScalar)); michael@0: fWriter.writeScalar(constY); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength, michael@0: const SkPath& path, const SkMatrix* matrix, michael@0: const SkPaint& paint) { michael@0: if (byteLength) { michael@0: NOTIFY_SETUP(this); michael@0: unsigned flags = 0; michael@0: size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(NULL); michael@0: if (matrix) { michael@0: flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag; michael@0: size += matrix->writeToMemory(NULL); michael@0: } michael@0: this->writePaint(paint); michael@0: if (this->needOpBytes(size)) { michael@0: this->writeOp(kDrawTextOnPath_DrawOp, flags, 0); michael@0: michael@0: fWriter.write32(byteLength); michael@0: fWriter.writePad(text, byteLength); michael@0: michael@0: fWriter.writePath(path); michael@0: if (matrix) { michael@0: fWriter.writeMatrix(*matrix); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawPicture(SkPicture& picture) { michael@0: // we want to playback the picture into individual draw calls michael@0: this->INHERITED::drawPicture(picture); michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawVertices(VertexMode vmode, int vertexCount, michael@0: const SkPoint vertices[], const SkPoint texs[], michael@0: const SkColor colors[], SkXfermode* xfer, michael@0: const uint16_t indices[], int indexCount, michael@0: const SkPaint& paint) { michael@0: if (0 == vertexCount) { michael@0: return; michael@0: } michael@0: michael@0: NOTIFY_SETUP(this); michael@0: size_t size = 4 + vertexCount * sizeof(SkPoint); michael@0: this->writePaint(paint); michael@0: unsigned flags = 0; michael@0: if (texs) { michael@0: flags |= kDrawVertices_HasTexs_DrawOpFlag; michael@0: size += vertexCount * sizeof(SkPoint); michael@0: } michael@0: if (colors) { michael@0: flags |= kDrawVertices_HasColors_DrawOpFlag; michael@0: size += vertexCount * sizeof(SkColor); michael@0: } michael@0: if (indices && indexCount > 0) { michael@0: flags |= kDrawVertices_HasIndices_DrawOpFlag; michael@0: size += 4 + SkAlign4(indexCount * sizeof(uint16_t)); michael@0: } michael@0: if (xfer && !SkXfermode::IsMode(xfer, SkXfermode::kModulate_Mode)) { michael@0: flags |= kDrawVertices_HasXfermode_DrawOpFlag; michael@0: size += sizeof(int32_t); // mode enum michael@0: } michael@0: michael@0: if (this->needOpBytes(size)) { michael@0: this->writeOp(kDrawVertices_DrawOp, flags, 0); michael@0: fWriter.write32(vmode); michael@0: fWriter.write32(vertexCount); michael@0: fWriter.write(vertices, vertexCount * sizeof(SkPoint)); michael@0: if (texs) { michael@0: fWriter.write(texs, vertexCount * sizeof(SkPoint)); michael@0: } michael@0: if (colors) { michael@0: fWriter.write(colors, vertexCount * sizeof(SkColor)); michael@0: } michael@0: if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { michael@0: SkXfermode::Mode mode = SkXfermode::kModulate_Mode; michael@0: (void)xfer->asMode(&mode); michael@0: fWriter.write32(mode); michael@0: } michael@0: if (indices && indexCount > 0) { michael@0: fWriter.write32(indexCount); michael@0: fWriter.writePad(indices, indexCount * sizeof(uint16_t)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::drawData(const void* ptr, size_t size) { michael@0: if (size && ptr) { michael@0: NOTIFY_SETUP(this); michael@0: unsigned data = 0; michael@0: if (size < (1 << DRAWOPS_DATA_BITS)) { michael@0: data = (unsigned)size; michael@0: } michael@0: if (this->needOpBytes(4 + SkAlign4(size))) { michael@0: this->writeOp(kDrawData_DrawOp, 0, data); michael@0: if (0 == data) { michael@0: fWriter.write32(size); michael@0: } michael@0: fWriter.writePad(ptr, size); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkGPipeCanvas::beginCommentGroup(const char* description) { michael@0: // ignore for now michael@0: } michael@0: michael@0: void SkGPipeCanvas::addComment(const char* kywd, const char* value) { michael@0: // ignore for now michael@0: } michael@0: michael@0: void SkGPipeCanvas::endCommentGroup() { michael@0: // ignore for now michael@0: } michael@0: michael@0: void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) { michael@0: doNotify(); michael@0: if (detachCurrentBlock) { michael@0: // force a new block to be requested for the next recorded command michael@0: fBlockSize = 0; michael@0: } michael@0: } michael@0: michael@0: size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) { michael@0: return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->freeMemoryIfPossible(bytesToFree); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: template uint32_t castToU32(T value) { michael@0: union { michael@0: T fSrc; michael@0: uint32_t fDst; michael@0: } data; michael@0: data.fSrc = value; michael@0: return data.fDst; michael@0: } michael@0: michael@0: void SkGPipeCanvas::writePaint(const SkPaint& paint) { michael@0: if (fDone) { michael@0: return; michael@0: } michael@0: SkPaint& base = fPaint; michael@0: uint32_t storage[32]; michael@0: uint32_t* ptr = storage; michael@0: michael@0: if (base.getFlags() != paint.getFlags()) { michael@0: *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags()); michael@0: base.setFlags(paint.getFlags()); michael@0: } michael@0: if (base.getColor() != paint.getColor()) { michael@0: *ptr++ = PaintOp_packOp(kColor_PaintOp); michael@0: *ptr++ = paint.getColor(); michael@0: base.setColor(paint.getColor()); michael@0: } michael@0: if (base.getStyle() != paint.getStyle()) { michael@0: *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle()); michael@0: base.setStyle(paint.getStyle()); michael@0: } michael@0: if (base.getStrokeJoin() != paint.getStrokeJoin()) { michael@0: *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin()); michael@0: base.setStrokeJoin(paint.getStrokeJoin()); michael@0: } michael@0: if (base.getStrokeCap() != paint.getStrokeCap()) { michael@0: *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap()); michael@0: base.setStrokeCap(paint.getStrokeCap()); michael@0: } michael@0: if (base.getStrokeWidth() != paint.getStrokeWidth()) { michael@0: *ptr++ = PaintOp_packOp(kWidth_PaintOp); michael@0: *ptr++ = castToU32(paint.getStrokeWidth()); michael@0: base.setStrokeWidth(paint.getStrokeWidth()); michael@0: } michael@0: if (base.getStrokeMiter() != paint.getStrokeMiter()) { michael@0: *ptr++ = PaintOp_packOp(kMiter_PaintOp); michael@0: *ptr++ = castToU32(paint.getStrokeMiter()); michael@0: base.setStrokeMiter(paint.getStrokeMiter()); michael@0: } michael@0: if (base.getTextEncoding() != paint.getTextEncoding()) { michael@0: *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding()); michael@0: base.setTextEncoding(paint.getTextEncoding()); michael@0: } michael@0: if (base.getHinting() != paint.getHinting()) { michael@0: *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting()); michael@0: base.setHinting(paint.getHinting()); michael@0: } michael@0: if (base.getTextAlign() != paint.getTextAlign()) { michael@0: *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign()); michael@0: base.setTextAlign(paint.getTextAlign()); michael@0: } michael@0: if (base.getTextSize() != paint.getTextSize()) { michael@0: *ptr++ = PaintOp_packOp(kTextSize_PaintOp); michael@0: *ptr++ = castToU32(paint.getTextSize()); michael@0: base.setTextSize(paint.getTextSize()); michael@0: } michael@0: if (base.getTextScaleX() != paint.getTextScaleX()) { michael@0: *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp); michael@0: *ptr++ = castToU32(paint.getTextScaleX()); michael@0: base.setTextScaleX(paint.getTextScaleX()); michael@0: } michael@0: if (base.getTextSkewX() != paint.getTextSkewX()) { michael@0: *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); michael@0: *ptr++ = castToU32(paint.getTextSkewX()); michael@0: base.setTextSkewX(paint.getTextSkewX()); michael@0: } michael@0: michael@0: if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { michael@0: if (isCrossProcess(fFlags)) { michael@0: uint32_t id = this->getTypefaceID(paint.getTypeface()); michael@0: *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); michael@0: } else if (this->needOpBytes(sizeof(void*))) { michael@0: // Add to the set for ref counting. michael@0: fTypefaceSet.add(paint.getTypeface()); michael@0: // It is safe to write the typeface to the stream before the rest michael@0: // of the paint unless we ever send a kReset_PaintOp, which we michael@0: // currently never do. michael@0: this->writeOp(kSetTypeface_DrawOp); michael@0: fWriter.writePtr(paint.getTypeface()); michael@0: } michael@0: base.setTypeface(paint.getTypeface()); michael@0: } michael@0: michael@0: // This is a new paint, so all old flats can be safely purged, if necessary. michael@0: fFlattenableHeap.markAllFlatsSafeToDelete(); michael@0: for (int i = 0; i < kCount_PaintFlats; i++) { michael@0: int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i); michael@0: bool replaced = index < 0; michael@0: if (replaced) { michael@0: index = ~index; michael@0: } michael@0: // Store the index of any flat that needs to be kept. 0 means no flat. michael@0: if (index > 0) { michael@0: fFlattenableHeap.markFlatForKeeping(index); michael@0: } michael@0: SkASSERT(index >= 0 && index <= fFlatDictionary.count()); michael@0: if (index != fCurrFlatIndex[i] || replaced) { michael@0: *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index); michael@0: fCurrFlatIndex[i] = index; michael@0: } michael@0: } michael@0: michael@0: size_t size = (char*)ptr - (char*)storage; michael@0: if (size && this->needOpBytes(size)) { michael@0: this->writeOp(kPaintOp_DrawOp, 0, size); michael@0: fWriter.write(storage, size); michael@0: for (size_t i = 0; i < size/4; i++) { michael@0: // SkDebugf("[%d] %08X\n", i, storage[i]); michael@0: } michael@0: } michael@0: michael@0: // michael@0: // Do these after we've written kPaintOp_DrawOp michael@0: michael@0: if (base.getAnnotation() != paint.getAnnotation()) { michael@0: if (NULL == paint.getAnnotation()) { michael@0: if (this->needOpBytes()) { michael@0: this->writeOp(kSetAnnotation_DrawOp, 0, 0); michael@0: } michael@0: } else { michael@0: SkWriteBuffer buffer; michael@0: paint.getAnnotation()->writeToBuffer(buffer); michael@0: const size_t size = buffer.bytesWritten(); michael@0: if (this->needOpBytes(size)) { michael@0: this->writeOp(kSetAnnotation_DrawOp, 0, size); michael@0: buffer.writeToMemory(fWriter.reserve(size)); michael@0: } michael@0: } michael@0: base.setAnnotation(paint.getAnnotation()); michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include "SkGPipe.h" michael@0: michael@0: SkGPipeController::~SkGPipeController() { michael@0: SkSafeUnref(fCanvas); michael@0: } michael@0: michael@0: void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) { michael@0: SkRefCnt_SafeAssign(fCanvas, canvas); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkGPipeWriter::SkGPipeWriter() michael@0: : fWriter(0) { michael@0: fCanvas = NULL; michael@0: } michael@0: michael@0: SkGPipeWriter::~SkGPipeWriter() { michael@0: this->endRecording(); michael@0: } michael@0: michael@0: SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags, michael@0: uint32_t width, uint32_t height) { michael@0: if (NULL == fCanvas) { michael@0: fWriter.reset(NULL, 0); michael@0: fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height)); michael@0: } michael@0: controller->setCanvas(fCanvas); michael@0: return fCanvas; michael@0: } michael@0: michael@0: void SkGPipeWriter::endRecording() { michael@0: if (fCanvas) { michael@0: fCanvas->finish(true); michael@0: fCanvas->unref(); michael@0: fCanvas = NULL; michael@0: } michael@0: } michael@0: michael@0: void SkGPipeWriter::flushRecording(bool detachCurrentBlock) { michael@0: if (fCanvas) { michael@0: fCanvas->flushRecording(detachCurrentBlock); michael@0: } michael@0: } michael@0: michael@0: size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) { michael@0: if (fCanvas) { michael@0: return fCanvas->freeMemoryIfPossible(bytesToFree); michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: size_t SkGPipeWriter::storageAllocatedForRecording() const { michael@0: return NULL == fCanvas ? 0 : fCanvas->storageAllocatedForRecording(); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) { michael@0: SkASSERT(canvas != NULL); michael@0: fCanvas = canvas; michael@0: fCanvas->ref(); michael@0: } michael@0: michael@0: BitmapShuttle::~BitmapShuttle() { michael@0: this->removeCanvas(); michael@0: } michael@0: michael@0: bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) { michael@0: SkASSERT(fCanvas != NULL); michael@0: return fCanvas->shuttleBitmap(bitmap, slot); michael@0: } michael@0: michael@0: void BitmapShuttle::removeCanvas() { michael@0: if (NULL == fCanvas) { michael@0: return; michael@0: } michael@0: fCanvas->unref(); michael@0: fCanvas = NULL; michael@0: }