blob: 066159f10abe89f494ed8a6aa46c3f944fe73094 [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());
scroggo@google.com5af9b202012-06-04 17:17:36 +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--) {
88 if (genID == fBitmaps[i].fGenID) {
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +000089 if (orig.pixelRefOffset() != fBitmaps[i].fBitmap->pixelRefOffset()) {
90 // In this case, the bitmaps share a pixelRef, but have
91 // different offsets. Keep track of the other bitmap so that
92 // instead of making another copy of the pixelRef we can use
93 // the copy we already made.
94 sharedPixelRef = fBitmaps[i].fBitmap->pixelRef();
95 break;
96 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +000097 return fBitmaps[i].fBitmap;
98 }
99 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000100 SkBitmap* copy;
101 // If the bitmap is mutable, we still need to do a deep copy, since the
102 // caller may modify it afterwards. That said, if the bitmap is mutable,
103 // but has no pixelRef, the copy constructor actually does a deep copy.
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +0000104 if (fCanDoShallowCopies && (orig.isImmutable() || !orig.pixelRef())) {
105 copy = new SkBitmap(orig);
scroggo@google.com565254b2012-06-28 15:41:32 +0000106 } else {
scroggo@google.com4f1f6bf2012-07-02 13:35:09 +0000107 if (sharedPixelRef != NULL) {
108 // Do a shallow copy of the bitmap to get the width, height, etc
109 copy = new SkBitmap(orig);
110 // Replace the pixelRef with the copy that was already made, and
111 // use the appropriate offset.
112 copy->setPixelRef(sharedPixelRef, orig.pixelRefOffset());
113 } else {
114 copy = new SkBitmap();
115 if (!orig.copyTo(copy, orig.getConfig())) {
116 delete copy;
117 return NULL;
118 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000119 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000120 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000121 BitmapInfo* info = fBitmaps.append();
122 info->fBitmap = copy;
123 info->fGenID = genID;
124 return copy;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000125 }
126private:
127 struct BitmapInfo {
128 SkBitmap* fBitmap;
129 // Store the generation ID of the original bitmap, since copying does
130 // not copy this field, so fBitmap's generation ID will not be useful
131 // for comparing.
132 uint32_t fGenID;
133 };
scroggo@google.com565254b2012-06-28 15:41:32 +0000134 SkTDArray<BitmapInfo> fBitmaps;
135 const bool fCanDoShallowCopies;
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000136};
137
138///////////////////////////////////////////////////////////////////////////////
139
reed@google.combb6992a2011-04-26 17:41:56 +0000140class SkGPipeCanvas : public SkCanvas {
141public:
scroggo@google.com565254b2012-06-28 15:41:32 +0000142 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*, uint32_t flags);
reed@google.combb6992a2011-04-26 17:41:56 +0000143 virtual ~SkGPipeCanvas();
144
145 void finish() {
146 if (!fDone) {
reed@google.comdbccc882011-07-08 18:53:39 +0000147 if (this->needOpBytes()) {
148 this->writeOp(kDone_DrawOp);
149 this->doNotify();
150 }
reed@google.combb6992a2011-04-26 17:41:56 +0000151 fDone = true;
152 }
153 }
154
155 // overrides from SkCanvas
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000156 virtual int save(SaveFlags) SK_OVERRIDE;
157 virtual int saveLayer(const SkRect* bounds, const SkPaint*,
158 SaveFlags) SK_OVERRIDE;
159 virtual void restore() SK_OVERRIDE;
160 virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
161 virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
162 virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
163 virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
164 virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
165 virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
166 virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
167 bool doAntiAlias = false) SK_OVERRIDE;
168 virtual bool clipPath(const SkPath& path, SkRegion::Op op,
169 bool doAntiAlias = false) SK_OVERRIDE;
170 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op) SK_OVERRIDE;
171 virtual void clear(SkColor) SK_OVERRIDE;
172 virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000173 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000174 const SkPaint&) SK_OVERRIDE;
175 virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE;
176 virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000177 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000178 const SkPaint*) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000179 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000180 const SkRect& dst, const SkPaint*) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000181 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000182 const SkPaint*) SK_OVERRIDE;
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000183 virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
184 const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000185 virtual void drawSprite(const SkBitmap&, int left, int top,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000186 const SkPaint*) SK_OVERRIDE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000187 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000188 SkScalar y, const SkPaint&) SK_OVERRIDE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000189 virtual void drawPosText(const void* text, size_t byteLength,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000190 const SkPoint pos[], const SkPaint&) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000191 virtual void drawPosTextH(const void* text, size_t byteLength,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000192 const SkScalar xpos[], SkScalar constY,
193 const SkPaint&) SK_OVERRIDE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000194 virtual void drawTextOnPath(const void* text, size_t byteLength,
195 const SkPath& path, const SkMatrix* matrix,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000196 const SkPaint&) SK_OVERRIDE;
197 virtual void drawPicture(SkPicture& picture) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000198 virtual void drawVertices(VertexMode, int vertexCount,
199 const SkPoint vertices[], const SkPoint texs[],
200 const SkColor colors[], SkXfermode*,
201 const uint16_t indices[], int indexCount,
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000202 const SkPaint&) SK_OVERRIDE;
203 virtual void drawData(const void*, size_t) SK_OVERRIDE;
reed@google.combb6992a2011-04-26 17:41:56 +0000204
205private:
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000206 Heap fHeap;
reed@google.comdde09562011-05-23 12:21:05 +0000207 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000208 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000209 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000210 size_t fBlockSize; // amount allocated for writer
211 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000212 bool fDone;
scroggo@google.com565254b2012-06-28 15:41:32 +0000213 uint32_t fFlags;
reed@google.combb6992a2011-04-26 17:41:56 +0000214
reed@google.comf5842f72011-05-04 18:30:04 +0000215 SkRefCntSet fTypefaceSet;
216
217 uint32_t getTypefaceID(SkTypeface*);
218
reed@google.comacd471f2011-05-03 21:26:46 +0000219 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000220 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
221 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000222
reed@google.comacd471f2011-05-03 21:26:46 +0000223 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000224 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
225 }
reed@google.comacd471f2011-05-03 21:26:46 +0000226
227 bool needOpBytes(size_t size = 0);
228
229 inline void doNotify() {
230 if (!fDone) {
231 size_t bytes = fWriter.size() - fBytesNotified;
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000232 if (bytes > 0) {
233 fController->notifyWritten(bytes);
234 fBytesNotified += bytes;
235 }
reed@google.comacd471f2011-05-03 21:26:46 +0000236 }
237 }
reed@google.comb55d1182011-05-11 00:42:04 +0000238
239 struct FlatData {
240 uint32_t fIndex; // always > 0
241 uint32_t fSize;
242
243 void* data() { return (char*)this + sizeof(*this); }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000244
reed@google.comb55d1182011-05-11 00:42:04 +0000245 static int Compare(const FlatData* a, const FlatData* b) {
246 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
247 }
248 };
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000249
250 SkTDArray<FlatData*> fBitmapArray;
251 int flattenToIndex(const SkBitmap&);
252
reed@google.comb55d1182011-05-11 00:42:04 +0000253 SkTDArray<FlatData*> fFlatArray;
254 int fCurrFlatIndex[kCount_PaintFlats];
255 int flattenToIndex(SkFlattenable* obj, PaintFlats);
256
reed@google.com31891582011-05-12 03:03:56 +0000257 SkPaint fPaint;
258 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000259
reed@google.comacd471f2011-05-03 21:26:46 +0000260 class AutoPipeNotify {
261 public:
262 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
263 ~AutoPipeNotify() { fCanvas->doNotify(); }
264 private:
265 SkGPipeCanvas* fCanvas;
266 };
267 friend class AutoPipeNotify;
268
reed@google.combb6992a2011-04-26 17:41:56 +0000269 typedef SkCanvas INHERITED;
270};
271
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000272int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000273 SkASSERT(shouldFlattenBitmaps(fFlags));
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000274 SkOrderedWriteBuffer tmpWriter(1024);
scroggo@google.com565254b2012-06-28 15:41:32 +0000275 tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
276 (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
277 | SkFlattenableWriteBuffer::kCrossProcess_Flag));
278 tmpWriter.setFactoryRecorder(fFactorySet);
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000279 bitmap.flatten(tmpWriter);
280
281 size_t len = tmpWriter.size();
282 size_t allocSize = len + sizeof(FlatData);
283
284 SkAutoSMalloc<1024> storage(allocSize);
285 FlatData* flat = (FlatData*)storage.get();
286 flat->fSize = len;
287 tmpWriter.flatten(flat->data());
288
289 int index = SkTSearch<FlatData>((const FlatData**)fBitmapArray.begin(),
290 fBitmapArray.count(), flat, sizeof(flat),
291 &FlatData::Compare);
292 if (index < 0) {
293 index = ~index;
294 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
295 memcpy(copy, flat, allocSize);
296 // For bitmaps, we can use zero based indices, since we will never ask
297 // for a NULL bitmap (unlike with paint flattenables).
298 copy->fIndex = fBitmapArray.count();
299 *fBitmapArray.insert(index) = copy;
scroggo@google.com565254b2012-06-28 15:41:32 +0000300 if (this->needOpBytes(len)) {
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000301 this->writeOp(kDef_Bitmap_DrawOp, 0, copy->fIndex);
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000302 fWriter.write(copy->data(), len);
303 }
304 }
305 return fBitmapArray[index]->fIndex;
306}
307
reed@google.comb55d1182011-05-11 00:42:04 +0000308// return 0 for NULL (or unflattenable obj), or index-base-1
309int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
310 if (NULL == obj) {
311 return 0;
312 }
reed@google.comb55d1182011-05-11 00:42:04 +0000313
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000314 SkOrderedWriteBuffer tmpWriter(1024);
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000315
scroggo@google.com565254b2012-06-28 15:41:32 +0000316 if (fFlags & SkGPipeWriter::kCrossProcess_Flag) {
317 tmpWriter.setFlags((SkFlattenableWriteBuffer::Flags)
318 (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
319 | SkFlattenableWriteBuffer::kCrossProcess_Flag));
320 tmpWriter.setFactoryRecorder(fFactorySet);
321 } else {
322 // Needed for bitmap shaders.
323 tmpWriter.setFlags(SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag);
324 }
reed@google.comdde09562011-05-23 12:21:05 +0000325
reed@google.comb55d1182011-05-11 00:42:04 +0000326 tmpWriter.writeFlattenable(obj);
327 size_t len = tmpWriter.size();
328 size_t allocSize = len + sizeof(FlatData);
329
330 SkAutoSMalloc<1024> storage(allocSize);
331 FlatData* flat = (FlatData*)storage.get();
332 flat->fSize = len;
333 tmpWriter.flatten(flat->data());
334
335 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
336 fFlatArray.count(), flat, sizeof(flat),
337 &FlatData::Compare);
338 if (index < 0) {
339 index = ~index;
340 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
341 memcpy(copy, flat, allocSize);
342 *fFlatArray.insert(index) = copy;
343 // call this after the insert, so that count() will have been grown
344 copy->fIndex = fFlatArray.count();
345// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
346
347 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000348 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000349 fWriter.write(copy->data(), len);
350 }
351 }
352 return fFlatArray[index]->fIndex;
353}
354
reed@google.combb6992a2011-04-26 17:41:56 +0000355///////////////////////////////////////////////////////////////////////////////
356
reed@google.comacd471f2011-05-03 21:26:46 +0000357#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000358
reed@google.comacd471f2011-05-03 21:26:46 +0000359SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
scroggo@google.com565254b2012-06-28 15:41:32 +0000360 SkWriter32* writer, SkFactorySet* fset, uint32_t flags)
scroggo@google.comd33819a2012-06-29 19:24:25 +0000361: fHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag)), fWriter(*writer), fFlags(flags) {
reed@google.com67908f22011-06-27 14:47:50 +0000362 fFactorySet = fset;
reed@google.comacd471f2011-05-03 21:26:46 +0000363 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000364 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000365 fBlockSize = 0; // need first block from controller
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000366 fBytesNotified = 0;
reed@google.comb55d1182011-05-11 00:42:04 +0000367 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000368
reed@google.combb6793b2011-05-05 15:18:15 +0000369 // we need a device to limit our clip
370 // should the caller give us the bounds?
yangsu@google.com06b4da162011-06-17 15:04:40 +0000371 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000372 SkBitmap bitmap;
373 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da162011-06-17 15:04:40 +0000374 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000375 this->setDevice(device)->unref();
scroggo@google.com565254b2012-06-28 15:41:32 +0000376 // Tell the reader the appropriate flags to use.
377 if (this->needOpBytes()) {
378 this->writeOp(kReportFlags_DrawOp, fFlags, 0);
379 }
reed@google.combb6992a2011-04-26 17:41:56 +0000380}
381
382SkGPipeCanvas::~SkGPipeCanvas() {
383 this->finish();
384
reed@google.comb55d1182011-05-11 00:42:04 +0000385 fFlatArray.freeAll();
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000386 fBitmapArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000387}
388
reed@google.comacd471f2011-05-03 21:26:46 +0000389bool SkGPipeCanvas::needOpBytes(size_t needed) {
390 if (fDone) {
391 return false;
392 }
393
394 needed += 4; // size of DrawOp atom
395 if (fWriter.size() + needed > fBlockSize) {
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000396 // Before we wipe out any data that has already been written, read it
397 // out.
398 this->doNotify();
399 size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed);
400 void* block = fController->requestBlock(blockSize, &fBlockSize);
reed@google.comacd471f2011-05-03 21:26:46 +0000401 if (NULL == block) {
402 fDone = true;
403 return false;
404 }
405 fWriter.reset(block, fBlockSize);
406 fBytesNotified = 0;
407 }
408 return true;
409}
410
reed@google.comf5842f72011-05-04 18:30:04 +0000411uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
412 uint32_t id = 0; // 0 means default/null typeface
413 if (face) {
414 id = fTypefaceSet.find(face);
415 if (0 == id) {
416 id = fTypefaceSet.add(face);
417 size_t size = writeTypeface(NULL, face);
418 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000419 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000420 writeTypeface(&fWriter, face);
421 }
422 }
423 }
424 return id;
425}
426
reed@google.combb6992a2011-04-26 17:41:56 +0000427///////////////////////////////////////////////////////////////////////////////
428
reed@google.comacd471f2011-05-03 21:26:46 +0000429#define NOTIFY_SETUP(canvas) \
430 AutoPipeNotify apn(canvas)
431
reed@google.combb6992a2011-04-26 17:41:56 +0000432int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000433 NOTIFY_SETUP(this);
434 if (this->needOpBytes()) {
435 this->writeOp(kSave_DrawOp, 0, flags);
436 }
reed@google.combb6992a2011-04-26 17:41:56 +0000437 return this->INHERITED::save(flags);
438}
439
440int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
441 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000442 NOTIFY_SETUP(this);
443 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000444 unsigned opFlags = 0;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000445
reed@google.combb6992a2011-04-26 17:41:56 +0000446 if (bounds) {
447 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000448 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000449 }
450 if (paint) {
451 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000452 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000453 }
454
reed@google.comacd471f2011-05-03 21:26:46 +0000455 if (this->needOpBytes(size)) {
456 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
457 if (bounds) {
458 fWriter.writeRect(*bounds);
459 }
reed@google.combb6992a2011-04-26 17:41:56 +0000460 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000461
reed@google.combb6992a2011-04-26 17:41:56 +0000462 // we just pass on the save, so we don't create a layer
463 return this->INHERITED::save(saveFlags);
464}
465
466void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000467 NOTIFY_SETUP(this);
468 if (this->needOpBytes()) {
469 this->writeOp(kRestore_DrawOp);
470 }
reed@google.combb6992a2011-04-26 17:41:56 +0000471 this->INHERITED::restore();
472}
473
474bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
475 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000476 NOTIFY_SETUP(this);
477 if (this->needOpBytes(2 * sizeof(SkScalar))) {
478 this->writeOp(kTranslate_DrawOp);
479 fWriter.writeScalar(dx);
480 fWriter.writeScalar(dy);
481 }
reed@google.combb6992a2011-04-26 17:41:56 +0000482 }
483 return this->INHERITED::translate(dx, dy);
484}
485
486bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
487 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000488 NOTIFY_SETUP(this);
489 if (this->needOpBytes(2 * sizeof(SkScalar))) {
490 this->writeOp(kScale_DrawOp);
491 fWriter.writeScalar(sx);
492 fWriter.writeScalar(sy);
493 }
reed@google.combb6992a2011-04-26 17:41:56 +0000494 }
495 return this->INHERITED::scale(sx, sy);
496}
497
498bool SkGPipeCanvas::rotate(SkScalar degrees) {
499 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000500 NOTIFY_SETUP(this);
501 if (this->needOpBytes(sizeof(SkScalar))) {
502 this->writeOp(kRotate_DrawOp);
503 fWriter.writeScalar(degrees);
504 }
reed@google.combb6992a2011-04-26 17:41:56 +0000505 }
506 return this->INHERITED::rotate(degrees);
507}
508
509bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
510 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000511 NOTIFY_SETUP(this);
512 if (this->needOpBytes(2 * sizeof(SkScalar))) {
513 this->writeOp(kSkew_DrawOp);
514 fWriter.writeScalar(sx);
515 fWriter.writeScalar(sy);
516 }
reed@google.combb6992a2011-04-26 17:41:56 +0000517 }
518 return this->INHERITED::skew(sx, sy);
519}
520
521bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
522 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000523 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000524 if (this->needOpBytes(matrix.writeToMemory(NULL))) {
reed@google.comacd471f2011-05-03 21:26:46 +0000525 this->writeOp(kConcat_DrawOp);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000526 fWriter.writeMatrix(matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000527 }
reed@google.combb6992a2011-04-26 17:41:56 +0000528 }
529 return this->INHERITED::concat(matrix);
530}
531
532void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000533 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000534 if (this->needOpBytes(matrix.writeToMemory(NULL))) {
reed@google.comacd471f2011-05-03 21:26:46 +0000535 this->writeOp(kSetMatrix_DrawOp);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000536 fWriter.writeMatrix(matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000537 }
reed@google.combb6992a2011-04-26 17:41:56 +0000538 this->INHERITED::setMatrix(matrix);
539}
540
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000541bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp,
542 bool doAntiAlias) {
reed@google.comacd471f2011-05-03 21:26:46 +0000543 NOTIFY_SETUP(this);
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000544 if (this->needOpBytes(sizeof(SkRect)) + sizeof(bool)) {
reed@google.comacd471f2011-05-03 21:26:46 +0000545 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
546 fWriter.writeRect(rect);
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000547 fWriter.writeBool(doAntiAlias);
reed@google.comacd471f2011-05-03 21:26:46 +0000548 }
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000549 return this->INHERITED::clipRect(rect, rgnOp, doAntiAlias);
reed@google.combb6992a2011-04-26 17:41:56 +0000550}
551
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000552bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp,
553 bool doAntiAlias) {
reed@google.comacd471f2011-05-03 21:26:46 +0000554 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000555 if (this->needOpBytes(path.writeToMemory(NULL)) + sizeof(bool)) {
reed@google.comacd471f2011-05-03 21:26:46 +0000556 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000557 fWriter.writePath(path);
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000558 fWriter.writeBool(doAntiAlias);
reed@google.comacd471f2011-05-03 21:26:46 +0000559 }
reed@google.combb6992a2011-04-26 17:41:56 +0000560 // we just pass on the bounds of the path
scroggo@google.com3b45cd52012-04-18 13:57:47 +0000561 return this->INHERITED::clipRect(path.getBounds(), rgnOp, doAntiAlias);
reed@google.combb6992a2011-04-26 17:41:56 +0000562}
563
564bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000565 NOTIFY_SETUP(this);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000566 if (this->needOpBytes(region.writeToMemory(NULL))) {
reed@google.comacd471f2011-05-03 21:26:46 +0000567 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000568 fWriter.writeRegion(region);
reed@google.comacd471f2011-05-03 21:26:46 +0000569 }
reed@google.combb6992a2011-04-26 17:41:56 +0000570 return this->INHERITED::clipRegion(region, rgnOp);
571}
572
573///////////////////////////////////////////////////////////////////////////////
574
575void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000576 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000577 unsigned flags = 0;
578 if (color) {
579 flags |= kClear_HasColor_DrawOpFlag;
580 }
reed@google.comacd471f2011-05-03 21:26:46 +0000581 if (this->needOpBytes(sizeof(SkColor))) {
582 this->writeOp(kDrawClear_DrawOp, flags, 0);
583 if (color) {
584 fWriter.write32(color);
585 }
reed@google.combb6992a2011-04-26 17:41:56 +0000586 }
587}
588
589void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000590 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000591 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000592 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000593 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000594 }
reed@google.combb6992a2011-04-26 17:41:56 +0000595}
596
597void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
598 const SkPoint pts[], const SkPaint& paint) {
599 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000600 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000601 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000602 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000603 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000604 fWriter.write32(count);
605 fWriter.write(pts, count * sizeof(SkPoint));
606 }
reed@google.combb6992a2011-04-26 17:41:56 +0000607 }
608}
609
610void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000611 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000612 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000613 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000614 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000615 fWriter.writeRect(rect);
616 }
reed@google.combb6992a2011-04-26 17:41:56 +0000617}
618
619void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000620 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000621 this->writePaint(paint);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000622 if (this->needOpBytes(path.writeToMemory(NULL))) {
reed@google.com31891582011-05-12 03:03:56 +0000623 this->writeOp(kDrawPath_DrawOp);
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000624 fWriter.writePath(path);
reed@google.comacd471f2011-05-03 21:26:46 +0000625 }
reed@google.combb6992a2011-04-26 17:41:56 +0000626}
627
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000628void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
629 const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000630 bool flatten = shouldFlattenBitmaps(fFlags);
631 const void* ptr = 0;
632 int bitmapIndex = 0;
633 if (flatten) {
634 bitmapIndex = this->flattenToIndex(bm);
635 } else {
636 ptr = fHeap.addBitmap(bm);
637 if (NULL == ptr) {
638 return;
639 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000640 }
641
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000642 NOTIFY_SETUP(this);
643 if (paint) {
644 this->writePaint(*paint);
645 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000646
scroggo@google.com565254b2012-06-28 15:41:32 +0000647 size_t opBytesNeeded = sizeof(SkScalar) * 2 + sizeof(bool);
648 if (!flatten) {
649 opBytesNeeded += sizeof(void*);
650 }
651 if (this->needOpBytes(opBytesNeeded)) {
652 this->writeOp(kDrawBitmap_DrawOp, 0, bitmapIndex);
653 if (!flatten) {
654 fWriter.writePtr(const_cast<void*>(ptr));
655 }
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000656 fWriter.writeBool(paint != NULL);
657 fWriter.writeScalar(left);
658 fWriter.writeScalar(top);
659 }
reed@google.combb6992a2011-04-26 17:41:56 +0000660}
661
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000662void SkGPipeCanvas::drawBitmapRect(const SkBitmap& bm, const SkIRect* src,
663 const SkRect& dst, const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000664 bool flatten = shouldFlattenBitmaps(fFlags);
665 const void* ptr = 0;
666 int bitmapIndex = 0;
667 if (flatten) {
668 bitmapIndex = this->flattenToIndex(bm);
669 } else {
670 ptr = fHeap.addBitmap(bm);
671 if (NULL == ptr) {
672 return;
673 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000674 }
675
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000676 NOTIFY_SETUP(this);
677 if (paint) {
678 this->writePaint(*paint);
679 }
680
scroggo@google.com565254b2012-06-28 15:41:32 +0000681 size_t opBytesNeeded = sizeof(SkRect) + sizeof(bool) * 2;
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000682 bool hasSrc = src != NULL;
683 if (hasSrc) {
684 opBytesNeeded += sizeof(int32_t) * 4;
685 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000686 if (!flatten) {
687 opBytesNeeded += sizeof(void*);
688 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000689 if (this->needOpBytes(opBytesNeeded)) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000690 this->writeOp(kDrawBitmapRect_DrawOp, 0, bitmapIndex);
691 if (!flatten) {
692 fWriter.writePtr(const_cast<void*>(ptr));
693 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000694 fWriter.writeBool(paint != NULL);
695 fWriter.writeBool(hasSrc);
696 if (hasSrc) {
697 fWriter.write32(src->fLeft);
698 fWriter.write32(src->fTop);
699 fWriter.write32(src->fRight);
700 fWriter.write32(src->fBottom);
701 }
702 fWriter.writeRect(dst);
703 }
reed@google.combb6992a2011-04-26 17:41:56 +0000704}
705
706void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
707 const SkPaint*) {
708 UNIMPLEMENTED
709}
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000710
711void SkGPipeCanvas::drawBitmapNine(const SkBitmap& bm, const SkIRect& center,
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000712 const SkRect& dst, const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000713 bool flatten = shouldFlattenBitmaps(fFlags);
714 const void* ptr = 0;
715 int bitmapIndex = 0;
716 if (flatten) {
717 bitmapIndex = this->flattenToIndex(bm);
718 } else {
719 ptr = fHeap.addBitmap(bm);
720 if (NULL == ptr) {
721 return;
722 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000723 }
724
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000725 NOTIFY_SETUP(this);
726 if (paint) {
727 this->writePaint(*paint);
728 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000729
scroggo@google.com565254b2012-06-28 15:41:32 +0000730 size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(bool) + sizeof(SkRect);
731 if (!flatten) {
732 opBytesNeeded += sizeof(void*);
733 }
734 if (this->needOpBytes(opBytesNeeded)) {
735 this->writeOp(kDrawBitmapNine_DrawOp, 0, bitmapIndex);
736 if (!flatten) {
737 fWriter.writePtr(const_cast<void*>(ptr));
738 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000739 fWriter.writeBool(paint != NULL);
740 fWriter.write32(center.fLeft);
741 fWriter.write32(center.fTop);
742 fWriter.write32(center.fRight);
743 fWriter.write32(center.fBottom);
744 fWriter.writeRect(dst);
745 }
scroggo@google.com5a2e8792012-04-20 17:39:51 +0000746}
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000747
748void SkGPipeCanvas::drawSprite(const SkBitmap& bm, int left, int top,
749 const SkPaint* paint) {
scroggo@google.com565254b2012-06-28 15:41:32 +0000750 bool flatten = shouldFlattenBitmaps(fFlags);
751 const void* ptr = 0;
752 int bitmapIndex = 0;
753 if (flatten) {
754 bitmapIndex = this->flattenToIndex(bm);
755 } else {
756 ptr = fHeap.addBitmap(bm);
757 if (NULL == ptr) {
758 return;
759 }
scroggo@google.com8ae3c7f2012-06-13 17:47:52 +0000760 }
761
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000762 NOTIFY_SETUP(this);
763 if (paint) {
764 this->writePaint(*paint);
765 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000766
scroggo@google.com565254b2012-06-28 15:41:32 +0000767 size_t opBytesNeeded = sizeof(int32_t) * 2 + sizeof(bool);
768 if (!flatten) {
769 opBytesNeeded += sizeof(void*);
770 }
771 if (this->needOpBytes(opBytesNeeded)) {
772 this->writeOp(kDrawSprite_DrawOp, 0, bitmapIndex);
773 if (!flatten) {
774 fWriter.writePtr(const_cast<void*>(ptr));
775 }
scroggo@google.com16d1d0b2012-05-02 19:09:40 +0000776 fWriter.writeBool(paint != NULL);
777 fWriter.write32(left);
778 fWriter.write32(top);
779 }
reed@google.combb6992a2011-04-26 17:41:56 +0000780}
781
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000782void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
reed@google.combb6992a2011-04-26 17:41:56 +0000783 SkScalar y, const SkPaint& paint) {
784 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000785 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000786 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000787 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000788 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000789 fWriter.write32(byteLength);
790 fWriter.writePad(text, byteLength);
791 fWriter.writeScalar(x);
792 fWriter.writeScalar(y);
793 }
reed@google.combb6992a2011-04-26 17:41:56 +0000794 }
795}
796
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000797void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
reed@google.combb6992a2011-04-26 17:41:56 +0000798 const SkPoint pos[], const SkPaint& paint) {
799 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000800 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000801 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000802 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000803 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000804 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000805 fWriter.write32(byteLength);
806 fWriter.writePad(text, byteLength);
807 fWriter.write32(count);
808 fWriter.write(pos, count * sizeof(SkPoint));
809 }
reed@google.combb6992a2011-04-26 17:41:56 +0000810 }
811}
812
813void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
814 const SkScalar xpos[], SkScalar constY,
815 const SkPaint& paint) {
816 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000817 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000818 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000819 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000820 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000821 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000822 fWriter.write32(byteLength);
823 fWriter.writePad(text, byteLength);
824 fWriter.write32(count);
825 fWriter.write(xpos, count * sizeof(SkScalar));
826 fWriter.writeScalar(constY);
827 }
reed@google.combb6992a2011-04-26 17:41:56 +0000828 }
829}
830
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000831void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
832 const SkPath& path, const SkMatrix* matrix,
reed@google.combb6992a2011-04-26 17:41:56 +0000833 const SkPaint& paint) {
834 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000835 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000836 unsigned flags = 0;
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000837 size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000838 if (matrix) {
839 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000840 size += matrix->writeToMemory(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000841 }
reed@google.com31891582011-05-12 03:03:56 +0000842 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000843 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000844 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000845
reed@google.comacd471f2011-05-03 21:26:46 +0000846 fWriter.write32(byteLength);
847 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000848
djsollen@google.com94e75ee2012-06-08 18:30:46 +0000849 fWriter.writePath(path);
reed@google.comacd471f2011-05-03 21:26:46 +0000850 if (matrix) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000851 fWriter.writeMatrix(*matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000852 }
reed@google.combb6992a2011-04-26 17:41:56 +0000853 }
854 }
855}
856
857void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000858 // we want to playback the picture into individual draw calls
859 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000860}
861
reed@google.combb6992a2011-04-26 17:41:56 +0000862void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
863 const SkPoint vertices[], const SkPoint texs[],
864 const SkColor colors[], SkXfermode*,
865 const uint16_t indices[], int indexCount,
866 const SkPaint& paint) {
867 if (0 == vertexCount) {
868 return;
869 }
870
reed@google.comacd471f2011-05-03 21:26:46 +0000871 NOTIFY_SETUP(this);
872 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000873 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000874 unsigned flags = 0;
875 if (texs) {
876 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000877 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000878 }
879 if (colors) {
880 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000881 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000882 }
883 if (indices && indexCount > 0) {
884 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000885 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000886 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000887
reed@google.comacd471f2011-05-03 21:26:46 +0000888 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000889 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000890 fWriter.write32(mode);
891 fWriter.write32(vertexCount);
892 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
893 if (texs) {
894 fWriter.write(texs, vertexCount * sizeof(SkPoint));
895 }
896 if (colors) {
897 fWriter.write(colors, vertexCount * sizeof(SkColor));
898 }
reed@google.combb6992a2011-04-26 17:41:56 +0000899
reed@google.comacd471f2011-05-03 21:26:46 +0000900 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000901
reed@google.comacd471f2011-05-03 21:26:46 +0000902 if (indices && indexCount > 0) {
903 fWriter.write32(indexCount);
904 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
905 }
reed@google.combb6992a2011-04-26 17:41:56 +0000906 }
907}
908
reed@google.comacd471f2011-05-03 21:26:46 +0000909void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
910 if (size && ptr) {
911 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000912 unsigned data = 0;
913 if (size < (1 << DRAWOPS_DATA_BITS)) {
914 data = (unsigned)size;
915 }
reed@google.comacd471f2011-05-03 21:26:46 +0000916 if (this->needOpBytes(4 + SkAlign4(size))) {
917 this->writeOp(kDrawData_DrawOp, 0, data);
918 if (0 == data) {
919 fWriter.write32(size);
920 }
reed@google.combb6793b2011-05-05 15:18:15 +0000921 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000922 }
923 }
924}
925
926///////////////////////////////////////////////////////////////////////////////
927
928template <typename T> uint32_t castToU32(T value) {
929 union {
930 T fSrc;
931 uint32_t fDst;
932 } data;
933 data.fSrc = value;
934 return data.fDst;
935}
936
reed@google.com31891582011-05-12 03:03:56 +0000937void SkGPipeCanvas::writePaint(const SkPaint& paint) {
938 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000939 uint32_t storage[32];
940 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000941
942 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000943 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000944 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000945 }
946 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000947 *ptr++ = PaintOp_packOp(kColor_PaintOp);
948 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000949 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000950 }
951 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000952 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000953 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000954 }
955 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000956 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000957 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000958 }
959 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000960 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000961 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000962 }
963 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000964 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
965 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000966 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000967 }
968 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000969 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
970 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000971 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000972 }
973 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000974 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000975 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000976 }
977 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000978 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000979 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000980 }
981 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000982 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000983 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000984 }
985 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000986 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
987 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000988 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000989 }
990 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000991 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
992 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000993 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000994 }
995 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000996 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
997 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000998 base.setTextSkewX(paint.getTextSkewX());
999 }
1000
1001 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
1002 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +00001003 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
1004 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +00001005 }
reed@google.combb6992a2011-04-26 17:41:56 +00001006
reed@google.comb55d1182011-05-11 00:42:04 +00001007 for (int i = 0; i < kCount_PaintFlats; i++) {
1008 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
1009 SkASSERT(index >= 0 && index <= fFlatArray.count());
1010 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +00001011 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
1012 fCurrFlatIndex[i] = index;
1013 }
1014 }
1015
reed@google.comacd471f2011-05-03 21:26:46 +00001016 size_t size = (char*)ptr - (char*)storage;
1017 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +00001018 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +00001019 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +00001020 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +00001021// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +00001022 }
1023 }
reed@google.combb6992a2011-04-26 17:41:56 +00001024}
1025
1026///////////////////////////////////////////////////////////////////////////////
1027
1028#include "SkGPipe.h"
1029
reed@google.comacd471f2011-05-03 21:26:46 +00001030SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +00001031 fCanvas = NULL;
1032}
1033
1034SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +00001035 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +00001036 SkSafeUnref(fCanvas);
1037}
1038
scroggo@google.com565254b2012-06-28 15:41:32 +00001039SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +00001040 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +00001041 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +00001042 fFactorySet.reset();
1043 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
1044 (flags & kCrossProcess_Flag) ?
scroggo@google.com565254b2012-06-28 15:41:32 +00001045 &fFactorySet : NULL, flags));
reed@google.combb6992a2011-04-26 17:41:56 +00001046 }
1047 return fCanvas;
1048}
1049
1050void SkGPipeWriter::endRecording() {
1051 if (fCanvas) {
1052 fCanvas->finish();
1053 fCanvas->unref();
1054 fCanvas = NULL;
1055 }
1056}
1057