blob: e546b5c5927a0649415e5c41ce170bbf14d9f9be [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.combb6992a2011-04-26 17:41:56 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.combb6992a2011-04-26 17:41:56 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.combb6992a2011-04-26 17:41:56 +000011#include "SkCanvas.h"
reed@google.com8a85d0c2011-06-24 19:12:12 +000012#include "SkData.h"
reed@google.combb6793b2011-05-05 15:18:15 +000013#include "SkDevice.h"
reed@google.combb6992a2011-04-26 17:41:56 +000014#include "SkPaint.h"
reed@google.com75a09722012-05-10 12:56:16 +000015#include "SkPathEffect.h"
reed@google.comacd471f2011-05-03 21:26:46 +000016#include "SkGPipe.h"
reed@google.combb6992a2011-04-26 17:41:56 +000017#include "SkGPipePriv.h"
scroggo@google.com16d1d0b2012-05-02 19:09:40 +000018#include "SkImageFilter.h"
reed@google.comf5842f72011-05-04 18:30:04 +000019#include "SkStream.h"
reed@google.comb55d1182011-05-11 00:42:04 +000020#include "SkTSearch.h"
reed@google.comf5842f72011-05-04 18:30:04 +000021#include "SkTypeface.h"
reed@google.combb6992a2011-04-26 17:41:56 +000022#include "SkWriter32.h"
reed@google.comb55d1182011-05-11 00:42:04 +000023#include "SkColorFilter.h"
reed@google.com0faac1e2011-05-11 05:58:58 +000024#include "SkDrawLooper.h"
reed@google.comb55d1182011-05-11 00:42:04 +000025#include "SkMaskFilter.h"
26#include "SkRasterizer.h"
27#include "SkShader.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000028#include "SkOrderedWriteBuffer.h"
reed@google.comb55d1182011-05-11 00:42:04 +000029
30static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
31 SkASSERT(paintFlat < kCount_PaintFlats);
32 switch (paintFlat) {
33 case kColorFilter_PaintFlat: return paint.getColorFilter();
reed@google.com0faac1e2011-05-11 05:58:58 +000034 case kDrawLooper_PaintFlat: return paint.getLooper();
reed@google.comb55d1182011-05-11 00:42:04 +000035 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
36 case kPathEffect_PaintFlat: return paint.getPathEffect();
37 case kRasterizer_PaintFlat: return paint.getRasterizer();
38 case kShader_PaintFlat: return paint.getShader();
scroggo@google.com16d1d0b2012-05-02 19:09:40 +000039 case kImageFilter_PaintFlat: return paint.getImageFilter();
reed@google.comb55d1182011-05-11 00:42:04 +000040 case kXfermode_PaintFlat: return paint.getXfermode();
41 }
tomhudson@google.com0c00f212011-12-28 14:59:50 +000042 SkDEBUGFAIL("never gets here");
reed@google.comb55d1182011-05-11 00:42:04 +000043 return NULL;
44}
reed@google.combb6992a2011-04-26 17:41:56 +000045
reed@google.comf5842f72011-05-04 18:30:04 +000046static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
47 SkASSERT(typeface);
48 SkDynamicMemoryWStream stream;
49 typeface->serialize(&stream);
50 size_t size = stream.getOffset();
51 if (writer) {
52 writer->write32(size);
reed@google.com8a85d0c2011-06-24 19:12:12 +000053 SkAutoDataUnref data(stream.copyToData());
robertphillips@google.com59f46b82012-07-10 17:30:58 +000054 writer->writePad(data->data(), size);
reed@google.comf5842f72011-05-04 18:30:04 +000055 }
scroggo@google.com5af9b202012-06-04 17:17:36 +000056 return 4 + SkAlign4(size);
reed@google.comf5842f72011-05-04 18:30:04 +000057}
58
reed@google.combb6992a2011-04-26 17:41:56 +000059///////////////////////////////////////////////////////////////////////////////
60
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +000061/*
62 * Shared heap for storing large things that can be shared, for a stream
63 * used by multiple readers.
64 * TODO: Make the allocations all come from cross process safe address space
65 * TODO: Store paths (others?)
66 * TODO: Allow reclaiming of memory. Will require us to know when all readers
67 * have used the object.
68 */
69class Heap {
70public:
scroggo@google.com565254b2012-06-28 15:41:32 +000071 Heap(bool shallow) : fCanDoShallowCopies(shallow) {}
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +000072 ~Heap() {
73 for (int i = 0; i < fBitmaps.count(); i++) {
74 delete fBitmaps[i].fBitmap;
75 }
76 }
77
78 /*
79 * Add a copy of a bitmap to the heap.
80 * @param bm The SkBitmap to be copied and placed in the heap.
81 * @return void* Pointer to the heap's copy of the bitmap. If NULL,
82 * the bitmap could not be copied.
83 */
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +000084 const SkBitmap* addBitmap(const SkBitmap& orig) {
85 const uint32_t genID = orig.getGenerationID();
86 SkPixelRef* sharedPixelRef = NULL;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +000087 for (int i = fBitmaps.count() - 1; i >= 0; i--) {
scroggo@google.com6ea165d2012-07-03 14:52:08 +000088 SkBitmap* storedBitmap = fBitmaps[i].fBitmap;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +000089 if (genID == fBitmaps[i].fGenID) {
scroggo@google.com6ea165d2012-07-03 14:52:08 +000090 if (orig.pixelRefOffset() != storedBitmap->pixelRefOffset()
91 || orig.width() != storedBitmap->width()
92 || orig.height() != storedBitmap->height()) {
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +000093 // In this case, the bitmaps share a pixelRef, but have
scroggo@google.com6ea165d2012-07-03 14:52:08 +000094 // different offsets or sizes. Keep track of the other
95 // bitmap so that instead of making another copy of the
96 // pixelRef we can use the copy we already made.
97 sharedPixelRef = storedBitmap->pixelRef();
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +000098 break;
99 }
scroggo@google.com6ea165d2012-07-03 14:52:08 +0000100 return storedBitmap;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000101 }
102 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000103 SkBitmap* copy;
104 // If the bitmap is mutable, we still need to do a deep copy, since the
105 // caller may modify it afterwards. That said, if the bitmap is mutable,
106 // but has no pixelRef, the copy constructor actually does a deep copy.
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +0000107 if (fCanDoShallowCopies && (orig.isImmutable() || !orig.pixelRef())) {
108 copy = new SkBitmap(orig);
scroggo@google.com565254b2012-06-28 15:41:32 +0000109 } else {
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +0000110 if (sharedPixelRef != NULL) {
111 // Do a shallow copy of the bitmap to get the width, height, etc
112 copy = new SkBitmap(orig);
113 // Replace the pixelRef with the copy that was already made, and
114 // use the appropriate offset.
115 copy->setPixelRef(sharedPixelRef, orig.pixelRefOffset());
116 } else {
117 copy = new SkBitmap();
118 if (!orig.copyTo(copy, orig.getConfig())) {
119 delete copy;
120 return NULL;
121 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000122 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000123 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000124 BitmapInfo* info = fBitmaps.append();
125 info->fBitmap = copy;
126 info->fGenID = genID;
127 return copy;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000128 }
129private:
130 struct BitmapInfo {
131 SkBitmap* fBitmap;
132 // Store the generation ID of the original bitmap, since copying does
133 // not copy this field, so fBitmap's generation ID will not be useful
134 // for comparing.
135 uint32_t fGenID;
136 };
scroggo@google.com565254b2012-06-28 15:41:32 +0000137 SkTDArray<BitmapInfo> fBitmaps;
138 const bool fCanDoShallowCopies;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000139};
140
141///////////////////////////////////////////////////////////////////////////////
142
reed@google.combb6992a2011-04-26 17:41:56 +0000143class SkGPipeCanvas : public SkCanvas {
144public:
scroggo@google.com565254b2012-06-28 15:41:32 +0000145 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*, uint32_t flags);
reed@google.combb6992a2011-04-26 17:41:56 +0000146 virtual ~SkGPipeCanvas();
147
148 void finish() {
149 if (!fDone) {
reed@google.comdbccc882011-07-08 18:53:39 +0000150 if (this->needOpBytes()) {
151 this->writeOp(kDone_DrawOp);
152 this->doNotify();
153 }
reed@google.combb6992a2011-04-26 17:41:56 +0000154 fDone = true;
155 }
156 }
157
158 // overrides from SkCanvas
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000159 virtual int save(SaveFlags) SK_OVERRIDE;
160 virtual int saveLayer(const SkRect* bounds, const SkPaint*,
161 SaveFlags) SK_OVERRIDE;
162 virtual void restore() SK_OVERRIDE;
163 virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
164 virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
165 virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
166 virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
167 virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
168 virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
169 virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
170 bool doAntiAlias = false) SK_OVERRIDE;
171 virtual bool clipPath(const SkPath& path, SkRegion::Op op,
172 bool doAntiAlias = false) SK_OVERRIDE;
173 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op) SK_OVERRIDE;
174 virtual void clear(SkColor) SK_OVERRIDE;
175 virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000176 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000177 const SkPaint&) SK_OVERRIDE;
178 virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE;
179 virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000180 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000181 const SkPaint*) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000182 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000183 const SkRect& dst, const SkPaint*) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000184 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000185 const SkPaint*) SK_OVERRIDE;
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000186 virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
187 const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000188 virtual void drawSprite(const SkBitmap&, int left, int top,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000189 const SkPaint*) SK_OVERRIDE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000190 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000191 SkScalar y, const SkPaint&) SK_OVERRIDE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000192 virtual void drawPosText(const void* text, size_t byteLength,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000193 const SkPoint pos[], const SkPaint&) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000194 virtual void drawPosTextH(const void* text, size_t byteLength,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000195 const SkScalar xpos[], SkScalar constY,
196 const SkPaint&) SK_OVERRIDE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000197 virtual void drawTextOnPath(const void* text, size_t byteLength,
198 const SkPath& path, const SkMatrix* matrix,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000199 const SkPaint&) SK_OVERRIDE;
200 virtual void drawPicture(SkPicture& picture) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000201 virtual void drawVertices(VertexMode, int vertexCount,
202 const SkPoint vertices[], const SkPoint texs[],
203 const SkColor colors[], SkXfermode*,
204 const uint16_t indices[], int indexCount,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000205 const SkPaint&) SK_OVERRIDE;
206 virtual void drawData(const void*, size_t) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000207
208private:
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000209 Heap fHeap;
reed@google.comdde09562011-05-23 12:21:05 +0000210 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000211 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000212 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000213 size_t fBlockSize; // amount allocated for writer
214 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000215 bool fDone;
scroggo@google.com565254b2012-06-28 15:41:32 +0000216 uint32_t fFlags;
reed@google.combb6992a2011-04-26 17:41:56 +0000217
reed@google.comf5842f72011-05-04 18:30:04 +0000218 SkRefCntSet fTypefaceSet;
219
220 uint32_t getTypefaceID(SkTypeface*);
221
reed@google.comacd471f2011-05-03 21:26:46 +0000222 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000223 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
224 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000225
reed@google.comacd471f2011-05-03 21:26:46 +0000226 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000227 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
228 }
reed@google.comacd471f2011-05-03 21:26:46 +0000229
230 bool needOpBytes(size_t size = 0);
231
232 inline void doNotify() {
233 if (!fDone) {
234 size_t bytes = fWriter.size() - fBytesNotified;
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000235 if (bytes > 0) {
236 fController->notifyWritten(bytes);
237 fBytesNotified += bytes;
238 }
reed@google.comacd471f2011-05-03 21:26:46 +0000239 }
240 }
reed@google.comb55d1182011-05-11 00:42:04 +0000241
242 struct FlatData {
243 uint32_t fIndex; // always > 0
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000244 PaintFlats fPaintFlat; // deliberately before fSize so that Compare
245 // will ignore it.
reed@google.comb55d1182011-05-11 00:42:04 +0000246 uint32_t fSize;
247
248 void* data() { return (char*)this + sizeof(*this); }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000249
reed@google.comb55d1182011-05-11 00:42:04 +0000250 static int Compare(const FlatData* a, const FlatData* b) {
251 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
252 }
253 };
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000254
255 SkTDArray<FlatData*> fBitmapArray;
256 int flattenToIndex(const SkBitmap&);
257
reed@google.comb55d1182011-05-11 00:42:04 +0000258 SkTDArray<FlatData*> fFlatArray;
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000259 size_t fBytesOfFlatData;
reed@google.comb55d1182011-05-11 00:42:04 +0000260 int fCurrFlatIndex[kCount_PaintFlats];
261 int flattenToIndex(SkFlattenable* obj, PaintFlats);
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000262 int flattenableToReplace(const FlatData& newFlat);
reed@google.comb55d1182011-05-11 00:42:04 +0000263
reed@google.com31891582011-05-12 03:03:56 +0000264 SkPaint fPaint;
265 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000266
reed@google.comacd471f2011-05-03 21:26:46 +0000267 class AutoPipeNotify {
268 public:
269 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
270 ~AutoPipeNotify() { fCanvas->doNotify(); }
271 private:
272 SkGPipeCanvas* fCanvas;
273 };
274 friend class AutoPipeNotify;
275
reed@google.combb6992a2011-04-26 17:41:56 +0000276 typedef SkCanvas INHERITED;
277};
278
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000279int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000280 SkASSERT(shouldFlattenBitmaps(fFlags));
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000281 SkOrderedWriteBuffer tmpWriter(1024);
scroggo@google.com565254b2012-06-28 15:41:32 +0000282 tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
283 (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
284 | SkFlattenableWriteBuffer::kCrossProcess_Flag));
285 tmpWriter.setFactoryRecorder(fFactorySet);
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000286 bitmap.flatten(tmpWriter);
287
288 size_t len = tmpWriter.size();
289 size_t allocSize = len + sizeof(FlatData);
290
291 SkAutoSMalloc<1024> storage(allocSize);
292 FlatData* flat = (FlatData*)storage.get();
293 flat->fSize = len;
294 tmpWriter.flatten(flat->data());
295
296 int index = SkTSearch<FlatData>((const FlatData**)fBitmapArray.begin(),
297 fBitmapArray.count(), flat, sizeof(flat),
298 &FlatData::Compare);
299 if (index < 0) {
300 index = ~index;
301 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
302 memcpy(copy, flat, allocSize);
303 // For bitmaps, we can use zero based indices, since we will never ask
304 // for a NULL bitmap (unlike with paint flattenables).
305 copy->fIndex = fBitmapArray.count();
306 *fBitmapArray.insert(index) = copy;
scroggo@google.com565254b2012-06-28 15:41:32 +0000307 if (this->needOpBytes(len)) {
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000308 this->writeOp(kDef_Bitmap_DrawOp, 0, copy->fIndex);
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000309 fWriter.write(copy->data(), len);
310 }
311 }
312 return fBitmapArray[index]->fIndex;
313}
314
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000315// Return -1 if there is no need to replace a flattenable, or there was not an
316// appropriate one to replace. Otherwise return the index of a flattenable to
317// replace.
318int SkGPipeCanvas::flattenableToReplace(const FlatData& newFlat) {
319 // For now, set an arbitrary limit on the size of FlatData we have stored.
320 // Note that this is currently a soft limit. If we have reached the limit,
321 // we replace one, but do not ensure that we return to below the limit.
322 if (fBytesOfFlatData + fFlatArray.bytes() > 1024) {
323 for (int i = 0; i < fFlatArray.count(); i++) {
324 // Only replace the same paint flat. Since a paint can only have
325 // one of each type, replacing one of the same type means that
326 // we will not be purging a flat on the same paint.
327 if (newFlat.fPaintFlat == fFlatArray[i]->fPaintFlat) {
328 return i;
329 }
330 }
331 }
332 return -1;
333}
334
reed@google.comb55d1182011-05-11 00:42:04 +0000335// return 0 for NULL (or unflattenable obj), or index-base-1
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000336// return ~(index-base-1) if an old flattenable was replaced
reed@google.comb55d1182011-05-11 00:42:04 +0000337int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
338 if (NULL == obj) {
339 return 0;
340 }
reed@google.comb55d1182011-05-11 00:42:04 +0000341
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000342 SkOrderedWriteBuffer tmpWriter(1024);
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000343
scroggo@google.com565254b2012-06-28 15:41:32 +0000344 if (fFlags & SkGPipeWriter::kCrossProcess_Flag) {
345 tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
346 (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
347 | SkFlattenableWriteBuffer::kCrossProcess_Flag));
348 tmpWriter.setFactoryRecorder(fFactorySet);
349 } else {
350 // Needed for bitmap shaders.
351 tmpWriter.setFlags(SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag);
352 }
reed@google.comdde09562011-05-23 12:21:05 +0000353
reed@google.comb55d1182011-05-11 00:42:04 +0000354 tmpWriter.writeFlattenable(obj);
355 size_t len = tmpWriter.size();
356 size_t allocSize = len + sizeof(FlatData);
357
358 SkAutoSMalloc<1024> storage(allocSize);
359 FlatData* flat = (FlatData*)storage.get();
360 flat->fSize = len;
361 tmpWriter.flatten(flat->data());
362
363 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000364 fFlatArray.count(), flat, sizeof(FlatData*),
reed@google.comb55d1182011-05-11 00:42:04 +0000365 &FlatData::Compare);
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000366 bool replacedAFlat = false;
reed@google.comb55d1182011-05-11 00:42:04 +0000367 if (index < 0) {
368 index = ~index;
369 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
370 memcpy(copy, flat, allocSize);
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000371 copy->fPaintFlat = paintflat;
372 int indexToReplace = this->flattenableToReplace(*copy);
373 if (indexToReplace >= 0) {
374 replacedAFlat = true;
375 FlatData* oldData = fFlatArray[indexToReplace];
376 copy->fIndex = oldData->fIndex;
377 fBytesOfFlatData -= (sizeof(FlatData) + oldData->fSize);
378 sk_free(oldData);
379 fFlatArray.remove(indexToReplace);
380 if (indexToReplace < index) {
381 index--;
382 }
383 }
reed@google.comb55d1182011-05-11 00:42:04 +0000384 *fFlatArray.insert(index) = copy;
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000385 fBytesOfFlatData += allocSize;
386 if (!replacedAFlat) {
387 // Call this after the insert, so that count() will have been grown
388 // (unless we replaced one, in which case fIndex has already been
389 // set properly).
390 copy->fIndex = fFlatArray.count();
391// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
392 }
reed@google.comb55d1182011-05-11 00:42:04 +0000393
394 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000395 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000396 fWriter.write(copy->data(), len);
397 }
398 }
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000399 int retVal = fFlatArray[index]->fIndex;
400 if (replacedAFlat) {
401 retVal = ~retVal;
402 }
403 return retVal;
reed@google.comb55d1182011-05-11 00:42:04 +0000404}
405
reed@google.combb6992a2011-04-26 17:41:56 +0000406///////////////////////////////////////////////////////////////////////////////
407
reed@google.comacd471f2011-05-03 21:26:46 +0000408#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000409
reed@google.comacd471f2011-05-03 21:26:46 +0000410SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
scroggo@google.com565254b2012-06-28 15:41:32 +0000411 SkWriter32* writer, SkFactorySet* fset, uint32_t flags)
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +0000412: fHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag)), fWriter(*writer), fFlags(flags)
413, fBytesOfFlatData(0){
reed@google.com67908f22011-06-27 14:47:50 +0000414 fFactorySet = fset;
reed@google.comacd471f2011-05-03 21:26:46 +0000415 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000416 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000417 fBlockSize = 0; // need first block from controller
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000418 fBytesNotified = 0;
reed@google.comb55d1182011-05-11 00:42:04 +0000419 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000420
reed@google.combb6793b2011-05-05 15:18:15 +0000421 // we need a device to limit our clip
422 // should the caller give us the bounds?
yangsu@google.com06b4da162011-06-17 15:04:40 +0000423 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000424 SkBitmap bitmap;
425 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da162011-06-17 15:04:40 +0000426 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000427 this->setDevice(device)->unref();
scroggo@google.com565254b2012-06-28 15:41:32 +0000428 // Tell the reader the appropriate flags to use.
429 if (this->needOpBytes()) {
430 this->writeOp(kReportFlags_DrawOp, fFlags, 0);
431 }
reed@google.combb6992a2011-04-26 17:41:56 +0000432}
433
434SkGPipeCanvas::~SkGPipeCanvas() {
435 this->finish();
436
reed@google.comb55d1182011-05-11 00:42:04 +0000437 fFlatArray.freeAll();
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000438 fBitmapArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000439}
440
reed@google.comacd471f2011-05-03 21:26:46 +0000441bool SkGPipeCanvas::needOpBytes(size_t needed) {
442 if (fDone) {
443 return false;
444 }
445
446 needed += 4; // size of DrawOp atom
447 if (fWriter.size() + needed > fBlockSize) {
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000448 // Before we wipe out any data that has already been written, read it
449 // out.
450 this->doNotify();
451 size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed);
452 void* block = fController->requestBlock(blockSize, &fBlockSize);
reed@google.comacd471f2011-05-03 21:26:46 +0000453 if (NULL == block) {
454 fDone = true;
455 return false;
456 }
457 fWriter.reset(block, fBlockSize);
458 fBytesNotified = 0;
459 }
460 return true;
461}
462
reed@google.comf5842f72011-05-04 18:30:04 +0000463uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
464 uint32_t id = 0; // 0 means default/null typeface
465 if (face) {
466 id = fTypefaceSet.find(face);
467 if (0 == id) {
468 id = fTypefaceSet.add(face);
469 size_t size = writeTypeface(NULL, face);
470 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000471 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000472 writeTypeface(&fWriter, face);
473 }
474 }
475 }
476 return id;
477}
478
reed@google.combb6992a2011-04-26 17:41:56 +0000479///////////////////////////////////////////////////////////////////////////////
480
reed@google.comacd471f2011-05-03 21:26:46 +0000481#define NOTIFY_SETUP(canvas) \
482 AutoPipeNotify apn(canvas)
483
reed@google.combb6992a2011-04-26 17:41:56 +0000484int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000485 NOTIFY_SETUP(this);
486 if (this->needOpBytes()) {
487 this->writeOp(kSave_DrawOp, 0, flags);
488 }
reed@google.combb6992a2011-04-26 17:41:56 +0000489 return this->INHERITED::save(flags);
490}
491
492int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
493 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000494 NOTIFY_SETUP(this);
495 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000496 unsigned opFlags = 0;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000497
reed@google.combb6992a2011-04-26 17:41:56 +0000498 if (bounds) {
499 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000500 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000501 }
502 if (paint) {
503 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000504 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000505 }
506
reed@google.comacd471f2011-05-03 21:26:46 +0000507 if (this->needOpBytes(size)) {
508 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
509 if (bounds) {
510 fWriter.writeRect(*bounds);
511 }
reed@google.combb6992a2011-04-26 17:41:56 +0000512 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000513
reed@google.combb6992a2011-04-26 17:41:56 +0000514 // we just pass on the save, so we don't create a layer
515 return this->INHERITED::save(saveFlags);
516}
517
518void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000519 NOTIFY_SETUP(this);
520 if (this->needOpBytes()) {
521 this->writeOp(kRestore_DrawOp);
522 }
reed@google.combb6992a2011-04-26 17:41:56 +0000523 this->INHERITED::restore();
524}
525
526bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
527 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000528 NOTIFY_SETUP(this);
529 if (this->needOpBytes(2 * sizeof(SkScalar))) {
530 this->writeOp(kTranslate_DrawOp);
531 fWriter.writeScalar(dx);
532 fWriter.writeScalar(dy);
533 }
reed@google.combb6992a2011-04-26 17:41:56 +0000534 }
535 return this->INHERITED::translate(dx, dy);
536}
537
538bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
539 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000540 NOTIFY_SETUP(this);
541 if (this->needOpBytes(2 * sizeof(SkScalar))) {
542 this->writeOp(kScale_DrawOp);
543 fWriter.writeScalar(sx);
544 fWriter.writeScalar(sy);
545 }
reed@google.combb6992a2011-04-26 17:41:56 +0000546 }
547 return this->INHERITED::scale(sx, sy);
548}
549
550bool SkGPipeCanvas::rotate(SkScalar degrees) {
551 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000552 NOTIFY_SETUP(this);
553 if (this->needOpBytes(sizeof(SkScalar))) {
554 this->writeOp(kRotate_DrawOp);
555 fWriter.writeScalar(degrees);
556 }
reed@google.combb6992a2011-04-26 17:41:56 +0000557 }
558 return this->INHERITED::rotate(degrees);
559}
560
561bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
562 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000563 NOTIFY_SETUP(this);
564 if (this->needOpBytes(2 * sizeof(SkScalar))) {
565 this->writeOp(kSkew_DrawOp);
566 fWriter.writeScalar(sx);
567 fWriter.writeScalar(sy);
568 }
reed@google.combb6992a2011-04-26 17:41:56 +0000569 }
570 return this->INHERITED::skew(sx, sy);
571}
572
573bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
574 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000575 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000576 if (this->needOpBytes(matrix.writeToMemory(NULL))) {
reed@google.comacd471f2011-05-03 21:26:46 +0000577 this->writeOp(kConcat_DrawOp);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000578 fWriter.writeMatrix(matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000579 }
reed@google.combb6992a2011-04-26 17:41:56 +0000580 }
581 return this->INHERITED::concat(matrix);
582}
583
584void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000585 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000586 if (this->needOpBytes(matrix.writeToMemory(NULL))) {
reed@google.comacd471f2011-05-03 21:26:46 +0000587 this->writeOp(kSetMatrix_DrawOp);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000588 fWriter.writeMatrix(matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000589 }
reed@google.combb6992a2011-04-26 17:41:56 +0000590 this->INHERITED::setMatrix(matrix);
591}
592
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000593bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp,
594 bool doAntiAlias) {
reed@google.comacd471f2011-05-03 21:26:46 +0000595 NOTIFY_SETUP(this);
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000596 if (this->needOpBytes(sizeof(SkRect)) + sizeof(bool)) {
reed@google.comacd471f2011-05-03 21:26:46 +0000597 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
598 fWriter.writeRect(rect);
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000599 fWriter.writeBool(doAntiAlias);
reed@google.comacd471f2011-05-03 21:26:46 +0000600 }
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000601 return this->INHERITED::clipRect(rect, rgnOp, doAntiAlias);
reed@google.combb6992a2011-04-26 17:41:56 +0000602}
603
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000604bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp,
605 bool doAntiAlias) {
reed@google.comacd471f2011-05-03 21:26:46 +0000606 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000607 if (this->needOpBytes(path.writeToMemory(NULL)) + sizeof(bool)) {
reed@google.comacd471f2011-05-03 21:26:46 +0000608 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000609 fWriter.writePath(path);
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000610 fWriter.writeBool(doAntiAlias);
reed@google.comacd471f2011-05-03 21:26:46 +0000611 }
reed@google.combb6992a2011-04-26 17:41:56 +0000612 // we just pass on the bounds of the path
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000613 return this->INHERITED::clipRect(path.getBounds(), rgnOp, doAntiAlias);
reed@google.combb6992a2011-04-26 17:41:56 +0000614}
615
616bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000617 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000618 if (this->needOpBytes(region.writeToMemory(NULL))) {
reed@google.comacd471f2011-05-03 21:26:46 +0000619 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000620 fWriter.writeRegion(region);
reed@google.comacd471f2011-05-03 21:26:46 +0000621 }
reed@google.combb6992a2011-04-26 17:41:56 +0000622 return this->INHERITED::clipRegion(region, rgnOp);
623}
624
625///////////////////////////////////////////////////////////////////////////////
626
627void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000628 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000629 unsigned flags = 0;
630 if (color) {
631 flags |= kClear_HasColor_DrawOpFlag;
632 }
reed@google.comacd471f2011-05-03 21:26:46 +0000633 if (this->needOpBytes(sizeof(SkColor))) {
634 this->writeOp(kDrawClear_DrawOp, flags, 0);
635 if (color) {
636 fWriter.write32(color);
637 }
reed@google.combb6992a2011-04-26 17:41:56 +0000638 }
639}
640
641void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000642 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000643 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000644 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000645 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000646 }
reed@google.combb6992a2011-04-26 17:41:56 +0000647}
648
649void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
650 const SkPoint pts[], const SkPaint& paint) {
651 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000652 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000653 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000654 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000655 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000656 fWriter.write32(count);
657 fWriter.write(pts, count * sizeof(SkPoint));
658 }
reed@google.combb6992a2011-04-26 17:41:56 +0000659 }
660}
661
662void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000663 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000664 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000665 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000666 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000667 fWriter.writeRect(rect);
668 }
reed@google.combb6992a2011-04-26 17:41:56 +0000669}
670
671void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000672 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000673 this->writePaint(paint);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000674 if (this->needOpBytes(path.writeToMemory(NULL))) {
reed@google.com31891582011-05-12 03:03:56 +0000675 this->writeOp(kDrawPath_DrawOp);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000676 fWriter.writePath(path);
reed@google.comacd471f2011-05-03 21:26:46 +0000677 }
reed@google.combb6992a2011-04-26 17:41:56 +0000678}
679
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000680void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
681 const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000682 bool flatten = shouldFlattenBitmaps(fFlags);
683 const void* ptr = 0;
684 int bitmapIndex = 0;
685 if (flatten) {
686 bitmapIndex = this->flattenToIndex(bm);
687 } else {
688 ptr = fHeap.addBitmap(bm);
689 if (NULL == ptr) {
690 return;
691 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000692 }
693
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000694 NOTIFY_SETUP(this);
695 if (paint) {
696 this->writePaint(*paint);
697 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000698
scroggo@google.com565254b2012-06-28 15:41:32 +0000699 size_t opBytesNeeded = sizeof(SkScalar) * 2 + sizeof(bool);
700 if (!flatten) {
701 opBytesNeeded += sizeof(void*);
702 }
703 if (this->needOpBytes(opBytesNeeded)) {
704 this->writeOp(kDrawBitmap_DrawOp, 0, bitmapIndex);
705 if (!flatten) {
706 fWriter.writePtr(const_cast<void*>(ptr));
707 }
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000708 fWriter.writeBool(paint != NULL);
709 fWriter.writeScalar(left);
710 fWriter.writeScalar(top);
711 }
reed@google.combb6992a2011-04-26 17:41:56 +0000712}
713
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000714void SkGPipeCanvas::drawBitmapRect(const SkBitmap& bm, const SkIRect* src,
715 const SkRect& dst, const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000716 bool flatten = shouldFlattenBitmaps(fFlags);
717 const void* ptr = 0;
718 int bitmapIndex = 0;
719 if (flatten) {
720 bitmapIndex = this->flattenToIndex(bm);
721 } else {
722 ptr = fHeap.addBitmap(bm);
723 if (NULL == ptr) {
724 return;
725 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000726 }
727
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000728 NOTIFY_SETUP(this);
729 if (paint) {
730 this->writePaint(*paint);
731 }
732
scroggo@google.com565254b2012-06-28 15:41:32 +0000733 size_t opBytesNeeded = sizeof(SkRect) + sizeof(bool) * 2;
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000734 bool hasSrc = src != NULL;
735 if (hasSrc) {
736 opBytesNeeded += sizeof(int32_t) * 4;
737 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000738 if (!flatten) {
739 opBytesNeeded += sizeof(void*);
740 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000741 if (this->needOpBytes(opBytesNeeded)) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000742 this->writeOp(kDrawBitmapRect_DrawOp, 0, bitmapIndex);
743 if (!flatten) {
744 fWriter.writePtr(const_cast<void*>(ptr));
745 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000746 fWriter.writeBool(paint != NULL);
747 fWriter.writeBool(hasSrc);
748 if (hasSrc) {
749 fWriter.write32(src->fLeft);
750 fWriter.write32(src->fTop);
751 fWriter.write32(src->fRight);
752 fWriter.write32(src->fBottom);
753 }
754 fWriter.writeRect(dst);
755 }
reed@google.combb6992a2011-04-26 17:41:56 +0000756}
757
758void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
759 const SkPaint*) {
760 UNIMPLEMENTED
761}
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000762
763void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center,
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000764 const SkRect& dst, const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000765 bool flatten = shouldFlattenBitmaps(fFlags);
766 const void* ptr = 0;
767 int bitmapIndex = 0;
768 if (flatten) {
769 bitmapIndex = this->flattenToIndex(bm);
770 } else {
771 ptr = fHeap.addBitmap(bm);
772 if (NULL == ptr) {
773 return;
774 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000775 }
776
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000777 NOTIFY_SETUP(this);
778 if (paint) {
779 this->writePaint(*paint);
780 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000781
scroggo@google.com565254b2012-06-28 15:41:32 +0000782 size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(bool) + sizeof(SkRect);
783 if (!flatten) {
784 opBytesNeeded += sizeof(void*);
785 }
786 if (this->needOpBytes(opBytesNeeded)) {
787 this->writeOp(kDrawBitmapNine_DrawOp, 0, bitmapIndex);
788 if (!flatten) {
789 fWriter.writePtr(const_cast<void*>(ptr));
790 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000791 fWriter.writeBool(paint != NULL);
792 fWriter.write32(center.fLeft);
793 fWriter.write32(center.fTop);
794 fWriter.write32(center.fRight);
795 fWriter.write32(center.fBottom);
796 fWriter.writeRect(dst);
797 }
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000798}
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000799
800void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top,
801 const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000802 bool flatten = shouldFlattenBitmaps(fFlags);
803 const void* ptr = 0;
804 int bitmapIndex = 0;
805 if (flatten) {
806 bitmapIndex = this->flattenToIndex(bm);
807 } else {
808 ptr = fHeap.addBitmap(bm);
809 if (NULL == ptr) {
810 return;
811 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000812 }
813
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000814 NOTIFY_SETUP(this);
815 if (paint) {
816 this->writePaint(*paint);
817 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000818
scroggo@google.com565254b2012-06-28 15:41:32 +0000819 size_t opBytesNeeded = sizeof(int32_t) * 2 + sizeof(bool);
820 if (!flatten) {
821 opBytesNeeded += sizeof(void*);
822 }
823 if (this->needOpBytes(opBytesNeeded)) {
824 this->writeOp(kDrawSprite_DrawOp, 0, bitmapIndex);
825 if (!flatten) {
826 fWriter.writePtr(const_cast<void*>(ptr));
827 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000828 fWriter.writeBool(paint != NULL);
829 fWriter.write32(left);
830 fWriter.write32(top);
831 }
reed@google.combb6992a2011-04-26 17:41:56 +0000832}
833
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000834void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
reed@google.combb6992a2011-04-26 17:41:56 +0000835 SkScalar y, const SkPaint& paint) {
836 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000837 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000838 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000839 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000840 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000841 fWriter.write32(byteLength);
842 fWriter.writePad(text, byteLength);
843 fWriter.writeScalar(x);
844 fWriter.writeScalar(y);
845 }
reed@google.combb6992a2011-04-26 17:41:56 +0000846 }
847}
848
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000849void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
reed@google.combb6992a2011-04-26 17:41:56 +0000850 const SkPoint pos[], const SkPaint& paint) {
851 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000852 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000853 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000854 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000855 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000856 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000857 fWriter.write32(byteLength);
858 fWriter.writePad(text, byteLength);
859 fWriter.write32(count);
860 fWriter.write(pos, count * sizeof(SkPoint));
861 }
reed@google.combb6992a2011-04-26 17:41:56 +0000862 }
863}
864
865void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
866 const SkScalar xpos[], SkScalar constY,
867 const SkPaint& paint) {
868 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000869 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000870 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000871 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000872 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000873 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000874 fWriter.write32(byteLength);
875 fWriter.writePad(text, byteLength);
876 fWriter.write32(count);
877 fWriter.write(xpos, count * sizeof(SkScalar));
878 fWriter.writeScalar(constY);
879 }
reed@google.combb6992a2011-04-26 17:41:56 +0000880 }
881}
882
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000883void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
884 const SkPath& path, const SkMatrix* matrix,
reed@google.combb6992a2011-04-26 17:41:56 +0000885 const SkPaint& paint) {
886 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000887 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000888 unsigned flags = 0;
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000889 size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000890 if (matrix) {
891 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000892 size += matrix->writeToMemory(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000893 }
reed@google.com31891582011-05-12 03:03:56 +0000894 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000895 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000896 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000897
reed@google.comacd471f2011-05-03 21:26:46 +0000898 fWriter.write32(byteLength);
899 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000900
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000901 fWriter.writePath(path);
reed@google.comacd471f2011-05-03 21:26:46 +0000902 if (matrix) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000903 fWriter.writeMatrix(*matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000904 }
reed@google.combb6992a2011-04-26 17:41:56 +0000905 }
906 }
907}
908
909void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000910 // we want to playback the picture into individual draw calls
911 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000912}
913
reed@google.combb6992a2011-04-26 17:41:56 +0000914void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
915 const SkPoint vertices[], const SkPoint texs[],
916 const SkColor colors[], SkXfermode*,
917 const uint16_t indices[], int indexCount,
918 const SkPaint& paint) {
919 if (0 == vertexCount) {
920 return;
921 }
922
reed@google.comacd471f2011-05-03 21:26:46 +0000923 NOTIFY_SETUP(this);
924 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000925 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000926 unsigned flags = 0;
927 if (texs) {
928 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000929 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000930 }
931 if (colors) {
932 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000933 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000934 }
935 if (indices && indexCount > 0) {
936 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000937 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000938 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000939
reed@google.comacd471f2011-05-03 21:26:46 +0000940 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000941 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000942 fWriter.write32(mode);
943 fWriter.write32(vertexCount);
944 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
945 if (texs) {
946 fWriter.write(texs, vertexCount * sizeof(SkPoint));
947 }
948 if (colors) {
949 fWriter.write(colors, vertexCount * sizeof(SkColor));
950 }
reed@google.combb6992a2011-04-26 17:41:56 +0000951
reed@google.comacd471f2011-05-03 21:26:46 +0000952 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000953
reed@google.comacd471f2011-05-03 21:26:46 +0000954 if (indices && indexCount > 0) {
955 fWriter.write32(indexCount);
956 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
957 }
reed@google.combb6992a2011-04-26 17:41:56 +0000958 }
959}
960
reed@google.comacd471f2011-05-03 21:26:46 +0000961void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
962 if (size && ptr) {
963 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000964 unsigned data = 0;
965 if (size < (1 << DRAWOPS_DATA_BITS)) {
966 data = (unsigned)size;
967 }
reed@google.comacd471f2011-05-03 21:26:46 +0000968 if (this->needOpBytes(4 + SkAlign4(size))) {
969 this->writeOp(kDrawData_DrawOp, 0, data);
970 if (0 == data) {
971 fWriter.write32(size);
972 }
reed@google.combb6793b2011-05-05 15:18:15 +0000973 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000974 }
975 }
976}
977
978///////////////////////////////////////////////////////////////////////////////
979
980template <typename T> uint32_t castToU32(T value) {
981 union {
982 T fSrc;
983 uint32_t fDst;
984 } data;
985 data.fSrc = value;
986 return data.fDst;
987}
988
reed@google.com31891582011-05-12 03:03:56 +0000989void SkGPipeCanvas::writePaint(const SkPaint& paint) {
990 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000991 uint32_t storage[32];
992 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000993
994 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000995 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000996 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000997 }
998 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000999 *ptr++ = PaintOp_packOp(kColor_PaintOp);
1000 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +00001001 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +00001002 }
1003 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001004 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +00001005 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +00001006 }
1007 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001008 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +00001009 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +00001010 }
1011 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001012 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +00001013 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +00001014 }
1015 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001016 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
1017 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +00001018 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +00001019 }
1020 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001021 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
1022 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +00001023 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +00001024 }
1025 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001026 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +00001027 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +00001028 }
1029 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001030 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +00001031 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +00001032 }
1033 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001034 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +00001035 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +00001036 }
1037 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001038 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
1039 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +00001040 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +00001041 }
1042 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001043 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
1044 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +00001045 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +00001046 }
1047 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +00001048 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
1049 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +00001050 base.setTextSkewX(paint.getTextSkewX());
1051 }
1052
1053 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
1054 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +00001055 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
1056 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +00001057 }
reed@google.combb6992a2011-04-26 17:41:56 +00001058
reed@google.comb55d1182011-05-11 00:42:04 +00001059 for (int i = 0; i < kCount_PaintFlats; i++) {
1060 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +00001061 bool replaced = index < 0;
1062 if (replaced) {
1063 index = ~index;
1064 }
reed@google.comb55d1182011-05-11 00:42:04 +00001065 SkASSERT(index >= 0 && index <= fFlatArray.count());
scroggo@google.comd3ba5cc2012-07-09 16:05:53 +00001066 if (index != fCurrFlatIndex[i] || replaced) {
reed@google.comb55d1182011-05-11 00:42:04 +00001067 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
1068 fCurrFlatIndex[i] = index;
1069 }
1070 }
1071
reed@google.comacd471f2011-05-03 21:26:46 +00001072 size_t size = (char*)ptr - (char*)storage;
1073 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +00001074 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +00001075 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +00001076 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +00001077// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +00001078 }
1079 }
reed@google.combb6992a2011-04-26 17:41:56 +00001080}
1081
1082///////////////////////////////////////////////////////////////////////////////
1083
1084#include "SkGPipe.h"
1085
reed@google.comacd471f2011-05-03 21:26:46 +00001086SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +00001087 fCanvas = NULL;
1088}
1089
1090SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +00001091 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +00001092 SkSafeUnref(fCanvas);
1093}
1094
scroggo@google.com565254b2012-06-28 15:41:32 +00001095SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +00001096 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +00001097 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +00001098 fFactorySet.reset();
1099 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
1100 (flags & kCrossProcess_Flag) ?
scroggo@google.com565254b2012-06-28 15:41:32 +00001101 &fFactorySet : NULL, flags));
reed@google.combb6992a2011-04-26 17:41:56 +00001102 }
1103 return fCanvas;
1104}
1105
1106void SkGPipeWriter::endRecording() {
1107 if (fCanvas) {
1108 fCanvas->finish();
1109 fCanvas->unref();
1110 fCanvas = NULL;
1111 }
1112}
1113