blob: 5e8ba3dd2abec447dd1a82e6c9d1739a1e09c98d [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.combb6793b2011-05-05 15:18:15 +000019#include "SkDevice.h"
reed@google.combb6992a2011-04-26 17:41:56 +000020#include "SkPaint.h"
reed@google.comacd471f2011-05-03 21:26:46 +000021#include "SkGPipe.h"
reed@google.combb6992a2011-04-26 17:41:56 +000022#include "SkGPipePriv.h"
reed@google.comf5842f72011-05-04 18:30:04 +000023#include "SkStream.h"
reed@google.comb55d1182011-05-11 00:42:04 +000024#include "SkTSearch.h"
reed@google.comf5842f72011-05-04 18:30:04 +000025#include "SkTypeface.h"
reed@google.combb6992a2011-04-26 17:41:56 +000026#include "SkWriter32.h"
reed@google.comb55d1182011-05-11 00:42:04 +000027#include "SkColorFilter.h"
reed@google.com0faac1e2011-05-11 05:58:58 +000028#include "SkDrawLooper.h"
reed@google.comb55d1182011-05-11 00:42:04 +000029#include "SkMaskFilter.h"
30#include "SkRasterizer.h"
31#include "SkShader.h"
32
33static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
34 SkASSERT(paintFlat < kCount_PaintFlats);
35 switch (paintFlat) {
36 case kColorFilter_PaintFlat: return paint.getColorFilter();
reed@google.com0faac1e2011-05-11 05:58:58 +000037 case kDrawLooper_PaintFlat: return paint.getLooper();
reed@google.comb55d1182011-05-11 00:42:04 +000038 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
39 case kPathEffect_PaintFlat: return paint.getPathEffect();
40 case kRasterizer_PaintFlat: return paint.getRasterizer();
41 case kShader_PaintFlat: return paint.getShader();
42 case kXfermode_PaintFlat: return paint.getXfermode();
43 }
44 SkASSERT(!"never gets here");
45 return NULL;
46}
reed@google.combb6992a2011-04-26 17:41:56 +000047
reed@google.comacd471f2011-05-03 21:26:46 +000048static size_t estimateFlattenSize(const SkPath& path) {
49 int n = path.countPoints();
50 size_t bytes = 3 * sizeof(int32_t);
51 bytes += n * sizeof(SkPoint);
52 bytes += SkAlign4(n + 2); // verbs: add 2 for move/close extras
53
54#ifdef SK_DEBUG
55 {
56 SkWriter32 writer(1024);
57 path.flatten(writer);
58 SkASSERT(writer.size() <= bytes);
59 }
60#endif
61 return bytes;
62}
63
reed@google.comf5842f72011-05-04 18:30:04 +000064static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
65 SkASSERT(typeface);
66 SkDynamicMemoryWStream stream;
67 typeface->serialize(&stream);
68 size_t size = stream.getOffset();
69 if (writer) {
70 writer->write32(size);
71 writer->write(stream.getStream(), size);
72 }
73 return 4 + size;
74}
75
reed@google.combb6992a2011-04-26 17:41:56 +000076///////////////////////////////////////////////////////////////////////////////
77
78class SkGPipeCanvas : public SkCanvas {
79public:
reed@google.comdde09562011-05-23 12:21:05 +000080 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
reed@google.combb6992a2011-04-26 17:41:56 +000081 virtual ~SkGPipeCanvas();
82
83 void finish() {
84 if (!fDone) {
85 this->writeOp(kDone_DrawOp);
86 fDone = true;
87 }
88 }
89
90 // overrides from SkCanvas
91 virtual int save(SaveFlags);
92 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
93 virtual void restore();
94 virtual bool translate(SkScalar dx, SkScalar dy);
95 virtual bool scale(SkScalar sx, SkScalar sy);
96 virtual bool rotate(SkScalar degrees);
97 virtual bool skew(SkScalar sx, SkScalar sy);
98 virtual bool concat(const SkMatrix& matrix);
99 virtual void setMatrix(const SkMatrix& matrix);
100 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
101 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
102 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
103 virtual void clear(SkColor);
104 virtual void drawPaint(const SkPaint& paint);
105 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
106 const SkPaint&);
107 virtual void drawRect(const SkRect& rect, const SkPaint&);
108 virtual void drawPath(const SkPath& path, const SkPaint&);
109 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
110 const SkPaint*);
111 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
112 const SkRect& dst, const SkPaint*);
113 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
114 const SkPaint*);
115 virtual void drawSprite(const SkBitmap&, int left, int top,
116 const SkPaint*);
117 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
118 SkScalar y, const SkPaint&);
119 virtual void drawPosText(const void* text, size_t byteLength,
120 const SkPoint pos[], const SkPaint&);
121 virtual void drawPosTextH(const void* text, size_t byteLength,
122 const SkScalar xpos[], SkScalar constY, const SkPaint&);
123 virtual void drawTextOnPath(const void* text, size_t byteLength,
124 const SkPath& path, const SkMatrix* matrix,
125 const SkPaint&);
126 virtual void drawPicture(SkPicture& picture);
127 virtual void drawShape(SkShape*);
128 virtual void drawVertices(VertexMode, int vertexCount,
129 const SkPoint vertices[], const SkPoint texs[],
130 const SkColor colors[], SkXfermode*,
131 const uint16_t indices[], int indexCount,
132 const SkPaint&);
133 virtual void drawData(const void*, size_t);
134
135private:
reed@google.comdde09562011-05-23 12:21:05 +0000136 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000137 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000138 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000139 size_t fBlockSize; // amount allocated for writer
140 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000141 bool fDone;
142
reed@google.comf5842f72011-05-04 18:30:04 +0000143 SkRefCntSet fTypefaceSet;
144
145 uint32_t getTypefaceID(SkTypeface*);
146
reed@google.comacd471f2011-05-03 21:26:46 +0000147 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000148 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
149 }
150
reed@google.comacd471f2011-05-03 21:26:46 +0000151 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000152 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
153 }
reed@google.comacd471f2011-05-03 21:26:46 +0000154
155 bool needOpBytes(size_t size = 0);
156
157 inline void doNotify() {
158 if (!fDone) {
159 size_t bytes = fWriter.size() - fBytesNotified;
160 fController->notifyWritten(bytes);
161 fBytesNotified += bytes;
162 }
163 }
reed@google.comb55d1182011-05-11 00:42:04 +0000164
165 struct FlatData {
166 uint32_t fIndex; // always > 0
167 uint32_t fSize;
168
169 void* data() { return (char*)this + sizeof(*this); }
170
171 static int Compare(const FlatData* a, const FlatData* b) {
172 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
173 }
174 };
175 SkTDArray<FlatData*> fFlatArray;
176 int fCurrFlatIndex[kCount_PaintFlats];
177 int flattenToIndex(SkFlattenable* obj, PaintFlats);
178
reed@google.com31891582011-05-12 03:03:56 +0000179 SkPaint fPaint;
180 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000181
reed@google.comacd471f2011-05-03 21:26:46 +0000182 class AutoPipeNotify {
183 public:
184 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
185 ~AutoPipeNotify() { fCanvas->doNotify(); }
186 private:
187 SkGPipeCanvas* fCanvas;
188 };
189 friend class AutoPipeNotify;
190
reed@google.combb6992a2011-04-26 17:41:56 +0000191 typedef SkCanvas INHERITED;
192};
193
reed@google.comb55d1182011-05-11 00:42:04 +0000194// return 0 for NULL (or unflattenable obj), or index-base-1
195int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
196 if (NULL == obj) {
197 return 0;
198 }
199
200 SkFlattenable::Factory fact = obj->getFactory();
201 if (NULL == fact) {
202 return 0;
203 }
204
reed@google.comdde09562011-05-23 12:21:05 +0000205 if (fFactorySet) {
206 uint32_t id = fFactorySet->find((void*)fact);
207 if (0 == id) {
208 const char* name = SkFlattenable::FactoryToName(fact);
209 if (NULL == name) {
210 return 0;
211 }
212 size_t len = strlen(name);
213 size_t size = SkWriter32::WriteStringSize(name, len);
214 if (!this->needOpBytes(size)) {
215 return 0;
216 }
217 unsigned id = fFactorySet->add(fact);
218 this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
219 fWriter.writeString(name, len);
220 }
221 }
222
reed@google.comb55d1182011-05-11 00:42:04 +0000223 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.comdde09562011-05-23 12:21:05 +0000224 tmpWriter.setFactoryRecorder(fFactorySet);
225
reed@google.comb55d1182011-05-11 00:42:04 +0000226 tmpWriter.writeFlattenable(obj);
227 size_t len = tmpWriter.size();
228 size_t allocSize = len + sizeof(FlatData);
229
230 SkAutoSMalloc<1024> storage(allocSize);
231 FlatData* flat = (FlatData*)storage.get();
232 flat->fSize = len;
233 tmpWriter.flatten(flat->data());
234
235 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
236 fFlatArray.count(), flat, sizeof(flat),
237 &FlatData::Compare);
238 if (index < 0) {
239 index = ~index;
240 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
241 memcpy(copy, flat, allocSize);
242 *fFlatArray.insert(index) = copy;
243 // call this after the insert, so that count() will have been grown
244 copy->fIndex = fFlatArray.count();
245// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
246
247 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000248 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000249 fWriter.write(copy->data(), len);
250 }
251 }
252 return fFlatArray[index]->fIndex;
253}
254
reed@google.combb6992a2011-04-26 17:41:56 +0000255///////////////////////////////////////////////////////////////////////////////
256
reed@google.comacd471f2011-05-03 21:26:46 +0000257#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000258
reed@google.comacd471f2011-05-03 21:26:46 +0000259SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000260 SkWriter32* writer, SkFactorySet* fset)
261 : fWriter(*writer), fFactorySet(fset) {
reed@google.comacd471f2011-05-03 21:26:46 +0000262 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000263 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000264 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000265 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000266
reed@google.combb6793b2011-05-05 15:18:15 +0000267 // we need a device to limit our clip
268 // should the caller give us the bounds?
269 SkBitmap bitmap;
270 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
271 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
272 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000273}
274
275SkGPipeCanvas::~SkGPipeCanvas() {
276 this->finish();
277
reed@google.comb55d1182011-05-11 00:42:04 +0000278 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000279}
280
reed@google.comacd471f2011-05-03 21:26:46 +0000281bool SkGPipeCanvas::needOpBytes(size_t needed) {
282 if (fDone) {
283 return false;
284 }
285
286 needed += 4; // size of DrawOp atom
287 if (fWriter.size() + needed > fBlockSize) {
288 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
289 if (NULL == block) {
290 fDone = true;
291 return false;
292 }
293 fWriter.reset(block, fBlockSize);
294 fBytesNotified = 0;
295 }
296 return true;
297}
298
reed@google.comf5842f72011-05-04 18:30:04 +0000299uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
300 uint32_t id = 0; // 0 means default/null typeface
301 if (face) {
302 id = fTypefaceSet.find(face);
303 if (0 == id) {
304 id = fTypefaceSet.add(face);
305 size_t size = writeTypeface(NULL, face);
306 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000307 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000308 writeTypeface(&fWriter, face);
309 }
310 }
311 }
312 return id;
313}
314
reed@google.combb6992a2011-04-26 17:41:56 +0000315///////////////////////////////////////////////////////////////////////////////
316
reed@google.comacd471f2011-05-03 21:26:46 +0000317#define NOTIFY_SETUP(canvas) \
318 AutoPipeNotify apn(canvas)
319
reed@google.combb6992a2011-04-26 17:41:56 +0000320int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000321 NOTIFY_SETUP(this);
322 if (this->needOpBytes()) {
323 this->writeOp(kSave_DrawOp, 0, flags);
324 }
reed@google.combb6992a2011-04-26 17:41:56 +0000325 return this->INHERITED::save(flags);
326}
327
328int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
329 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000330 NOTIFY_SETUP(this);
331 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000332 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000333
reed@google.combb6992a2011-04-26 17:41:56 +0000334 if (bounds) {
335 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000336 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000337 }
338 if (paint) {
339 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000340 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000341 }
342
reed@google.comacd471f2011-05-03 21:26:46 +0000343 if (this->needOpBytes(size)) {
344 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
345 if (bounds) {
346 fWriter.writeRect(*bounds);
347 }
reed@google.combb6992a2011-04-26 17:41:56 +0000348 }
349
350 // we just pass on the save, so we don't create a layer
351 return this->INHERITED::save(saveFlags);
352}
353
354void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000355 NOTIFY_SETUP(this);
356 if (this->needOpBytes()) {
357 this->writeOp(kRestore_DrawOp);
358 }
reed@google.combb6992a2011-04-26 17:41:56 +0000359 this->INHERITED::restore();
360}
361
362bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
363 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000364 NOTIFY_SETUP(this);
365 if (this->needOpBytes(2 * sizeof(SkScalar))) {
366 this->writeOp(kTranslate_DrawOp);
367 fWriter.writeScalar(dx);
368 fWriter.writeScalar(dy);
369 }
reed@google.combb6992a2011-04-26 17:41:56 +0000370 }
371 return this->INHERITED::translate(dx, dy);
372}
373
374bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
375 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000376 NOTIFY_SETUP(this);
377 if (this->needOpBytes(2 * sizeof(SkScalar))) {
378 this->writeOp(kScale_DrawOp);
379 fWriter.writeScalar(sx);
380 fWriter.writeScalar(sy);
381 }
reed@google.combb6992a2011-04-26 17:41:56 +0000382 }
383 return this->INHERITED::scale(sx, sy);
384}
385
386bool SkGPipeCanvas::rotate(SkScalar degrees) {
387 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000388 NOTIFY_SETUP(this);
389 if (this->needOpBytes(sizeof(SkScalar))) {
390 this->writeOp(kRotate_DrawOp);
391 fWriter.writeScalar(degrees);
392 }
reed@google.combb6992a2011-04-26 17:41:56 +0000393 }
394 return this->INHERITED::rotate(degrees);
395}
396
397bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
398 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000399 NOTIFY_SETUP(this);
400 if (this->needOpBytes(2 * sizeof(SkScalar))) {
401 this->writeOp(kSkew_DrawOp);
402 fWriter.writeScalar(sx);
403 fWriter.writeScalar(sy);
404 }
reed@google.combb6992a2011-04-26 17:41:56 +0000405 }
406 return this->INHERITED::skew(sx, sy);
407}
408
409bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
410 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000411 NOTIFY_SETUP(this);
412 if (this->needOpBytes(matrix.flatten(NULL))) {
413 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000414 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000415 }
reed@google.combb6992a2011-04-26 17:41:56 +0000416 }
417 return this->INHERITED::concat(matrix);
418}
419
420void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000421 NOTIFY_SETUP(this);
422 if (this->needOpBytes(matrix.flatten(NULL))) {
423 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000424 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000425 }
reed@google.combb6992a2011-04-26 17:41:56 +0000426 this->INHERITED::setMatrix(matrix);
427}
428
429bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000430 NOTIFY_SETUP(this);
431 if (this->needOpBytes(sizeof(SkRect))) {
432 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
433 fWriter.writeRect(rect);
434 }
reed@google.combb6992a2011-04-26 17:41:56 +0000435 return this->INHERITED::clipRect(rect, rgnOp);
436}
437
438bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000439 NOTIFY_SETUP(this);
440 if (this->needOpBytes(estimateFlattenSize(path))) {
441 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
442 path.flatten(fWriter);
443 }
reed@google.combb6992a2011-04-26 17:41:56 +0000444 // we just pass on the bounds of the path
445 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
446}
447
448bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000449 NOTIFY_SETUP(this);
450 if (this->needOpBytes(region.flatten(NULL))) {
451 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000452 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000453 }
reed@google.combb6992a2011-04-26 17:41:56 +0000454 return this->INHERITED::clipRegion(region, rgnOp);
455}
456
457///////////////////////////////////////////////////////////////////////////////
458
459void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000460 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000461 unsigned flags = 0;
462 if (color) {
463 flags |= kClear_HasColor_DrawOpFlag;
464 }
reed@google.comacd471f2011-05-03 21:26:46 +0000465 if (this->needOpBytes(sizeof(SkColor))) {
466 this->writeOp(kDrawClear_DrawOp, flags, 0);
467 if (color) {
468 fWriter.write32(color);
469 }
reed@google.combb6992a2011-04-26 17:41:56 +0000470 }
471}
472
473void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000474 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000475 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000476 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000477 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000478 }
reed@google.combb6992a2011-04-26 17:41:56 +0000479}
480
481void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
482 const SkPoint pts[], const SkPaint& paint) {
483 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000484 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000485 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000486 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000487 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000488 fWriter.write32(count);
489 fWriter.write(pts, count * sizeof(SkPoint));
490 }
reed@google.combb6992a2011-04-26 17:41:56 +0000491 }
492}
493
494void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000495 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000496 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000497 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000498 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000499 fWriter.writeRect(rect);
500 }
reed@google.combb6992a2011-04-26 17:41:56 +0000501}
502
503void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000504 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000505 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000506 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000507 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000508 path.flatten(fWriter);
509 }
reed@google.combb6992a2011-04-26 17:41:56 +0000510}
511
512void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
513 const SkPaint*) {
514 UNIMPLEMENTED
515}
516
517void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
518 const SkRect& dst, const SkPaint*) {
519 UNIMPLEMENTED
520}
521
522void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
523 const SkPaint*) {
524 UNIMPLEMENTED
525}
526
527void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
528 const SkPaint*) {
529 UNIMPLEMENTED
530}
531
532void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
533 SkScalar y, const SkPaint& paint) {
534 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000535 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000536 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000537 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000538 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000539 fWriter.write32(byteLength);
540 fWriter.writePad(text, byteLength);
541 fWriter.writeScalar(x);
542 fWriter.writeScalar(y);
543 }
reed@google.combb6992a2011-04-26 17:41:56 +0000544 }
545}
546
547void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
548 const SkPoint pos[], const SkPaint& paint) {
549 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000550 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000551 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000552 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000553 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000554 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000555 fWriter.write32(byteLength);
556 fWriter.writePad(text, byteLength);
557 fWriter.write32(count);
558 fWriter.write(pos, count * sizeof(SkPoint));
559 }
reed@google.combb6992a2011-04-26 17:41:56 +0000560 }
561}
562
563void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
564 const SkScalar xpos[], SkScalar constY,
565 const SkPaint& paint) {
566 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000567 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000568 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000569 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000570 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000571 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000572 fWriter.write32(byteLength);
573 fWriter.writePad(text, byteLength);
574 fWriter.write32(count);
575 fWriter.write(xpos, count * sizeof(SkScalar));
576 fWriter.writeScalar(constY);
577 }
reed@google.combb6992a2011-04-26 17:41:56 +0000578 }
579}
580
581void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
582 const SkPath& path, const SkMatrix* matrix,
583 const SkPaint& paint) {
584 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000585 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000586 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000587 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000588 if (matrix) {
589 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000590 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000591 }
reed@google.com31891582011-05-12 03:03:56 +0000592 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000593 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000594 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000595
reed@google.comacd471f2011-05-03 21:26:46 +0000596 fWriter.write32(byteLength);
597 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000598
reed@google.comacd471f2011-05-03 21:26:46 +0000599 path.flatten(fWriter);
600 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000601 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000602 }
reed@google.combb6992a2011-04-26 17:41:56 +0000603 }
604 }
605}
606
607void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000608 // we want to playback the picture into individual draw calls
609 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000610}
611
612void SkGPipeCanvas::drawShape(SkShape* shape) {
613 UNIMPLEMENTED
614}
615
616void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
617 const SkPoint vertices[], const SkPoint texs[],
618 const SkColor colors[], SkXfermode*,
619 const uint16_t indices[], int indexCount,
620 const SkPaint& paint) {
621 if (0 == vertexCount) {
622 return;
623 }
624
reed@google.comacd471f2011-05-03 21:26:46 +0000625 NOTIFY_SETUP(this);
626 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000627 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000628 unsigned flags = 0;
629 if (texs) {
630 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000631 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000632 }
633 if (colors) {
634 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000635 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000636 }
637 if (indices && indexCount > 0) {
638 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000639 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000640 }
641
reed@google.comacd471f2011-05-03 21:26:46 +0000642 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000643 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000644 fWriter.write32(mode);
645 fWriter.write32(vertexCount);
646 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
647 if (texs) {
648 fWriter.write(texs, vertexCount * sizeof(SkPoint));
649 }
650 if (colors) {
651 fWriter.write(colors, vertexCount * sizeof(SkColor));
652 }
reed@google.combb6992a2011-04-26 17:41:56 +0000653
reed@google.comacd471f2011-05-03 21:26:46 +0000654 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000655
reed@google.comacd471f2011-05-03 21:26:46 +0000656 if (indices && indexCount > 0) {
657 fWriter.write32(indexCount);
658 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
659 }
reed@google.combb6992a2011-04-26 17:41:56 +0000660 }
661}
662
reed@google.comacd471f2011-05-03 21:26:46 +0000663void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
664 if (size && ptr) {
665 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000666 unsigned data = 0;
667 if (size < (1 << DRAWOPS_DATA_BITS)) {
668 data = (unsigned)size;
669 }
reed@google.comacd471f2011-05-03 21:26:46 +0000670 if (this->needOpBytes(4 + SkAlign4(size))) {
671 this->writeOp(kDrawData_DrawOp, 0, data);
672 if (0 == data) {
673 fWriter.write32(size);
674 }
reed@google.combb6793b2011-05-05 15:18:15 +0000675 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000676 }
677 }
678}
679
680///////////////////////////////////////////////////////////////////////////////
681
682template <typename T> uint32_t castToU32(T value) {
683 union {
684 T fSrc;
685 uint32_t fDst;
686 } data;
687 data.fSrc = value;
688 return data.fDst;
689}
690
reed@google.com31891582011-05-12 03:03:56 +0000691void SkGPipeCanvas::writePaint(const SkPaint& paint) {
692 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000693 uint32_t storage[32];
694 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000695
696 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000697 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000698 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000699 }
700 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000701 *ptr++ = PaintOp_packOp(kColor_PaintOp);
702 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000703 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000704 }
705 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000706 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000707 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000708 }
709 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000710 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000711 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000712 }
713 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000714 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000715 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000716 }
717 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000718 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
719 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000720 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000721 }
722 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000723 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
724 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000725 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000726 }
727 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000728 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000729 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000730 }
731 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000732 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000733 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000734 }
735 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000736 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000737 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000738 }
739 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000740 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
741 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000742 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000743 }
744 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000745 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
746 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000747 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000748 }
749 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000750 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
751 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000752 base.setTextSkewX(paint.getTextSkewX());
753 }
754
755 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
756 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000757 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
758 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000759 }
reed@google.combb6992a2011-04-26 17:41:56 +0000760
reed@google.comb55d1182011-05-11 00:42:04 +0000761 for (int i = 0; i < kCount_PaintFlats; i++) {
762 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
763 SkASSERT(index >= 0 && index <= fFlatArray.count());
764 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000765 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
766 fCurrFlatIndex[i] = index;
767 }
768 }
769
reed@google.comacd471f2011-05-03 21:26:46 +0000770 size_t size = (char*)ptr - (char*)storage;
771 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000772 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000773 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000774 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000775// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000776 }
777 }
reed@google.combb6992a2011-04-26 17:41:56 +0000778}
779
780///////////////////////////////////////////////////////////////////////////////
781
782#include "SkGPipe.h"
783
reed@google.comacd471f2011-05-03 21:26:46 +0000784SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000785 fCanvas = NULL;
786}
787
788SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000789 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000790 SkSafeUnref(fCanvas);
791}
792
reed@google.comdde09562011-05-23 12:21:05 +0000793SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
794 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000795 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000796 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000797 fFactorySet.reset();
798 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
799 (flags & kCrossProcess_Flag) ?
800 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000801 }
802 return fCanvas;
803}
804
805void SkGPipeWriter::endRecording() {
806 if (fCanvas) {
807 fCanvas->finish();
808 fCanvas->unref();
809 fCanvas = NULL;
810 }
811}
812