blob: f56fe2798b099ccc44a6c75e1092ceadc90983ba [file] [log] [blame]
reed@google.combb6992a2011-04-26 17:41:56 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "SkCanvas.h"
reed@google.com8a85d0c2011-06-24 19:12:12 +000019#include "SkData.h"
reed@google.combb6793b2011-05-05 15:18:15 +000020#include "SkDevice.h"
reed@google.combb6992a2011-04-26 17:41:56 +000021#include "SkPaint.h"
reed@google.comacd471f2011-05-03 21:26:46 +000022#include "SkGPipe.h"
reed@google.combb6992a2011-04-26 17:41:56 +000023#include "SkGPipePriv.h"
reed@google.comf5842f72011-05-04 18:30:04 +000024#include "SkStream.h"
reed@google.comb55d1182011-05-11 00:42:04 +000025#include "SkTSearch.h"
reed@google.comf5842f72011-05-04 18:30:04 +000026#include "SkTypeface.h"
reed@google.combb6992a2011-04-26 17:41:56 +000027#include "SkWriter32.h"
reed@google.comb55d1182011-05-11 00:42:04 +000028#include "SkColorFilter.h"
reed@google.com0faac1e2011-05-11 05:58:58 +000029#include "SkDrawLooper.h"
reed@google.comb55d1182011-05-11 00:42:04 +000030#include "SkMaskFilter.h"
31#include "SkRasterizer.h"
32#include "SkShader.h"
33
34static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
35 SkASSERT(paintFlat < kCount_PaintFlats);
36 switch (paintFlat) {
37 case kColorFilter_PaintFlat: return paint.getColorFilter();
reed@google.com0faac1e2011-05-11 05:58:58 +000038 case kDrawLooper_PaintFlat: return paint.getLooper();
reed@google.comb55d1182011-05-11 00:42:04 +000039 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
40 case kPathEffect_PaintFlat: return paint.getPathEffect();
41 case kRasterizer_PaintFlat: return paint.getRasterizer();
42 case kShader_PaintFlat: return paint.getShader();
43 case kXfermode_PaintFlat: return paint.getXfermode();
44 }
45 SkASSERT(!"never gets here");
46 return NULL;
47}
reed@google.combb6992a2011-04-26 17:41:56 +000048
reed@google.comacd471f2011-05-03 21:26:46 +000049static size_t estimateFlattenSize(const SkPath& path) {
50 int n = path.countPoints();
51 size_t bytes = 3 * sizeof(int32_t);
52 bytes += n * sizeof(SkPoint);
53 bytes += SkAlign4(n + 2); // verbs: add 2 for move/close extras
54
55#ifdef SK_DEBUG
56 {
57 SkWriter32 writer(1024);
58 path.flatten(writer);
59 SkASSERT(writer.size() <= bytes);
60 }
61#endif
62 return bytes;
63}
64
reed@google.comf5842f72011-05-04 18:30:04 +000065static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
66 SkASSERT(typeface);
67 SkDynamicMemoryWStream stream;
68 typeface->serialize(&stream);
69 size_t size = stream.getOffset();
70 if (writer) {
71 writer->write32(size);
reed@google.com8a85d0c2011-06-24 19:12:12 +000072 SkAutoDataUnref data(stream.copyToData());
73 writer->write(data.data(), size);
reed@google.comf5842f72011-05-04 18:30:04 +000074 }
75 return 4 + size;
76}
77
reed@google.combb6992a2011-04-26 17:41:56 +000078///////////////////////////////////////////////////////////////////////////////
79
80class SkGPipeCanvas : public SkCanvas {
81public:
reed@google.comdde09562011-05-23 12:21:05 +000082 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
reed@google.combb6992a2011-04-26 17:41:56 +000083 virtual ~SkGPipeCanvas();
84
85 void finish() {
86 if (!fDone) {
reed@google.comdbccc882011-07-08 18:53:39 +000087 if (this->needOpBytes()) {
88 this->writeOp(kDone_DrawOp);
89 this->doNotify();
90 }
reed@google.combb6992a2011-04-26 17:41:56 +000091 fDone = true;
92 }
93 }
94
95 // overrides from SkCanvas
96 virtual int save(SaveFlags);
97 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
98 virtual void restore();
99 virtual bool translate(SkScalar dx, SkScalar dy);
100 virtual bool scale(SkScalar sx, SkScalar sy);
101 virtual bool rotate(SkScalar degrees);
102 virtual bool skew(SkScalar sx, SkScalar sy);
103 virtual bool concat(const SkMatrix& matrix);
104 virtual void setMatrix(const SkMatrix& matrix);
105 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
106 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
107 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
108 virtual void clear(SkColor);
109 virtual void drawPaint(const SkPaint& paint);
110 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
111 const SkPaint&);
112 virtual void drawRect(const SkRect& rect, const SkPaint&);
113 virtual void drawPath(const SkPath& path, const SkPaint&);
114 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
115 const SkPaint*);
116 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
117 const SkRect& dst, const SkPaint*);
118 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
119 const SkPaint*);
120 virtual void drawSprite(const SkBitmap&, int left, int top,
121 const SkPaint*);
122 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
123 SkScalar y, const SkPaint&);
124 virtual void drawPosText(const void* text, size_t byteLength,
125 const SkPoint pos[], const SkPaint&);
126 virtual void drawPosTextH(const void* text, size_t byteLength,
127 const SkScalar xpos[], SkScalar constY, const SkPaint&);
128 virtual void drawTextOnPath(const void* text, size_t byteLength,
129 const SkPath& path, const SkMatrix* matrix,
130 const SkPaint&);
131 virtual void drawPicture(SkPicture& picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000132 virtual void drawVertices(VertexMode, int vertexCount,
133 const SkPoint vertices[], const SkPoint texs[],
134 const SkColor colors[], SkXfermode*,
135 const uint16_t indices[], int indexCount,
136 const SkPaint&);
137 virtual void drawData(const void*, size_t);
138
139private:
reed@google.comdde09562011-05-23 12:21:05 +0000140 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000141 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000142 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000143 size_t fBlockSize; // amount allocated for writer
144 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000145 bool fDone;
146
reed@google.comf5842f72011-05-04 18:30:04 +0000147 SkRefCntSet fTypefaceSet;
148
149 uint32_t getTypefaceID(SkTypeface*);
150
reed@google.comacd471f2011-05-03 21:26:46 +0000151 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000152 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
153 }
154
reed@google.comacd471f2011-05-03 21:26:46 +0000155 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000156 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
157 }
reed@google.comacd471f2011-05-03 21:26:46 +0000158
159 bool needOpBytes(size_t size = 0);
160
161 inline void doNotify() {
162 if (!fDone) {
163 size_t bytes = fWriter.size() - fBytesNotified;
164 fController->notifyWritten(bytes);
165 fBytesNotified += bytes;
166 }
167 }
reed@google.comb55d1182011-05-11 00:42:04 +0000168
169 struct FlatData {
170 uint32_t fIndex; // always > 0
171 uint32_t fSize;
172
173 void* data() { return (char*)this + sizeof(*this); }
174
175 static int Compare(const FlatData* a, const FlatData* b) {
176 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
177 }
178 };
179 SkTDArray<FlatData*> fFlatArray;
180 int fCurrFlatIndex[kCount_PaintFlats];
181 int flattenToIndex(SkFlattenable* obj, PaintFlats);
182
reed@google.com31891582011-05-12 03:03:56 +0000183 SkPaint fPaint;
184 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000185
reed@google.comacd471f2011-05-03 21:26:46 +0000186 class AutoPipeNotify {
187 public:
188 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
189 ~AutoPipeNotify() { fCanvas->doNotify(); }
190 private:
191 SkGPipeCanvas* fCanvas;
192 };
193 friend class AutoPipeNotify;
194
reed@google.combb6992a2011-04-26 17:41:56 +0000195 typedef SkCanvas INHERITED;
196};
197
reed@google.comb55d1182011-05-11 00:42:04 +0000198// return 0 for NULL (or unflattenable obj), or index-base-1
199int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
200 if (NULL == obj) {
201 return 0;
202 }
reed@google.comb55d1182011-05-11 00:42:04 +0000203
204 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.com6bac9472011-06-21 19:24:00 +0000205 tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
reed@google.comdde09562011-05-23 12:21:05 +0000206 tmpWriter.setFactoryRecorder(fFactorySet);
207
reed@google.comb55d1182011-05-11 00:42:04 +0000208 tmpWriter.writeFlattenable(obj);
209 size_t len = tmpWriter.size();
210 size_t allocSize = len + sizeof(FlatData);
211
212 SkAutoSMalloc<1024> storage(allocSize);
213 FlatData* flat = (FlatData*)storage.get();
214 flat->fSize = len;
215 tmpWriter.flatten(flat->data());
216
217 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
218 fFlatArray.count(), flat, sizeof(flat),
219 &FlatData::Compare);
220 if (index < 0) {
221 index = ~index;
222 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
223 memcpy(copy, flat, allocSize);
224 *fFlatArray.insert(index) = copy;
225 // call this after the insert, so that count() will have been grown
226 copy->fIndex = fFlatArray.count();
227// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
228
229 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000230 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000231 fWriter.write(copy->data(), len);
232 }
233 }
234 return fFlatArray[index]->fIndex;
235}
236
reed@google.combb6992a2011-04-26 17:41:56 +0000237///////////////////////////////////////////////////////////////////////////////
238
reed@google.comacd471f2011-05-03 21:26:46 +0000239#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000240
reed@google.comacd471f2011-05-03 21:26:46 +0000241SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000242 SkWriter32* writer, SkFactorySet* fset)
reed@google.com67908f22011-06-27 14:47:50 +0000243 : fWriter(*writer) {
244 fFactorySet = fset;
reed@google.comacd471f2011-05-03 21:26:46 +0000245 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000246 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000247 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000248 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000249
reed@google.combb6793b2011-05-05 15:18:15 +0000250 // we need a device to limit our clip
251 // should the caller give us the bounds?
yangsu@google.com06b4da162011-06-17 15:04:40 +0000252 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000253 SkBitmap bitmap;
254 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da162011-06-17 15:04:40 +0000255 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000256 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000257}
258
259SkGPipeCanvas::~SkGPipeCanvas() {
260 this->finish();
261
reed@google.comb55d1182011-05-11 00:42:04 +0000262 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000263}
264
reed@google.comacd471f2011-05-03 21:26:46 +0000265bool SkGPipeCanvas::needOpBytes(size_t needed) {
266 if (fDone) {
267 return false;
268 }
269
270 needed += 4; // size of DrawOp atom
271 if (fWriter.size() + needed > fBlockSize) {
272 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
273 if (NULL == block) {
274 fDone = true;
275 return false;
276 }
277 fWriter.reset(block, fBlockSize);
278 fBytesNotified = 0;
279 }
280 return true;
281}
282
reed@google.comf5842f72011-05-04 18:30:04 +0000283uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
284 uint32_t id = 0; // 0 means default/null typeface
285 if (face) {
286 id = fTypefaceSet.find(face);
287 if (0 == id) {
288 id = fTypefaceSet.add(face);
289 size_t size = writeTypeface(NULL, face);
290 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000291 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000292 writeTypeface(&fWriter, face);
293 }
294 }
295 }
296 return id;
297}
298
reed@google.combb6992a2011-04-26 17:41:56 +0000299///////////////////////////////////////////////////////////////////////////////
300
reed@google.comacd471f2011-05-03 21:26:46 +0000301#define NOTIFY_SETUP(canvas) \
302 AutoPipeNotify apn(canvas)
303
reed@google.combb6992a2011-04-26 17:41:56 +0000304int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000305 NOTIFY_SETUP(this);
306 if (this->needOpBytes()) {
307 this->writeOp(kSave_DrawOp, 0, flags);
308 }
reed@google.combb6992a2011-04-26 17:41:56 +0000309 return this->INHERITED::save(flags);
310}
311
312int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
313 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000314 NOTIFY_SETUP(this);
315 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000316 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000317
reed@google.combb6992a2011-04-26 17:41:56 +0000318 if (bounds) {
319 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000320 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000321 }
322 if (paint) {
323 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000324 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000325 }
326
reed@google.comacd471f2011-05-03 21:26:46 +0000327 if (this->needOpBytes(size)) {
328 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
329 if (bounds) {
330 fWriter.writeRect(*bounds);
331 }
reed@google.combb6992a2011-04-26 17:41:56 +0000332 }
333
334 // we just pass on the save, so we don't create a layer
335 return this->INHERITED::save(saveFlags);
336}
337
338void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000339 NOTIFY_SETUP(this);
340 if (this->needOpBytes()) {
341 this->writeOp(kRestore_DrawOp);
342 }
reed@google.combb6992a2011-04-26 17:41:56 +0000343 this->INHERITED::restore();
344}
345
346bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
347 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000348 NOTIFY_SETUP(this);
349 if (this->needOpBytes(2 * sizeof(SkScalar))) {
350 this->writeOp(kTranslate_DrawOp);
351 fWriter.writeScalar(dx);
352 fWriter.writeScalar(dy);
353 }
reed@google.combb6992a2011-04-26 17:41:56 +0000354 }
355 return this->INHERITED::translate(dx, dy);
356}
357
358bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
359 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000360 NOTIFY_SETUP(this);
361 if (this->needOpBytes(2 * sizeof(SkScalar))) {
362 this->writeOp(kScale_DrawOp);
363 fWriter.writeScalar(sx);
364 fWriter.writeScalar(sy);
365 }
reed@google.combb6992a2011-04-26 17:41:56 +0000366 }
367 return this->INHERITED::scale(sx, sy);
368}
369
370bool SkGPipeCanvas::rotate(SkScalar degrees) {
371 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000372 NOTIFY_SETUP(this);
373 if (this->needOpBytes(sizeof(SkScalar))) {
374 this->writeOp(kRotate_DrawOp);
375 fWriter.writeScalar(degrees);
376 }
reed@google.combb6992a2011-04-26 17:41:56 +0000377 }
378 return this->INHERITED::rotate(degrees);
379}
380
381bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
382 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000383 NOTIFY_SETUP(this);
384 if (this->needOpBytes(2 * sizeof(SkScalar))) {
385 this->writeOp(kSkew_DrawOp);
386 fWriter.writeScalar(sx);
387 fWriter.writeScalar(sy);
388 }
reed@google.combb6992a2011-04-26 17:41:56 +0000389 }
390 return this->INHERITED::skew(sx, sy);
391}
392
393bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
394 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000395 NOTIFY_SETUP(this);
396 if (this->needOpBytes(matrix.flatten(NULL))) {
397 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000398 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000399 }
reed@google.combb6992a2011-04-26 17:41:56 +0000400 }
401 return this->INHERITED::concat(matrix);
402}
403
404void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000405 NOTIFY_SETUP(this);
406 if (this->needOpBytes(matrix.flatten(NULL))) {
407 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000408 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000409 }
reed@google.combb6992a2011-04-26 17:41:56 +0000410 this->INHERITED::setMatrix(matrix);
411}
412
413bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000414 NOTIFY_SETUP(this);
415 if (this->needOpBytes(sizeof(SkRect))) {
416 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
417 fWriter.writeRect(rect);
418 }
reed@google.combb6992a2011-04-26 17:41:56 +0000419 return this->INHERITED::clipRect(rect, rgnOp);
420}
421
422bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000423 NOTIFY_SETUP(this);
424 if (this->needOpBytes(estimateFlattenSize(path))) {
425 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
426 path.flatten(fWriter);
427 }
reed@google.combb6992a2011-04-26 17:41:56 +0000428 // we just pass on the bounds of the path
429 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
430}
431
432bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000433 NOTIFY_SETUP(this);
434 if (this->needOpBytes(region.flatten(NULL))) {
435 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000436 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000437 }
reed@google.combb6992a2011-04-26 17:41:56 +0000438 return this->INHERITED::clipRegion(region, rgnOp);
439}
440
441///////////////////////////////////////////////////////////////////////////////
442
443void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000444 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000445 unsigned flags = 0;
446 if (color) {
447 flags |= kClear_HasColor_DrawOpFlag;
448 }
reed@google.comacd471f2011-05-03 21:26:46 +0000449 if (this->needOpBytes(sizeof(SkColor))) {
450 this->writeOp(kDrawClear_DrawOp, flags, 0);
451 if (color) {
452 fWriter.write32(color);
453 }
reed@google.combb6992a2011-04-26 17:41:56 +0000454 }
455}
456
457void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000458 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000459 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000460 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000461 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000462 }
reed@google.combb6992a2011-04-26 17:41:56 +0000463}
464
465void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
466 const SkPoint pts[], const SkPaint& paint) {
467 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000468 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000469 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000470 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000471 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000472 fWriter.write32(count);
473 fWriter.write(pts, count * sizeof(SkPoint));
474 }
reed@google.combb6992a2011-04-26 17:41:56 +0000475 }
476}
477
478void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000479 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000480 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000481 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000482 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000483 fWriter.writeRect(rect);
484 }
reed@google.combb6992a2011-04-26 17:41:56 +0000485}
486
487void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000488 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000489 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000490 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000491 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000492 path.flatten(fWriter);
493 }
reed@google.combb6992a2011-04-26 17:41:56 +0000494}
495
496void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
497 const SkPaint*) {
498 UNIMPLEMENTED
499}
500
501void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
502 const SkRect& dst, const SkPaint*) {
503 UNIMPLEMENTED
504}
505
506void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
507 const SkPaint*) {
508 UNIMPLEMENTED
509}
510
511void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
512 const SkPaint*) {
513 UNIMPLEMENTED
514}
515
516void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
517 SkScalar y, const SkPaint& paint) {
518 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000519 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000520 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000521 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000522 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000523 fWriter.write32(byteLength);
524 fWriter.writePad(text, byteLength);
525 fWriter.writeScalar(x);
526 fWriter.writeScalar(y);
527 }
reed@google.combb6992a2011-04-26 17:41:56 +0000528 }
529}
530
531void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
532 const SkPoint pos[], const SkPaint& paint) {
533 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000534 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000535 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000536 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000537 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000538 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000539 fWriter.write32(byteLength);
540 fWriter.writePad(text, byteLength);
541 fWriter.write32(count);
542 fWriter.write(pos, count * sizeof(SkPoint));
543 }
reed@google.combb6992a2011-04-26 17:41:56 +0000544 }
545}
546
547void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
548 const SkScalar xpos[], SkScalar constY,
549 const SkPaint& paint) {
550 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000551 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000552 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000553 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000554 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000555 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000556 fWriter.write32(byteLength);
557 fWriter.writePad(text, byteLength);
558 fWriter.write32(count);
559 fWriter.write(xpos, count * sizeof(SkScalar));
560 fWriter.writeScalar(constY);
561 }
reed@google.combb6992a2011-04-26 17:41:56 +0000562 }
563}
564
565void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
566 const SkPath& path, const SkMatrix* matrix,
567 const SkPaint& paint) {
568 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000569 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000570 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000571 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000572 if (matrix) {
573 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000574 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000575 }
reed@google.com31891582011-05-12 03:03:56 +0000576 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000577 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000578 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000579
reed@google.comacd471f2011-05-03 21:26:46 +0000580 fWriter.write32(byteLength);
581 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000582
reed@google.comacd471f2011-05-03 21:26:46 +0000583 path.flatten(fWriter);
584 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000585 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000586 }
reed@google.combb6992a2011-04-26 17:41:56 +0000587 }
588 }
589}
590
591void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000592 // we want to playback the picture into individual draw calls
593 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000594}
595
reed@google.combb6992a2011-04-26 17:41:56 +0000596void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
597 const SkPoint vertices[], const SkPoint texs[],
598 const SkColor colors[], SkXfermode*,
599 const uint16_t indices[], int indexCount,
600 const SkPaint& paint) {
601 if (0 == vertexCount) {
602 return;
603 }
604
reed@google.comacd471f2011-05-03 21:26:46 +0000605 NOTIFY_SETUP(this);
606 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000607 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000608 unsigned flags = 0;
609 if (texs) {
610 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000611 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000612 }
613 if (colors) {
614 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000615 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000616 }
617 if (indices && indexCount > 0) {
618 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000619 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000620 }
621
reed@google.comacd471f2011-05-03 21:26:46 +0000622 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000623 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000624 fWriter.write32(mode);
625 fWriter.write32(vertexCount);
626 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
627 if (texs) {
628 fWriter.write(texs, vertexCount * sizeof(SkPoint));
629 }
630 if (colors) {
631 fWriter.write(colors, vertexCount * sizeof(SkColor));
632 }
reed@google.combb6992a2011-04-26 17:41:56 +0000633
reed@google.comacd471f2011-05-03 21:26:46 +0000634 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000635
reed@google.comacd471f2011-05-03 21:26:46 +0000636 if (indices && indexCount > 0) {
637 fWriter.write32(indexCount);
638 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
639 }
reed@google.combb6992a2011-04-26 17:41:56 +0000640 }
641}
642
reed@google.comacd471f2011-05-03 21:26:46 +0000643void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
644 if (size && ptr) {
645 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000646 unsigned data = 0;
647 if (size < (1 << DRAWOPS_DATA_BITS)) {
648 data = (unsigned)size;
649 }
reed@google.comacd471f2011-05-03 21:26:46 +0000650 if (this->needOpBytes(4 + SkAlign4(size))) {
651 this->writeOp(kDrawData_DrawOp, 0, data);
652 if (0 == data) {
653 fWriter.write32(size);
654 }
reed@google.combb6793b2011-05-05 15:18:15 +0000655 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000656 }
657 }
658}
659
660///////////////////////////////////////////////////////////////////////////////
661
662template <typename T> uint32_t castToU32(T value) {
663 union {
664 T fSrc;
665 uint32_t fDst;
666 } data;
667 data.fSrc = value;
668 return data.fDst;
669}
670
reed@google.com31891582011-05-12 03:03:56 +0000671void SkGPipeCanvas::writePaint(const SkPaint& paint) {
672 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000673 uint32_t storage[32];
674 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000675
676 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000677 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000678 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000679 }
680 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000681 *ptr++ = PaintOp_packOp(kColor_PaintOp);
682 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000683 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000684 }
685 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000686 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000687 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000688 }
689 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000690 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000691 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000692 }
693 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000694 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000695 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000696 }
697 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000698 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
699 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000700 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000701 }
702 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000703 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
704 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000705 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000706 }
707 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000708 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000709 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000710 }
711 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000712 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000713 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000714 }
715 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000716 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000717 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000718 }
719 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000720 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
721 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000722 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000723 }
724 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000725 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
726 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000727 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000728 }
729 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000730 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
731 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000732 base.setTextSkewX(paint.getTextSkewX());
733 }
734
735 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
736 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000737 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
738 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000739 }
reed@google.combb6992a2011-04-26 17:41:56 +0000740
reed@google.comb55d1182011-05-11 00:42:04 +0000741 for (int i = 0; i < kCount_PaintFlats; i++) {
742 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
743 SkASSERT(index >= 0 && index <= fFlatArray.count());
744 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000745 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
746 fCurrFlatIndex[i] = index;
747 }
748 }
749
reed@google.comacd471f2011-05-03 21:26:46 +0000750 size_t size = (char*)ptr - (char*)storage;
751 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000752 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000753 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000754 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000755// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000756 }
757 }
reed@google.combb6992a2011-04-26 17:41:56 +0000758}
759
760///////////////////////////////////////////////////////////////////////////////
761
762#include "SkGPipe.h"
763
reed@google.comacd471f2011-05-03 21:26:46 +0000764SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000765 fCanvas = NULL;
766}
767
768SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000769 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000770 SkSafeUnref(fCanvas);
771}
772
reed@google.comdde09562011-05-23 12:21:05 +0000773SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
774 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000775 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000776 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000777 fFactorySet.reset();
778 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
779 (flags & kCrossProcess_Flag) ?
780 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000781 }
782 return fCanvas;
783}
784
785void SkGPipeWriter::endRecording() {
786 if (fCanvas) {
787 fCanvas->finish();
788 fCanvas->unref();
789 fCanvas = NULL;
790 }
791}
792