blob: 5f928d7de3f87d182de188a0ddfa6b09aeccc27c [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);
reed@google.comeb5a8152011-05-23 21:09:13 +000086 this->doNotify();
reed@google.combb6992a2011-04-26 17:41:56 +000087 fDone = true;
88 }
89 }
90
91 // overrides from SkCanvas
92 virtual int save(SaveFlags);
93 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
94 virtual void restore();
95 virtual bool translate(SkScalar dx, SkScalar dy);
96 virtual bool scale(SkScalar sx, SkScalar sy);
97 virtual bool rotate(SkScalar degrees);
98 virtual bool skew(SkScalar sx, SkScalar sy);
99 virtual bool concat(const SkMatrix& matrix);
100 virtual void setMatrix(const SkMatrix& matrix);
101 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
102 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
103 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
104 virtual void clear(SkColor);
105 virtual void drawPaint(const SkPaint& paint);
106 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
107 const SkPaint&);
108 virtual void drawRect(const SkRect& rect, const SkPaint&);
109 virtual void drawPath(const SkPath& path, const SkPaint&);
110 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
111 const SkPaint*);
112 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
113 const SkRect& dst, const SkPaint*);
114 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
115 const SkPaint*);
116 virtual void drawSprite(const SkBitmap&, int left, int top,
117 const SkPaint*);
118 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
119 SkScalar y, const SkPaint&);
120 virtual void drawPosText(const void* text, size_t byteLength,
121 const SkPoint pos[], const SkPaint&);
122 virtual void drawPosTextH(const void* text, size_t byteLength,
123 const SkScalar xpos[], SkScalar constY, const SkPaint&);
124 virtual void drawTextOnPath(const void* text, size_t byteLength,
125 const SkPath& path, const SkMatrix* matrix,
126 const SkPaint&);
127 virtual void drawPicture(SkPicture& picture);
128 virtual void drawShape(SkShape*);
129 virtual void drawVertices(VertexMode, int vertexCount,
130 const SkPoint vertices[], const SkPoint texs[],
131 const SkColor colors[], SkXfermode*,
132 const uint16_t indices[], int indexCount,
133 const SkPaint&);
134 virtual void drawData(const void*, size_t);
135
136private:
reed@google.comdde09562011-05-23 12:21:05 +0000137 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000138 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000139 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000140 size_t fBlockSize; // amount allocated for writer
141 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000142 bool fDone;
143
reed@google.comf5842f72011-05-04 18:30:04 +0000144 SkRefCntSet fTypefaceSet;
145
146 uint32_t getTypefaceID(SkTypeface*);
147
reed@google.comacd471f2011-05-03 21:26:46 +0000148 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000149 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
150 }
151
reed@google.comacd471f2011-05-03 21:26:46 +0000152 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000153 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
154 }
reed@google.comacd471f2011-05-03 21:26:46 +0000155
156 bool needOpBytes(size_t size = 0);
157
158 inline void doNotify() {
159 if (!fDone) {
160 size_t bytes = fWriter.size() - fBytesNotified;
161 fController->notifyWritten(bytes);
162 fBytesNotified += bytes;
163 }
164 }
reed@google.comb55d1182011-05-11 00:42:04 +0000165
166 struct FlatData {
167 uint32_t fIndex; // always > 0
168 uint32_t fSize;
169
170 void* data() { return (char*)this + sizeof(*this); }
171
172 static int Compare(const FlatData* a, const FlatData* b) {
173 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
174 }
175 };
176 SkTDArray<FlatData*> fFlatArray;
177 int fCurrFlatIndex[kCount_PaintFlats];
178 int flattenToIndex(SkFlattenable* obj, PaintFlats);
179
reed@google.com31891582011-05-12 03:03:56 +0000180 SkPaint fPaint;
181 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000182
reed@google.comacd471f2011-05-03 21:26:46 +0000183 class AutoPipeNotify {
184 public:
185 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
186 ~AutoPipeNotify() { fCanvas->doNotify(); }
187 private:
188 SkGPipeCanvas* fCanvas;
189 };
190 friend class AutoPipeNotify;
191
reed@google.combb6992a2011-04-26 17:41:56 +0000192 typedef SkCanvas INHERITED;
193};
194
reed@google.comb55d1182011-05-11 00:42:04 +0000195// return 0 for NULL (or unflattenable obj), or index-base-1
196int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
197 if (NULL == obj) {
198 return 0;
199 }
200
201 SkFlattenable::Factory fact = obj->getFactory();
202 if (NULL == fact) {
203 return 0;
204 }
205
reed@google.comdde09562011-05-23 12:21:05 +0000206 if (fFactorySet) {
207 uint32_t id = fFactorySet->find((void*)fact);
208 if (0 == id) {
209 const char* name = SkFlattenable::FactoryToName(fact);
210 if (NULL == name) {
211 return 0;
212 }
213 size_t len = strlen(name);
214 size_t size = SkWriter32::WriteStringSize(name, len);
215 if (!this->needOpBytes(size)) {
216 return 0;
217 }
218 unsigned id = fFactorySet->add(fact);
219 this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
220 fWriter.writeString(name, len);
221 }
222 }
223
reed@google.comb55d1182011-05-11 00:42:04 +0000224 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.comdde09562011-05-23 12:21:05 +0000225 tmpWriter.setFactoryRecorder(fFactorySet);
226
reed@google.comb55d1182011-05-11 00:42:04 +0000227 tmpWriter.writeFlattenable(obj);
228 size_t len = tmpWriter.size();
229 size_t allocSize = len + sizeof(FlatData);
230
231 SkAutoSMalloc<1024> storage(allocSize);
232 FlatData* flat = (FlatData*)storage.get();
233 flat->fSize = len;
234 tmpWriter.flatten(flat->data());
235
236 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
237 fFlatArray.count(), flat, sizeof(flat),
238 &FlatData::Compare);
239 if (index < 0) {
240 index = ~index;
241 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
242 memcpy(copy, flat, allocSize);
243 *fFlatArray.insert(index) = copy;
244 // call this after the insert, so that count() will have been grown
245 copy->fIndex = fFlatArray.count();
246// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
247
248 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000249 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000250 fWriter.write(copy->data(), len);
251 }
252 }
253 return fFlatArray[index]->fIndex;
254}
255
reed@google.combb6992a2011-04-26 17:41:56 +0000256///////////////////////////////////////////////////////////////////////////////
257
reed@google.comacd471f2011-05-03 21:26:46 +0000258#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000259
reed@google.comacd471f2011-05-03 21:26:46 +0000260SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000261 SkWriter32* writer, SkFactorySet* fset)
262 : fWriter(*writer), fFactorySet(fset) {
reed@google.comacd471f2011-05-03 21:26:46 +0000263 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000264 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000265 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000266 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000267
reed@google.combb6793b2011-05-05 15:18:15 +0000268 // we need a device to limit our clip
269 // should the caller give us the bounds?
yangsu@google.com06b4da162011-06-17 15:04:40 +0000270 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000271 SkBitmap bitmap;
272 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da162011-06-17 15:04:40 +0000273 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000274 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000275}
276
277SkGPipeCanvas::~SkGPipeCanvas() {
278 this->finish();
279
reed@google.comb55d1182011-05-11 00:42:04 +0000280 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000281}
282
reed@google.comacd471f2011-05-03 21:26:46 +0000283bool SkGPipeCanvas::needOpBytes(size_t needed) {
284 if (fDone) {
285 return false;
286 }
287
288 needed += 4; // size of DrawOp atom
289 if (fWriter.size() + needed > fBlockSize) {
290 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
291 if (NULL == block) {
292 fDone = true;
293 return false;
294 }
295 fWriter.reset(block, fBlockSize);
296 fBytesNotified = 0;
297 }
298 return true;
299}
300
reed@google.comf5842f72011-05-04 18:30:04 +0000301uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
302 uint32_t id = 0; // 0 means default/null typeface
303 if (face) {
304 id = fTypefaceSet.find(face);
305 if (0 == id) {
306 id = fTypefaceSet.add(face);
307 size_t size = writeTypeface(NULL, face);
308 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000309 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000310 writeTypeface(&fWriter, face);
311 }
312 }
313 }
314 return id;
315}
316
reed@google.combb6992a2011-04-26 17:41:56 +0000317///////////////////////////////////////////////////////////////////////////////
318
reed@google.comacd471f2011-05-03 21:26:46 +0000319#define NOTIFY_SETUP(canvas) \
320 AutoPipeNotify apn(canvas)
321
reed@google.combb6992a2011-04-26 17:41:56 +0000322int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000323 NOTIFY_SETUP(this);
324 if (this->needOpBytes()) {
325 this->writeOp(kSave_DrawOp, 0, flags);
326 }
reed@google.combb6992a2011-04-26 17:41:56 +0000327 return this->INHERITED::save(flags);
328}
329
330int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
331 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000332 NOTIFY_SETUP(this);
333 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000334 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000335
reed@google.combb6992a2011-04-26 17:41:56 +0000336 if (bounds) {
337 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000338 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000339 }
340 if (paint) {
341 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000342 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000343 }
344
reed@google.comacd471f2011-05-03 21:26:46 +0000345 if (this->needOpBytes(size)) {
346 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
347 if (bounds) {
348 fWriter.writeRect(*bounds);
349 }
reed@google.combb6992a2011-04-26 17:41:56 +0000350 }
351
352 // we just pass on the save, so we don't create a layer
353 return this->INHERITED::save(saveFlags);
354}
355
356void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000357 NOTIFY_SETUP(this);
358 if (this->needOpBytes()) {
359 this->writeOp(kRestore_DrawOp);
360 }
reed@google.combb6992a2011-04-26 17:41:56 +0000361 this->INHERITED::restore();
362}
363
364bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
365 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000366 NOTIFY_SETUP(this);
367 if (this->needOpBytes(2 * sizeof(SkScalar))) {
368 this->writeOp(kTranslate_DrawOp);
369 fWriter.writeScalar(dx);
370 fWriter.writeScalar(dy);
371 }
reed@google.combb6992a2011-04-26 17:41:56 +0000372 }
373 return this->INHERITED::translate(dx, dy);
374}
375
376bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
377 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000378 NOTIFY_SETUP(this);
379 if (this->needOpBytes(2 * sizeof(SkScalar))) {
380 this->writeOp(kScale_DrawOp);
381 fWriter.writeScalar(sx);
382 fWriter.writeScalar(sy);
383 }
reed@google.combb6992a2011-04-26 17:41:56 +0000384 }
385 return this->INHERITED::scale(sx, sy);
386}
387
388bool SkGPipeCanvas::rotate(SkScalar degrees) {
389 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000390 NOTIFY_SETUP(this);
391 if (this->needOpBytes(sizeof(SkScalar))) {
392 this->writeOp(kRotate_DrawOp);
393 fWriter.writeScalar(degrees);
394 }
reed@google.combb6992a2011-04-26 17:41:56 +0000395 }
396 return this->INHERITED::rotate(degrees);
397}
398
399bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
400 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000401 NOTIFY_SETUP(this);
402 if (this->needOpBytes(2 * sizeof(SkScalar))) {
403 this->writeOp(kSkew_DrawOp);
404 fWriter.writeScalar(sx);
405 fWriter.writeScalar(sy);
406 }
reed@google.combb6992a2011-04-26 17:41:56 +0000407 }
408 return this->INHERITED::skew(sx, sy);
409}
410
411bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
412 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000413 NOTIFY_SETUP(this);
414 if (this->needOpBytes(matrix.flatten(NULL))) {
415 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000416 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000417 }
reed@google.combb6992a2011-04-26 17:41:56 +0000418 }
419 return this->INHERITED::concat(matrix);
420}
421
422void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000423 NOTIFY_SETUP(this);
424 if (this->needOpBytes(matrix.flatten(NULL))) {
425 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000426 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000427 }
reed@google.combb6992a2011-04-26 17:41:56 +0000428 this->INHERITED::setMatrix(matrix);
429}
430
431bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000432 NOTIFY_SETUP(this);
433 if (this->needOpBytes(sizeof(SkRect))) {
434 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
435 fWriter.writeRect(rect);
436 }
reed@google.combb6992a2011-04-26 17:41:56 +0000437 return this->INHERITED::clipRect(rect, rgnOp);
438}
439
440bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000441 NOTIFY_SETUP(this);
442 if (this->needOpBytes(estimateFlattenSize(path))) {
443 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
444 path.flatten(fWriter);
445 }
reed@google.combb6992a2011-04-26 17:41:56 +0000446 // we just pass on the bounds of the path
447 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
448}
449
450bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000451 NOTIFY_SETUP(this);
452 if (this->needOpBytes(region.flatten(NULL))) {
453 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000454 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000455 }
reed@google.combb6992a2011-04-26 17:41:56 +0000456 return this->INHERITED::clipRegion(region, rgnOp);
457}
458
459///////////////////////////////////////////////////////////////////////////////
460
461void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000462 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000463 unsigned flags = 0;
464 if (color) {
465 flags |= kClear_HasColor_DrawOpFlag;
466 }
reed@google.comacd471f2011-05-03 21:26:46 +0000467 if (this->needOpBytes(sizeof(SkColor))) {
468 this->writeOp(kDrawClear_DrawOp, flags, 0);
469 if (color) {
470 fWriter.write32(color);
471 }
reed@google.combb6992a2011-04-26 17:41:56 +0000472 }
473}
474
475void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000476 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000477 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000478 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000479 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000480 }
reed@google.combb6992a2011-04-26 17:41:56 +0000481}
482
483void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
484 const SkPoint pts[], const SkPaint& paint) {
485 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000486 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000487 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000488 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000489 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000490 fWriter.write32(count);
491 fWriter.write(pts, count * sizeof(SkPoint));
492 }
reed@google.combb6992a2011-04-26 17:41:56 +0000493 }
494}
495
496void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000497 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000498 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000499 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000500 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000501 fWriter.writeRect(rect);
502 }
reed@google.combb6992a2011-04-26 17:41:56 +0000503}
504
505void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000506 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000507 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000508 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000509 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000510 path.flatten(fWriter);
511 }
reed@google.combb6992a2011-04-26 17:41:56 +0000512}
513
514void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
515 const SkPaint*) {
516 UNIMPLEMENTED
517}
518
519void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
520 const SkRect& dst, const SkPaint*) {
521 UNIMPLEMENTED
522}
523
524void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
525 const SkPaint*) {
526 UNIMPLEMENTED
527}
528
529void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
530 const SkPaint*) {
531 UNIMPLEMENTED
532}
533
534void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
535 SkScalar y, const SkPaint& paint) {
536 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000537 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000538 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000539 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000540 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000541 fWriter.write32(byteLength);
542 fWriter.writePad(text, byteLength);
543 fWriter.writeScalar(x);
544 fWriter.writeScalar(y);
545 }
reed@google.combb6992a2011-04-26 17:41:56 +0000546 }
547}
548
549void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
550 const SkPoint pos[], const SkPaint& paint) {
551 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000552 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000553 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000554 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000555 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000556 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000557 fWriter.write32(byteLength);
558 fWriter.writePad(text, byteLength);
559 fWriter.write32(count);
560 fWriter.write(pos, count * sizeof(SkPoint));
561 }
reed@google.combb6992a2011-04-26 17:41:56 +0000562 }
563}
564
565void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
566 const SkScalar xpos[], SkScalar constY,
567 const SkPaint& paint) {
568 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000569 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000570 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000571 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000572 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000573 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000574 fWriter.write32(byteLength);
575 fWriter.writePad(text, byteLength);
576 fWriter.write32(count);
577 fWriter.write(xpos, count * sizeof(SkScalar));
578 fWriter.writeScalar(constY);
579 }
reed@google.combb6992a2011-04-26 17:41:56 +0000580 }
581}
582
583void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
584 const SkPath& path, const SkMatrix* matrix,
585 const SkPaint& paint) {
586 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000587 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000588 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000589 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000590 if (matrix) {
591 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000592 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000593 }
reed@google.com31891582011-05-12 03:03:56 +0000594 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000595 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000596 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000597
reed@google.comacd471f2011-05-03 21:26:46 +0000598 fWriter.write32(byteLength);
599 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000600
reed@google.comacd471f2011-05-03 21:26:46 +0000601 path.flatten(fWriter);
602 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000603 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000604 }
reed@google.combb6992a2011-04-26 17:41:56 +0000605 }
606 }
607}
608
609void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000610 // we want to playback the picture into individual draw calls
611 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000612}
613
614void SkGPipeCanvas::drawShape(SkShape* shape) {
615 UNIMPLEMENTED
616}
617
618void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
619 const SkPoint vertices[], const SkPoint texs[],
620 const SkColor colors[], SkXfermode*,
621 const uint16_t indices[], int indexCount,
622 const SkPaint& paint) {
623 if (0 == vertexCount) {
624 return;
625 }
626
reed@google.comacd471f2011-05-03 21:26:46 +0000627 NOTIFY_SETUP(this);
628 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000629 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000630 unsigned flags = 0;
631 if (texs) {
632 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000633 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000634 }
635 if (colors) {
636 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000637 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000638 }
639 if (indices && indexCount > 0) {
640 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000641 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000642 }
643
reed@google.comacd471f2011-05-03 21:26:46 +0000644 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000645 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000646 fWriter.write32(mode);
647 fWriter.write32(vertexCount);
648 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
649 if (texs) {
650 fWriter.write(texs, vertexCount * sizeof(SkPoint));
651 }
652 if (colors) {
653 fWriter.write(colors, vertexCount * sizeof(SkColor));
654 }
reed@google.combb6992a2011-04-26 17:41:56 +0000655
reed@google.comacd471f2011-05-03 21:26:46 +0000656 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000657
reed@google.comacd471f2011-05-03 21:26:46 +0000658 if (indices && indexCount > 0) {
659 fWriter.write32(indexCount);
660 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
661 }
reed@google.combb6992a2011-04-26 17:41:56 +0000662 }
663}
664
reed@google.comacd471f2011-05-03 21:26:46 +0000665void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
666 if (size && ptr) {
667 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000668 unsigned data = 0;
669 if (size < (1 << DRAWOPS_DATA_BITS)) {
670 data = (unsigned)size;
671 }
reed@google.comacd471f2011-05-03 21:26:46 +0000672 if (this->needOpBytes(4 + SkAlign4(size))) {
673 this->writeOp(kDrawData_DrawOp, 0, data);
674 if (0 == data) {
675 fWriter.write32(size);
676 }
reed@google.combb6793b2011-05-05 15:18:15 +0000677 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000678 }
679 }
680}
681
682///////////////////////////////////////////////////////////////////////////////
683
684template <typename T> uint32_t castToU32(T value) {
685 union {
686 T fSrc;
687 uint32_t fDst;
688 } data;
689 data.fSrc = value;
690 return data.fDst;
691}
692
reed@google.com31891582011-05-12 03:03:56 +0000693void SkGPipeCanvas::writePaint(const SkPaint& paint) {
694 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000695 uint32_t storage[32];
696 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000697
698 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000699 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000700 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000701 }
702 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000703 *ptr++ = PaintOp_packOp(kColor_PaintOp);
704 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000705 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000706 }
707 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000708 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000709 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000710 }
711 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000712 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000713 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000714 }
715 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000716 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000717 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000718 }
719 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000720 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
721 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000722 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000723 }
724 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000725 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
726 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000727 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000728 }
729 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000730 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000731 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000732 }
733 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000734 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000735 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000736 }
737 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000738 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000739 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000740 }
741 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000742 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
743 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000744 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000745 }
746 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000747 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
748 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000749 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000750 }
751 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000752 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
753 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000754 base.setTextSkewX(paint.getTextSkewX());
755 }
756
757 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
758 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000759 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
760 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000761 }
reed@google.combb6992a2011-04-26 17:41:56 +0000762
reed@google.comb55d1182011-05-11 00:42:04 +0000763 for (int i = 0; i < kCount_PaintFlats; i++) {
764 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
765 SkASSERT(index >= 0 && index <= fFlatArray.count());
766 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000767 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
768 fCurrFlatIndex[i] = index;
769 }
770 }
771
reed@google.comacd471f2011-05-03 21:26:46 +0000772 size_t size = (char*)ptr - (char*)storage;
773 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000774 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000775 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000776 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000777// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000778 }
779 }
reed@google.combb6992a2011-04-26 17:41:56 +0000780}
781
782///////////////////////////////////////////////////////////////////////////////
783
784#include "SkGPipe.h"
785
reed@google.comacd471f2011-05-03 21:26:46 +0000786SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000787 fCanvas = NULL;
788}
789
790SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000791 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000792 SkSafeUnref(fCanvas);
793}
794
reed@google.comdde09562011-05-23 12:21:05 +0000795SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
796 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000797 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000798 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000799 fFactorySet.reset();
800 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
801 (flags & kCrossProcess_Flag) ?
802 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000803 }
804 return fCanvas;
805}
806
807void SkGPipeWriter::endRecording() {
808 if (fCanvas) {
809 fCanvas->finish();
810 fCanvas->unref();
811 fCanvas = NULL;
812 }
813}
814