3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 #include "SkAnnotation.h"
10 #include "SkBitmapDevice.h"
11 #include "SkBitmapHeap.h"
13 #include "SkColorFilter.h"
15 #include "SkDrawLooper.h"
17 #include "SkGPipePriv.h"
18 #include "SkImageFilter.h"
19 #include "SkMaskFilter.h"
20 #include "SkWriteBuffer.h"
22 #include "SkPatchUtils.h"
23 #include "SkPathEffect.h"
24 #include "SkPictureFlat.h"
25 #include "SkPtrRecorder.h"
26 #include "SkRasterizer.h"
30 #include "SkTextBlob.h"
31 #include "SkTSearch.h"
32 #include "SkTypeface.h"
33 #include "SkWriter32.h"
36 kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector)
39 static bool is_cross_process(uint32_t flags) {
40 return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag);
43 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
44 SkASSERT(paintFlat < kCount_PaintFlats);
46 case kColorFilter_PaintFlat: return paint.getColorFilter();
47 case kDrawLooper_PaintFlat: return paint.getLooper();
48 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
49 case kPathEffect_PaintFlat: return paint.getPathEffect();
50 case kRasterizer_PaintFlat: return paint.getRasterizer();
51 case kShader_PaintFlat: return paint.getShader();
52 case kImageFilter_PaintFlat: return paint.getImageFilter();
53 case kXfermode_PaintFlat: return paint.getXfermode();
55 SkDEBUGFAIL("never gets here");
59 static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
61 SkDynamicMemoryWStream stream;
62 typeface->serialize(&stream);
63 size_t size = stream.getOffset();
65 writer->write32(SkToU32(size));
66 SkAutoDataUnref data(stream.copyToData());
67 writer->writePad(data->data(), size);
69 return 4 + SkAlign4(size);
72 ///////////////////////////////////////////////////////////////////////////////
74 class FlattenableHeap : public SkFlatController {
76 FlattenableHeap(int numFlatsToKeep, SkNamedFactorySet* fset, bool isCrossProcess)
77 : INHERITED(isCrossProcess ? SkWriteBuffer::kCrossProcess_Flag : 0)
78 , fNumFlatsToKeep(numFlatsToKeep) {
79 SkASSERT((isCrossProcess && fset != NULL) || (!isCrossProcess && NULL == fset));
81 this->setNamedFactorySet(fset);
89 void* allocThrow(size_t bytes) SK_OVERRIDE;
91 void unalloc(void* ptr) SK_OVERRIDE;
93 void setBitmapStorage(SkBitmapHeap* heap) {
94 this->setBitmapHeap(heap);
97 const SkFlatData* flatToReplace() const;
99 // Mark an SkFlatData as one that should not be returned by flatToReplace.
100 // Takes the result of SkFlatData::index() as its parameter.
101 void markFlatForKeeping(int index) {
102 *fFlatsThatMustBeKept.append() = index;
105 void markAllFlatsSafeToDelete() {
106 fFlatsThatMustBeKept.reset();
110 // Keep track of the indices (i.e. the result of SkFlatData::index()) of
111 // flats that must be kept, since they are on the current paint.
112 SkTDArray<int> fFlatsThatMustBeKept;
113 SkTDArray<void*> fPointers;
114 const int fNumFlatsToKeep;
116 typedef SkFlatController INHERITED;
119 void FlattenableHeap::unalloc(void* ptr) {
120 int indexToRemove = fPointers.rfind(ptr);
121 if (indexToRemove >= 0) {
123 fPointers.remove(indexToRemove);
127 void* FlattenableHeap::allocThrow(size_t bytes) {
128 void* ptr = sk_malloc_throw(bytes);
129 *fPointers.append() = ptr;
133 const SkFlatData* FlattenableHeap::flatToReplace() const {
134 // First, determine whether we should replace one.
135 if (fPointers.count() > fNumFlatsToKeep) {
136 // Look through the flattenable heap.
137 // TODO: Return the LRU flat.
138 for (int i = 0; i < fPointers.count(); i++) {
139 SkFlatData* potential = (SkFlatData*)fPointers[i];
140 // Make sure that it is not one that must be kept.
141 bool mustKeep = false;
142 for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) {
143 if (potential->index() == fFlatsThatMustBeKept[j]) {
156 ///////////////////////////////////////////////////////////////////////////////
158 struct SkFlattenableTraits {
159 static void Flatten(SkWriteBuffer& buffer, const SkFlattenable& flattenable) {
160 buffer.writeFlattenable(&flattenable);
162 // No need to define unflatten if we never call it.
164 typedef SkFlatDictionary<SkFlattenable, SkFlattenableTraits> FlatDictionary;
166 ///////////////////////////////////////////////////////////////////////////////
169 * If SkBitmaps are to be flattened to send to the reader, this class is
170 * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
172 class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
174 BitmapShuttle(SkGPipeCanvas*);
178 bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
181 * Remove the SkGPipeCanvas used for insertion. After this, calls to
187 SkGPipeCanvas* fCanvas;
190 ///////////////////////////////////////////////////////////////////////////////
192 class SkGPipeCanvas : public SkCanvas {
194 SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
195 uint32_t width, uint32_t height);
196 virtual ~SkGPipeCanvas();
199 * Called when nothing else is to be written to the stream. Any repeated
202 * @param notifyReaders Whether to send a message to the reader(s) that
203 * the writer is through sending commands. Should generally be true,
204 * unless there is an error which prevents further messages from
207 void finish(bool notifyReaders) {
211 if (notifyReaders && this->needOpBytes()) {
212 this->writeOp(kDone_DrawOp);
215 if (shouldFlattenBitmaps(fFlags)) {
216 // The following circular references exist:
217 // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalStorage -> fCanvas
218 // fBitmapHeap -> fExternalStorage -> fCanvas
219 // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas
221 // Break them all by destroying the final link to this SkGPipeCanvas.
222 fBitmapShuttle->removeCanvas();
227 void flushRecording(bool detachCurrentBlock);
228 size_t freeMemoryIfPossible(size_t bytesToFree);
230 size_t storageAllocatedForRecording() {
231 return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated();
234 void beginCommentGroup(const char* description) SK_OVERRIDE;
235 void addComment(const char* kywd, const char* value) SK_OVERRIDE;
236 void endCommentGroup() SK_OVERRIDE;
239 * Flatten an SkBitmap to send to the reader, where it will be referenced
242 bool shuttleBitmap(const SkBitmap&, int32_t slot);
245 void willSave() SK_OVERRIDE;
246 SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE;
247 void willRestore() SK_OVERRIDE;
249 void didConcat(const SkMatrix&) SK_OVERRIDE;
250 void didSetMatrix(const SkMatrix&) SK_OVERRIDE;
252 void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE;
253 virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
254 const SkPaint&) SK_OVERRIDE;
255 virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
256 const SkPaint&) SK_OVERRIDE;
257 virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
258 SkScalar constY, const SkPaint&) SK_OVERRIDE;
259 virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
260 const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
261 virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
262 const SkPaint& paint) SK_OVERRIDE;
263 virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
264 const SkPoint texCoords[4], SkXfermode* xmode,
265 const SkPaint& paint) SK_OVERRIDE;
266 void onDrawPaint(const SkPaint&) SK_OVERRIDE;
267 void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) SK_OVERRIDE;
268 void onDrawRect(const SkRect&, const SkPaint&) SK_OVERRIDE;
269 void onDrawOval(const SkRect&, const SkPaint&) SK_OVERRIDE;
270 void onDrawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE;
271 void onDrawPath(const SkPath&, const SkPaint&) SK_OVERRIDE;
272 void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) SK_OVERRIDE;
273 void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
274 DrawBitmapRectFlags flags) SK_OVERRIDE;
276 // rely on decomposition into bitmap (for now)
277 void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) SK_OVERRIDE;
278 void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
279 const SkPaint*) SK_OVERRIDE;
281 void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
282 const SkPaint*) SK_OVERRIDE;
283 void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) SK_OVERRIDE;
284 void onDrawVertices(VertexMode vmode, int vertexCount,
285 const SkPoint vertices[], const SkPoint texs[],
286 const SkColor colors[], SkXfermode* xmode,
287 const uint16_t indices[], int indexCount,
288 const SkPaint&) SK_OVERRIDE;
289 void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
290 void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
291 void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
292 void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
294 void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
297 void recordTranslate(const SkMatrix&);
298 void recordScale(const SkMatrix&);
299 void recordConcat(const SkMatrix&);
301 SkNamedFactorySet* fFactorySet;
302 SkBitmapHeap* fBitmapHeap;
303 SkGPipeController* fController;
305 size_t fBlockSize; // amount allocated for writer
306 size_t fBytesNotified;
308 const uint32_t fFlags;
310 SkRefCntSet fTypefaceSet;
312 uint32_t getTypefaceID(SkTypeface*);
314 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
315 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
318 inline void writeOp(DrawOps op) {
319 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
322 bool needOpBytes(size_t size = 0);
324 inline void doNotify() {
326 size_t bytes = fWriter.bytesWritten() - fBytesNotified;
328 fController->notifyWritten(bytes);
329 fBytesNotified += bytes;
334 typedef SkAutoSTMalloc<128, uint8_t> TypefaceBuffer;
335 size_t getInProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*);
336 size_t getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*);
338 // Should be called after any calls to an SkFlatDictionary::findAndReplace
339 // if a new SkFlatData was added when in cross process mode
340 void flattenFactoryNames();
342 FlattenableHeap fFlattenableHeap;
343 FlatDictionary fFlatDictionary;
344 SkAutoTUnref<BitmapShuttle> fBitmapShuttle;
345 int fCurrFlatIndex[kCount_PaintFlats];
347 int flattenToIndex(SkFlattenable* obj, PaintFlats);
349 // Common code used by drawBitmap*. Behaves differently depending on the
350 // type of SkBitmapHeap being used, which is determined by the flags used.
351 bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags,
352 size_t opBytesNeeded, const SkPaint* paint);
355 void writePaint(const SkPaint&);
357 class AutoPipeNotify {
359 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
360 ~AutoPipeNotify() { fCanvas->doNotify(); }
362 SkGPipeCanvas* fCanvas;
364 friend class AutoPipeNotify;
366 typedef SkCanvas INHERITED;
369 void SkGPipeCanvas::flattenFactoryNames() {
371 while ((name = fFactorySet->getNextAddedFactoryName()) != NULL) {
372 size_t len = strlen(name);
373 if (this->needOpBytes(SkWriter32::WriteStringSize(name, len))) {
374 this->writeOp(kDef_Factory_DrawOp);
375 fWriter.writeString(name, len);
380 bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) {
381 SkASSERT(shouldFlattenBitmaps(fFlags));
382 SkWriteBuffer buffer;
383 buffer.setNamedFactoryRecorder(fFactorySet);
384 buffer.writeBitmap(bm);
385 this->flattenFactoryNames();
386 size_t size = buffer.bytesWritten();
387 if (this->needOpBytes(size)) {
388 this->writeOp(kDef_Bitmap_DrawOp, 0, slot);
389 void* dst = static_cast<void*>(fWriter.reserve(size));
390 buffer.writeToMemory(dst);
396 // return 0 for NULL (or unflattenable obj), or index-base-1
397 // return ~(index-base-1) if an old flattenable was replaced
398 int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
399 SkASSERT(!fDone && fBitmapHeap != NULL);
404 fBitmapHeap->deferAddingOwners();
405 bool added, replaced;
406 const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHeap.flatToReplace(),
408 fBitmapHeap->endAddingOwnersDeferral(added);
409 int index = flat->index();
411 if (is_cross_process(fFlags)) {
412 this->flattenFactoryNames();
414 size_t flatSize = flat->flatSize();
415 if (this->needOpBytes(flatSize)) {
416 this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
417 fWriter.write(flat->data(), flatSize);
426 ///////////////////////////////////////////////////////////////////////////////
428 #define MIN_BLOCK_SIZE (16 * 1024)
429 #define BITMAPS_TO_KEEP 5
430 #define FLATTENABLES_TO_KEEP 10
432 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
433 SkWriter32* writer, uint32_t flags,
434 uint32_t width, uint32_t height)
435 : SkCanvas(width, height)
436 , fFactorySet(is_cross_process(flags) ? SkNEW(SkNamedFactorySet) : NULL)
439 , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags))
440 , fFlatDictionary(&fFlattenableHeap)
442 fController = controller;
444 fBlockSize = 0; // need first block from controller
446 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
448 // Tell the reader the appropriate flags to use.
449 if (this->needOpBytes()) {
450 this->writeOp(kReportFlags_DrawOp, fFlags, 0);
453 if (shouldFlattenBitmaps(flags)) {
454 fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this)));
455 fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO_KEEP));
457 fBitmapHeap = SkNEW_ARGS(SkBitmapHeap,
458 (BITMAPS_TO_KEEP, controller->numberOfReaders()));
459 if (this->needOpBytes(sizeof(void*))) {
460 this->writeOp(kShareBitmapHeap_DrawOp);
461 fWriter.writePtr(static_cast<void*>(fBitmapHeap));
464 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
468 SkGPipeCanvas::~SkGPipeCanvas() {
470 SkSafeUnref(fFactorySet);
471 SkSafeUnref(fBitmapHeap);
474 bool SkGPipeCanvas::needOpBytes(size_t needed) {
479 needed += 4; // size of DrawOp atom
480 needed = SkAlign4(needed);
481 if (fWriter.bytesWritten() + needed > fBlockSize) {
482 // Before we wipe out any data that has already been written, read it out.
485 // If we're going to allocate a new block, allocate enough to make it worthwhile.
486 needed = SkTMax<size_t>(MIN_BLOCK_SIZE, needed);
488 void* block = fController->requestBlock(needed, &fBlockSize);
490 // Do not notify the readers, which would call this function again.
494 SkASSERT(SkIsAlign4(fBlockSize));
495 fWriter.reset(block, fBlockSize);
501 uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
502 uint32_t id = 0; // 0 means default/null typeface
504 id = fTypefaceSet.find(face);
506 id = fTypefaceSet.add(face);
507 size_t size = writeTypeface(NULL, face);
508 if (this->needOpBytes(size)) {
509 this->writeOp(kDef_Typeface_DrawOp);
510 writeTypeface(&fWriter, face);
517 ///////////////////////////////////////////////////////////////////////////////
519 #define NOTIFY_SETUP(canvas) \
520 AutoPipeNotify apn(canvas)
522 void SkGPipeCanvas::willSave() {
524 if (this->needOpBytes()) {
525 this->writeOp(kSave_DrawOp);
528 this->INHERITED::willSave();
531 SkCanvas::SaveLayerStrategy SkGPipeCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
532 SaveFlags saveFlags) {
535 unsigned opFlags = 0;
538 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
539 size += sizeof(SkRect);
542 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
543 this->writePaint(*paint);
546 if (this->needOpBytes(size)) {
547 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
549 fWriter.writeRect(*bounds);
553 this->INHERITED::willSaveLayer(bounds, paint, saveFlags);
554 // we don't create a layer
555 return kNoLayer_SaveLayerStrategy;
558 void SkGPipeCanvas::willRestore() {
560 if (this->needOpBytes()) {
561 this->writeOp(kRestore_DrawOp);
564 this->INHERITED::willRestore();
567 void SkGPipeCanvas::recordTranslate(const SkMatrix& m) {
568 if (this->needOpBytes(2 * sizeof(SkScalar))) {
569 this->writeOp(kTranslate_DrawOp);
570 fWriter.writeScalar(m.getTranslateX());
571 fWriter.writeScalar(m.getTranslateY());
575 void SkGPipeCanvas::recordScale(const SkMatrix& m) {
576 if (this->needOpBytes(2 * sizeof(SkScalar))) {
577 this->writeOp(kScale_DrawOp);
578 fWriter.writeScalar(m.getScaleX());
579 fWriter.writeScalar(m.getScaleY());
583 void SkGPipeCanvas::recordConcat(const SkMatrix& m) {
584 if (this->needOpBytes(m.writeToMemory(NULL))) {
585 this->writeOp(kConcat_DrawOp);
586 fWriter.writeMatrix(m);
590 void SkGPipeCanvas::didConcat(const SkMatrix& matrix) {
591 if (!matrix.isIdentity()) {
593 switch (matrix.getType()) {
594 case SkMatrix::kTranslate_Mask:
595 this->recordTranslate(matrix);
597 case SkMatrix::kScale_Mask:
598 this->recordScale(matrix);
601 this->recordConcat(matrix);
606 this->INHERITED::didConcat(matrix);
609 void SkGPipeCanvas::didSetMatrix(const SkMatrix& matrix) {
611 if (this->needOpBytes(matrix.writeToMemory(NULL))) {
612 this->writeOp(kSetMatrix_DrawOp);
613 fWriter.writeMatrix(matrix);
615 this->INHERITED::didSetMatrix(matrix);
618 void SkGPipeCanvas::onClipRect(const SkRect& rect, SkRegion::Op rgnOp,
619 ClipEdgeStyle edgeStyle) {
621 if (this->needOpBytes(sizeof(SkRect))) {
623 if (kSoft_ClipEdgeStyle == edgeStyle) {
624 flags = kClip_HasAntiAlias_DrawOpFlag;
626 this->writeOp(kClipRect_DrawOp, flags, rgnOp);
627 fWriter.writeRect(rect);
629 this->INHERITED::onClipRect(rect, rgnOp, edgeStyle);
632 void SkGPipeCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op rgnOp,
633 ClipEdgeStyle edgeStyle) {
635 if (this->needOpBytes(kSizeOfFlatRRect)) {
637 if (kSoft_ClipEdgeStyle == edgeStyle) {
638 flags = kClip_HasAntiAlias_DrawOpFlag;
640 this->writeOp(kClipRRect_DrawOp, flags, rgnOp);
641 fWriter.writeRRect(rrect);
643 this->INHERITED::onClipRRect(rrect, rgnOp, edgeStyle);
646 void SkGPipeCanvas::onClipPath(const SkPath& path, SkRegion::Op rgnOp,
647 ClipEdgeStyle edgeStyle) {
649 if (this->needOpBytes(path.writeToMemory(NULL))) {
651 if (kSoft_ClipEdgeStyle == edgeStyle) {
652 flags = kClip_HasAntiAlias_DrawOpFlag;
654 this->writeOp(kClipPath_DrawOp, flags, rgnOp);
655 fWriter.writePath(path);
657 // we just pass on the bounds of the path
658 this->INHERITED::onClipRect(path.getBounds(), rgnOp, edgeStyle);
661 void SkGPipeCanvas::onClipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
663 if (this->needOpBytes(region.writeToMemory(NULL))) {
664 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
665 fWriter.writeRegion(region);
667 this->INHERITED::onClipRegion(region, rgnOp);
670 ///////////////////////////////////////////////////////////////////////////////
672 void SkGPipeCanvas::onDrawPaint(const SkPaint& paint) {
674 this->writePaint(paint);
675 if (this->needOpBytes()) {
676 this->writeOp(kDrawPaint_DrawOp);
680 void SkGPipeCanvas::onDrawPoints(PointMode mode, size_t count,
681 const SkPoint pts[], const SkPaint& paint) {
684 this->writePaint(paint);
685 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
686 this->writeOp(kDrawPoints_DrawOp, mode, 0);
687 fWriter.write32(SkToU32(count));
688 fWriter.write(pts, count * sizeof(SkPoint));
693 void SkGPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
695 this->writePaint(paint);
696 if (this->needOpBytes(sizeof(SkRect))) {
697 this->writeOp(kDrawOval_DrawOp);
698 fWriter.writeRect(rect);
702 void SkGPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
704 this->writePaint(paint);
705 if (this->needOpBytes(sizeof(SkRect))) {
706 this->writeOp(kDrawRect_DrawOp);
707 fWriter.writeRect(rect);
711 void SkGPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
713 this->writePaint(paint);
714 if (this->needOpBytes(kSizeOfFlatRRect)) {
715 this->writeOp(kDrawRRect_DrawOp);
716 fWriter.writeRRect(rrect);
720 void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
721 const SkPaint& paint) {
723 this->writePaint(paint);
724 if (this->needOpBytes(kSizeOfFlatRRect * 2)) {
725 this->writeOp(kDrawDRRect_DrawOp);
726 fWriter.writeRRect(outer);
727 fWriter.writeRRect(inner);
731 void SkGPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
733 this->writePaint(paint);
734 if (this->needOpBytes(path.writeToMemory(NULL))) {
735 this->writeOp(kDrawPath_DrawOp);
736 fWriter.writePath(path);
740 bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op,
742 size_t opBytesNeeded,
743 const SkPaint* paint) {
749 flags |= kDrawBitmap_HasPaint_DrawOpFlag;
750 this->writePaint(*paint);
752 // This needs to run first so its calls to needOpBytes() and its writes
753 // don't interlace with the needOpBytes() and write below.
754 SkASSERT(fBitmapHeap != NULL);
755 int32_t bitmapIndex = fBitmapHeap->insert(bm);
756 if (SkBitmapHeap::INVALID_SLOT == bitmapIndex) {
760 if (this->needOpBytes(opBytesNeeded)) {
761 this->writeOp(op, flags, bitmapIndex);
767 void SkGPipeCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
768 const SkPaint* paint) {
770 size_t opBytesNeeded = sizeof(SkScalar) * 2;
772 if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint)) {
773 fWriter.writeScalar(left);
774 fWriter.writeScalar(top);
778 void SkGPipeCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
779 const SkPaint* paint, DrawBitmapRectFlags dbmrFlags) {
781 size_t opBytesNeeded = sizeof(SkRect);
782 bool hasSrc = src != NULL;
785 flags = kDrawBitmap_HasSrcRect_DrawOpFlag;
786 opBytesNeeded += sizeof(int32_t) * 4;
790 if (dbmrFlags & kBleed_DrawBitmapRectFlag) {
791 flags |= kDrawBitmap_Bleed_DrawOpFlag;
794 if (this->commonDrawBitmap(bm, kDrawBitmapRectToRect_DrawOp, flags, opBytesNeeded, paint)) {
796 fWriter.writeRect(*src);
798 fWriter.writeRect(dst);
802 void SkGPipeCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center,
803 const SkRect& dst, const SkPaint* paint) {
805 size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect);
807 if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, paint)) {
808 fWriter.write32(center.fLeft);
809 fWriter.write32(center.fTop);
810 fWriter.write32(center.fRight);
811 fWriter.write32(center.fBottom);
812 fWriter.writeRect(dst);
816 void SkGPipeCanvas::onDrawSprite(const SkBitmap& bm, int left, int top, const SkPaint* paint) {
818 size_t opBytesNeeded = sizeof(int32_t) * 2;
820 if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) {
821 fWriter.write32(left);
822 fWriter.write32(top);
826 void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
827 const SkPaint& paint) {
830 this->writePaint(paint);
831 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
832 this->writeOp(kDrawText_DrawOp);
833 fWriter.write32(SkToU32(byteLength));
834 fWriter.writePad(text, byteLength);
835 fWriter.writeScalar(x);
836 fWriter.writeScalar(y);
841 void SkGPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
842 const SkPaint& paint) {
845 this->writePaint(paint);
846 int count = paint.textToGlyphs(text, byteLength, NULL);
847 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
848 this->writeOp(kDrawPosText_DrawOp);
849 fWriter.write32(SkToU32(byteLength));
850 fWriter.writePad(text, byteLength);
851 fWriter.write32(count);
852 fWriter.write(pos, count * sizeof(SkPoint));
857 void SkGPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
858 SkScalar constY, const SkPaint& paint) {
861 this->writePaint(paint);
862 int count = paint.textToGlyphs(text, byteLength, NULL);
863 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
864 this->writeOp(kDrawPosTextH_DrawOp);
865 fWriter.write32(SkToU32(byteLength));
866 fWriter.writePad(text, byteLength);
867 fWriter.write32(count);
868 fWriter.write(xpos, count * sizeof(SkScalar));
869 fWriter.writeScalar(constY);
874 void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
875 const SkMatrix* matrix, const SkPaint& paint) {
879 size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(NULL);
881 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
882 size += matrix->writeToMemory(NULL);
884 this->writePaint(paint);
885 if (this->needOpBytes(size)) {
886 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
888 fWriter.write32(SkToU32(byteLength));
889 fWriter.writePad(text, byteLength);
891 fWriter.writePath(path);
893 fWriter.writeMatrix(*matrix);
899 size_t SkGPipeCanvas::getInProcessTypefaces(const SkRefCntSet& typefaceSet,
900 TypefaceBuffer* buffer) {
901 // When in-process, we simply write out the typeface pointers.
902 size_t size = typefaceSet.count() * sizeof(SkTypeface*);
904 typefaceSet.copyToArray(reinterpret_cast<SkRefCnt**>(buffer->get()));
909 size_t SkGPipeCanvas::getCrossProcessTypefaces(const SkRefCntSet& typefaceSet,
910 TypefaceBuffer* buffer) {
911 // For cross-process we use typeface IDs.
912 size_t size = typefaceSet.count() * sizeof(uint32_t);
915 uint32_t* idBuffer = reinterpret_cast<uint32_t*>(buffer->get());
916 SkRefCntSet::Iter iter(typefaceSet);
919 for (void* setPtr = iter.next(); setPtr; setPtr = iter.next()) {
920 idBuffer[i++] = this->getTypefaceID(reinterpret_cast<SkTypeface*>(setPtr));
923 SkASSERT(i == typefaceSet.count());
928 void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
929 const SkPaint& paint) {
931 this->writePaint(paint);
933 // FIXME: this is inefficient but avoids duplicating the blob serialization logic.
934 SkRefCntSet typefaceSet;
935 SkWriteBuffer blobBuffer;
936 blobBuffer.setTypefaceRecorder(&typefaceSet);
937 blob->flatten(blobBuffer);
939 // Unlike most draw ops (which only use one paint/typeface), text blobs may reference
940 // an arbitrary number of typefaces. Since the one-paint-per-op model is not applicable,
941 // we need to serialize these explicitly.
942 TypefaceBuffer typefaceBuffer;
943 size_t typefaceSize = is_cross_process(fFlags)
944 ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer)
945 : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer);
947 // blob byte count + typeface count + x + y + blob data + an index (cross-process)
948 // or pointer (in-process) for each typeface
949 size_t size = 2 * sizeof(uint32_t)
950 + 2 * sizeof(SkScalar)
951 + blobBuffer.bytesWritten()
954 if (this->needOpBytes(size)) {
955 this->writeOp(kDrawTextBlob_DrawOp);
956 SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();)
958 fWriter.writeScalar(x);
959 fWriter.writeScalar(y);
961 fWriter.write32(typefaceSet.count());
962 fWriter.write(typefaceBuffer.get(), typefaceSize);
964 fWriter.write32(SkToU32(blobBuffer.bytesWritten()));
965 uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten());
966 blobBuffer.writeToMemory(pad);
968 SkASSERT(initialOffset + size == fWriter.bytesWritten());
972 void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
973 const SkPaint* paint) {
974 // we want to playback the picture into individual draw calls
976 // todo: do we always have to unroll? If the pipe is not cross-process, seems like
977 // we could just ref the picture and move on...? <reed, scroggo>
979 this->INHERITED::onDrawPicture(picture, matrix, paint);
982 void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
983 const SkPoint vertices[], const SkPoint texs[],
984 const SkColor colors[], SkXfermode* xfer,
985 const uint16_t indices[], int indexCount,
986 const SkPaint& paint) {
987 if (0 == vertexCount) {
992 this->writePaint(paint);
994 unsigned flags = 0; // packs with the op, so needs no extra space
998 size += 4; // vertex count
999 size += vertexCount * sizeof(SkPoint); // vertices
1002 flags |= kDrawVertices_HasTexs_DrawOpFlag;
1003 size += vertexCount * sizeof(SkPoint);
1006 flags |= kDrawVertices_HasColors_DrawOpFlag;
1007 size += vertexCount * sizeof(SkColor);
1009 if (xfer && !SkXfermode::IsMode(xfer, SkXfermode::kModulate_Mode)) {
1010 flags |= kDrawVertices_HasXfermode_DrawOpFlag;
1011 size += sizeof(int32_t); // SkXfermode::Mode
1013 if (indices && indexCount > 0) {
1014 flags |= kDrawVertices_HasIndices_DrawOpFlag;
1015 size += 4; // index count
1016 size += SkAlign4(indexCount * sizeof(uint16_t)); // indices
1019 if (this->needOpBytes(size)) {
1020 this->writeOp(kDrawVertices_DrawOp, flags, 0);
1021 fWriter.write32(vmode);
1022 fWriter.write32(vertexCount);
1023 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
1024 if (flags & kDrawVertices_HasTexs_DrawOpFlag) {
1025 fWriter.write(texs, vertexCount * sizeof(SkPoint));
1027 if (flags & kDrawVertices_HasColors_DrawOpFlag) {
1028 fWriter.write(colors, vertexCount * sizeof(SkColor));
1030 if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
1031 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1032 SkAssertResult(xfer->asMode(&mode));
1033 fWriter.write32(mode);
1035 if (flags & kDrawVertices_HasIndices_DrawOpFlag) {
1036 fWriter.write32(indexCount);
1037 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1042 void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
1043 const SkPoint texCoords[4], SkXfermode* xmode,
1044 const SkPaint& paint) {
1047 size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint);
1050 flags |= kDrawVertices_HasColors_DrawOpFlag;
1051 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
1054 flags |= kDrawVertices_HasTexs_DrawOpFlag;
1055 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
1058 SkXfermode::Mode mode;
1059 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1060 flags |= kDrawVertices_HasXfermode_DrawOpFlag;
1061 size += sizeof(int32_t);
1065 this->writePaint(paint);
1066 if (this->needOpBytes(size)) {
1067 this->writeOp(kDrawPatch_DrawOp, flags, 0);
1069 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
1072 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
1076 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
1079 if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
1080 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1081 SkAssertResult(xmode->asMode(&mode));
1082 fWriter.write32(mode);
1087 void SkGPipeCanvas::beginCommentGroup(const char* description) {
1091 void SkGPipeCanvas::addComment(const char* kywd, const char* value) {
1095 void SkGPipeCanvas::endCommentGroup() {
1099 void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) {
1101 if (detachCurrentBlock) {
1102 // force a new block to be requested for the next recorded command
1107 size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) {
1108 return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->freeMemoryIfPossible(bytesToFree);
1111 ///////////////////////////////////////////////////////////////////////////////
1113 template <typename T> uint32_t castToU32(T value) {
1122 void SkGPipeCanvas::writePaint(const SkPaint& paint) {
1126 SkPaint& base = fPaint;
1127 uint32_t storage[32];
1128 uint32_t* ptr = storage;
1130 if (base.getFlags() != paint.getFlags()) {
1131 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
1132 base.setFlags(paint.getFlags());
1134 if (base.getColor() != paint.getColor()) {
1135 *ptr++ = PaintOp_packOp(kColor_PaintOp);
1136 *ptr++ = paint.getColor();
1137 base.setColor(paint.getColor());
1139 if (base.getFilterQuality() != paint.getFilterQuality()) {
1140 *ptr++ = PaintOp_packOpData(kFilterLevel_PaintOp, paint.getFilterQuality());
1141 base.setFilterQuality(paint.getFilterQuality());
1143 if (base.getStyle() != paint.getStyle()) {
1144 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
1145 base.setStyle(paint.getStyle());
1147 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
1148 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
1149 base.setStrokeJoin(paint.getStrokeJoin());
1151 if (base.getStrokeCap() != paint.getStrokeCap()) {
1152 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
1153 base.setStrokeCap(paint.getStrokeCap());
1155 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
1156 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
1157 *ptr++ = castToU32(paint.getStrokeWidth());
1158 base.setStrokeWidth(paint.getStrokeWidth());
1160 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
1161 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
1162 *ptr++ = castToU32(paint.getStrokeMiter());
1163 base.setStrokeMiter(paint.getStrokeMiter());
1165 if (base.getTextEncoding() != paint.getTextEncoding()) {
1166 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
1167 base.setTextEncoding(paint.getTextEncoding());
1169 if (base.getHinting() != paint.getHinting()) {
1170 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
1171 base.setHinting(paint.getHinting());
1173 if (base.getTextAlign() != paint.getTextAlign()) {
1174 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
1175 base.setTextAlign(paint.getTextAlign());
1177 if (base.getTextSize() != paint.getTextSize()) {
1178 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
1179 *ptr++ = castToU32(paint.getTextSize());
1180 base.setTextSize(paint.getTextSize());
1182 if (base.getTextScaleX() != paint.getTextScaleX()) {
1183 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
1184 *ptr++ = castToU32(paint.getTextScaleX());
1185 base.setTextScaleX(paint.getTextScaleX());
1187 if (base.getTextSkewX() != paint.getTextSkewX()) {
1188 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
1189 *ptr++ = castToU32(paint.getTextSkewX());
1190 base.setTextSkewX(paint.getTextSkewX());
1193 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
1194 if (is_cross_process(fFlags)) {
1195 uint32_t id = this->getTypefaceID(paint.getTypeface());
1196 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
1197 } else if (this->needOpBytes(sizeof(void*))) {
1198 // Add to the set for ref counting.
1199 fTypefaceSet.add(paint.getTypeface());
1200 // It is safe to write the typeface to the stream before the rest
1201 // of the paint unless we ever send a kReset_PaintOp, which we
1202 // currently never do.
1203 this->writeOp(kSetTypeface_DrawOp);
1204 fWriter.writePtr(paint.getTypeface());
1206 base.setTypeface(paint.getTypeface());
1209 // This is a new paint, so all old flats can be safely purged, if necessary.
1210 fFlattenableHeap.markAllFlatsSafeToDelete();
1211 for (int i = 0; i < kCount_PaintFlats; i++) {
1212 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
1213 bool replaced = index < 0;
1217 // Store the index of any flat that needs to be kept. 0 means no flat.
1219 fFlattenableHeap.markFlatForKeeping(index);
1221 SkASSERT(index >= 0 && index <= fFlatDictionary.count());
1222 if (index != fCurrFlatIndex[i] || replaced) {
1223 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
1224 fCurrFlatIndex[i] = index;
1228 size_t size = (char*)ptr - (char*)storage;
1229 if (size && this->needOpBytes(size)) {
1230 this->writeOp(kPaintOp_DrawOp, 0, SkToU32(size));
1231 fWriter.write(storage, size);
1232 for (size_t i = 0; i < size/4; i++) {
1233 // SkDebugf("[%d] %08X\n", i, storage[i]);
1238 // Do these after we've written kPaintOp_DrawOp
1240 if (base.getAnnotation() != paint.getAnnotation()) {
1241 if (NULL == paint.getAnnotation()) {
1242 if (this->needOpBytes()) {
1243 this->writeOp(kSetAnnotation_DrawOp, 0, 0);
1246 SkWriteBuffer buffer;
1247 paint.getAnnotation()->writeToBuffer(buffer);
1248 const size_t size = buffer.bytesWritten();
1249 if (this->needOpBytes(size)) {
1250 this->writeOp(kSetAnnotation_DrawOp, 0, SkToU32(size));
1251 buffer.writeToMemory(fWriter.reserve(size));
1254 base.setAnnotation(paint.getAnnotation());
1258 ///////////////////////////////////////////////////////////////////////////////
1260 #include "SkGPipe.h"
1262 SkGPipeController::~SkGPipeController() {
1263 SkSafeUnref(fCanvas);
1266 void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) {
1267 SkRefCnt_SafeAssign(fCanvas, canvas);
1270 ///////////////////////////////////////////////////////////////////////////////
1272 SkGPipeWriter::SkGPipeWriter()
1277 SkGPipeWriter::~SkGPipeWriter() {
1278 this->endRecording();
1281 SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags,
1282 uint32_t width, uint32_t height) {
1283 if (NULL == fCanvas) {
1284 fWriter.reset(NULL, 0);
1285 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height));
1287 controller->setCanvas(fCanvas);
1291 void SkGPipeWriter::endRecording() {
1293 fCanvas->finish(true);
1299 void SkGPipeWriter::flushRecording(bool detachCurrentBlock) {
1301 fCanvas->flushRecording(detachCurrentBlock);
1305 size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) {
1307 return fCanvas->freeMemoryIfPossible(bytesToFree);
1312 size_t SkGPipeWriter::storageAllocatedForRecording() const {
1313 return NULL == fCanvas ? 0 : fCanvas->storageAllocatedForRecording();
1316 ///////////////////////////////////////////////////////////////////////////////
1318 BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) {
1319 SkASSERT(canvas != NULL);
1324 BitmapShuttle::~BitmapShuttle() {
1325 this->removeCanvas();
1328 bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) {
1329 SkASSERT(fCanvas != NULL);
1330 return fCanvas->shuttleBitmap(bitmap, slot);
1333 void BitmapShuttle::removeCanvas() {
1334 if (NULL == fCanvas) {