blob: aa6ed821b6f212b0c5e9ca05776af8b16b0e0ab6 [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.comacd471f2011-05-03 21:26:46 +000080 SkGPipeCanvas(SkGPipeController*, SkWriter32*);
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.comacd471f2011-05-03 21:26:46 +0000136 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000137 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000138 size_t fBlockSize; // amount allocated for writer
139 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000140 bool fDone;
141
reed@google.comf5842f72011-05-04 18:30:04 +0000142 SkRefCntSet fTypefaceSet;
143
144 uint32_t getTypefaceID(SkTypeface*);
145
reed@google.comacd471f2011-05-03 21:26:46 +0000146 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000147 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
148 }
149
reed@google.comacd471f2011-05-03 21:26:46 +0000150 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000151 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
152 }
reed@google.comacd471f2011-05-03 21:26:46 +0000153
154 bool needOpBytes(size_t size = 0);
155
156 inline void doNotify() {
157 if (!fDone) {
158 size_t bytes = fWriter.size() - fBytesNotified;
159 fController->notifyWritten(bytes);
160 fBytesNotified += bytes;
161 }
162 }
reed@google.comb55d1182011-05-11 00:42:04 +0000163
164 struct FlatData {
165 uint32_t fIndex; // always > 0
166 uint32_t fSize;
167
168 void* data() { return (char*)this + sizeof(*this); }
169
170 static int Compare(const FlatData* a, const FlatData* b) {
171 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
172 }
173 };
174 SkTDArray<FlatData*> fFlatArray;
175 int fCurrFlatIndex[kCount_PaintFlats];
176 int flattenToIndex(SkFlattenable* obj, PaintFlats);
177
reed@google.com31891582011-05-12 03:03:56 +0000178 SkPaint fPaint;
179 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000180
reed@google.comacd471f2011-05-03 21:26:46 +0000181 class AutoPipeNotify {
182 public:
183 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
184 ~AutoPipeNotify() { fCanvas->doNotify(); }
185 private:
186 SkGPipeCanvas* fCanvas;
187 };
188 friend class AutoPipeNotify;
189
reed@google.combb6992a2011-04-26 17:41:56 +0000190 typedef SkCanvas INHERITED;
191};
192
reed@google.comb55d1182011-05-11 00:42:04 +0000193// return 0 for NULL (or unflattenable obj), or index-base-1
194int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
195 if (NULL == obj) {
196 return 0;
197 }
198
199 SkFlattenable::Factory fact = obj->getFactory();
200 if (NULL == fact) {
201 return 0;
202 }
203
204 SkFlattenableWriteBuffer tmpWriter(1024);
205 tmpWriter.writeFlattenable(obj);
206 size_t len = tmpWriter.size();
207 size_t allocSize = len + sizeof(FlatData);
208
209 SkAutoSMalloc<1024> storage(allocSize);
210 FlatData* flat = (FlatData*)storage.get();
211 flat->fSize = len;
212 tmpWriter.flatten(flat->data());
213
214 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
215 fFlatArray.count(), flat, sizeof(flat),
216 &FlatData::Compare);
217 if (index < 0) {
218 index = ~index;
219 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
220 memcpy(copy, flat, allocSize);
221 *fFlatArray.insert(index) = copy;
222 // call this after the insert, so that count() will have been grown
223 copy->fIndex = fFlatArray.count();
224// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
225
226 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000227 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000228 fWriter.write(copy->data(), len);
229 }
230 }
231 return fFlatArray[index]->fIndex;
232}
233
reed@google.combb6992a2011-04-26 17:41:56 +0000234///////////////////////////////////////////////////////////////////////////////
235
reed@google.comacd471f2011-05-03 21:26:46 +0000236#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000237
reed@google.comacd471f2011-05-03 21:26:46 +0000238SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
239 SkWriter32* writer) : fWriter(*writer) {
240 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000241 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000242 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000243 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000244
reed@google.combb6793b2011-05-05 15:18:15 +0000245 // we need a device to limit our clip
246 // should the caller give us the bounds?
247 SkBitmap bitmap;
248 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
249 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
250 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000251}
252
253SkGPipeCanvas::~SkGPipeCanvas() {
254 this->finish();
255
reed@google.comb55d1182011-05-11 00:42:04 +0000256 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000257}
258
reed@google.comacd471f2011-05-03 21:26:46 +0000259bool SkGPipeCanvas::needOpBytes(size_t needed) {
260 if (fDone) {
261 return false;
262 }
263
264 needed += 4; // size of DrawOp atom
265 if (fWriter.size() + needed > fBlockSize) {
266 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
267 if (NULL == block) {
268 fDone = true;
269 return false;
270 }
271 fWriter.reset(block, fBlockSize);
272 fBytesNotified = 0;
273 }
274 return true;
275}
276
reed@google.comf5842f72011-05-04 18:30:04 +0000277uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
278 uint32_t id = 0; // 0 means default/null typeface
279 if (face) {
280 id = fTypefaceSet.find(face);
281 if (0 == id) {
282 id = fTypefaceSet.add(face);
283 size_t size = writeTypeface(NULL, face);
284 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000285 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000286 writeTypeface(&fWriter, face);
287 }
288 }
289 }
290 return id;
291}
292
reed@google.combb6992a2011-04-26 17:41:56 +0000293///////////////////////////////////////////////////////////////////////////////
294
reed@google.comacd471f2011-05-03 21:26:46 +0000295#define NOTIFY_SETUP(canvas) \
296 AutoPipeNotify apn(canvas)
297
reed@google.combb6992a2011-04-26 17:41:56 +0000298int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000299 NOTIFY_SETUP(this);
300 if (this->needOpBytes()) {
301 this->writeOp(kSave_DrawOp, 0, flags);
302 }
reed@google.combb6992a2011-04-26 17:41:56 +0000303 return this->INHERITED::save(flags);
304}
305
306int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
307 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000308 NOTIFY_SETUP(this);
309 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000310 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000311
reed@google.combb6992a2011-04-26 17:41:56 +0000312 if (bounds) {
313 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000314 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000315 }
316 if (paint) {
317 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000318 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000319 }
320
reed@google.comacd471f2011-05-03 21:26:46 +0000321 if (this->needOpBytes(size)) {
322 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
323 if (bounds) {
324 fWriter.writeRect(*bounds);
325 }
reed@google.combb6992a2011-04-26 17:41:56 +0000326 }
327
328 // we just pass on the save, so we don't create a layer
329 return this->INHERITED::save(saveFlags);
330}
331
332void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000333 NOTIFY_SETUP(this);
334 if (this->needOpBytes()) {
335 this->writeOp(kRestore_DrawOp);
336 }
reed@google.combb6992a2011-04-26 17:41:56 +0000337 this->INHERITED::restore();
338}
339
340bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
341 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000342 NOTIFY_SETUP(this);
343 if (this->needOpBytes(2 * sizeof(SkScalar))) {
344 this->writeOp(kTranslate_DrawOp);
345 fWriter.writeScalar(dx);
346 fWriter.writeScalar(dy);
347 }
reed@google.combb6992a2011-04-26 17:41:56 +0000348 }
349 return this->INHERITED::translate(dx, dy);
350}
351
352bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
353 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000354 NOTIFY_SETUP(this);
355 if (this->needOpBytes(2 * sizeof(SkScalar))) {
356 this->writeOp(kScale_DrawOp);
357 fWriter.writeScalar(sx);
358 fWriter.writeScalar(sy);
359 }
reed@google.combb6992a2011-04-26 17:41:56 +0000360 }
361 return this->INHERITED::scale(sx, sy);
362}
363
364bool SkGPipeCanvas::rotate(SkScalar degrees) {
365 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000366 NOTIFY_SETUP(this);
367 if (this->needOpBytes(sizeof(SkScalar))) {
368 this->writeOp(kRotate_DrawOp);
369 fWriter.writeScalar(degrees);
370 }
reed@google.combb6992a2011-04-26 17:41:56 +0000371 }
372 return this->INHERITED::rotate(degrees);
373}
374
375bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
376 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000377 NOTIFY_SETUP(this);
378 if (this->needOpBytes(2 * sizeof(SkScalar))) {
379 this->writeOp(kSkew_DrawOp);
380 fWriter.writeScalar(sx);
381 fWriter.writeScalar(sy);
382 }
reed@google.combb6992a2011-04-26 17:41:56 +0000383 }
384 return this->INHERITED::skew(sx, sy);
385}
386
387bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
388 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000389 NOTIFY_SETUP(this);
390 if (this->needOpBytes(matrix.flatten(NULL))) {
391 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000392 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000393 }
reed@google.combb6992a2011-04-26 17:41:56 +0000394 }
395 return this->INHERITED::concat(matrix);
396}
397
398void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000399 NOTIFY_SETUP(this);
400 if (this->needOpBytes(matrix.flatten(NULL))) {
401 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000402 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000403 }
reed@google.combb6992a2011-04-26 17:41:56 +0000404 this->INHERITED::setMatrix(matrix);
405}
406
407bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000408 NOTIFY_SETUP(this);
409 if (this->needOpBytes(sizeof(SkRect))) {
410 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
411 fWriter.writeRect(rect);
412 }
reed@google.combb6992a2011-04-26 17:41:56 +0000413 return this->INHERITED::clipRect(rect, rgnOp);
414}
415
416bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000417 NOTIFY_SETUP(this);
418 if (this->needOpBytes(estimateFlattenSize(path))) {
419 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
420 path.flatten(fWriter);
421 }
reed@google.combb6992a2011-04-26 17:41:56 +0000422 // we just pass on the bounds of the path
423 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
424}
425
426bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000427 NOTIFY_SETUP(this);
428 if (this->needOpBytes(region.flatten(NULL))) {
429 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000430 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000431 }
reed@google.combb6992a2011-04-26 17:41:56 +0000432 return this->INHERITED::clipRegion(region, rgnOp);
433}
434
435///////////////////////////////////////////////////////////////////////////////
436
437void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000438 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000439 unsigned flags = 0;
440 if (color) {
441 flags |= kClear_HasColor_DrawOpFlag;
442 }
reed@google.comacd471f2011-05-03 21:26:46 +0000443 if (this->needOpBytes(sizeof(SkColor))) {
444 this->writeOp(kDrawClear_DrawOp, flags, 0);
445 if (color) {
446 fWriter.write32(color);
447 }
reed@google.combb6992a2011-04-26 17:41:56 +0000448 }
449}
450
451void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000452 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000453 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000454 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000455 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000456 }
reed@google.combb6992a2011-04-26 17:41:56 +0000457}
458
459void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
460 const SkPoint pts[], const SkPaint& paint) {
461 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000462 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000463 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000464 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000465 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000466 fWriter.write32(count);
467 fWriter.write(pts, count * sizeof(SkPoint));
468 }
reed@google.combb6992a2011-04-26 17:41:56 +0000469 }
470}
471
472void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000473 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000474 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000475 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000476 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000477 fWriter.writeRect(rect);
478 }
reed@google.combb6992a2011-04-26 17:41:56 +0000479}
480
481void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000482 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000483 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000484 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000485 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000486 path.flatten(fWriter);
487 }
reed@google.combb6992a2011-04-26 17:41:56 +0000488}
489
490void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
491 const SkPaint*) {
492 UNIMPLEMENTED
493}
494
495void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
496 const SkRect& dst, const SkPaint*) {
497 UNIMPLEMENTED
498}
499
500void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
501 const SkPaint*) {
502 UNIMPLEMENTED
503}
504
505void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
506 const SkPaint*) {
507 UNIMPLEMENTED
508}
509
510void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
511 SkScalar y, const SkPaint& paint) {
512 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000513 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000514 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000515 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000516 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000517 fWriter.write32(byteLength);
518 fWriter.writePad(text, byteLength);
519 fWriter.writeScalar(x);
520 fWriter.writeScalar(y);
521 }
reed@google.combb6992a2011-04-26 17:41:56 +0000522 }
523}
524
525void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
526 const SkPoint pos[], const SkPaint& paint) {
527 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000528 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000529 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000530 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000531 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000532 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000533 fWriter.write32(byteLength);
534 fWriter.writePad(text, byteLength);
535 fWriter.write32(count);
536 fWriter.write(pos, count * sizeof(SkPoint));
537 }
reed@google.combb6992a2011-04-26 17:41:56 +0000538 }
539}
540
541void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
542 const SkScalar xpos[], SkScalar constY,
543 const SkPaint& paint) {
544 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000545 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000546 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000547 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000548 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000549 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000550 fWriter.write32(byteLength);
551 fWriter.writePad(text, byteLength);
552 fWriter.write32(count);
553 fWriter.write(xpos, count * sizeof(SkScalar));
554 fWriter.writeScalar(constY);
555 }
reed@google.combb6992a2011-04-26 17:41:56 +0000556 }
557}
558
559void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
560 const SkPath& path, const SkMatrix* matrix,
561 const SkPaint& paint) {
562 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000563 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000564 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000565 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000566 if (matrix) {
567 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000568 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000569 }
reed@google.com31891582011-05-12 03:03:56 +0000570 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000571 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000572 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000573
reed@google.comacd471f2011-05-03 21:26:46 +0000574 fWriter.write32(byteLength);
575 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000576
reed@google.comacd471f2011-05-03 21:26:46 +0000577 path.flatten(fWriter);
578 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000579 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000580 }
reed@google.combb6992a2011-04-26 17:41:56 +0000581 }
582 }
583}
584
585void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000586 // we want to playback the picture into individual draw calls
587 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000588}
589
590void SkGPipeCanvas::drawShape(SkShape* shape) {
591 UNIMPLEMENTED
592}
593
594void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
595 const SkPoint vertices[], const SkPoint texs[],
596 const SkColor colors[], SkXfermode*,
597 const uint16_t indices[], int indexCount,
598 const SkPaint& paint) {
599 if (0 == vertexCount) {
600 return;
601 }
602
reed@google.comacd471f2011-05-03 21:26:46 +0000603 NOTIFY_SETUP(this);
604 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000605 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000606 unsigned flags = 0;
607 if (texs) {
608 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000609 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000610 }
611 if (colors) {
612 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000613 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000614 }
615 if (indices && indexCount > 0) {
616 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000617 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000618 }
619
reed@google.comacd471f2011-05-03 21:26:46 +0000620 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000621 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000622 fWriter.write32(mode);
623 fWriter.write32(vertexCount);
624 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
625 if (texs) {
626 fWriter.write(texs, vertexCount * sizeof(SkPoint));
627 }
628 if (colors) {
629 fWriter.write(colors, vertexCount * sizeof(SkColor));
630 }
reed@google.combb6992a2011-04-26 17:41:56 +0000631
reed@google.comacd471f2011-05-03 21:26:46 +0000632 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000633
reed@google.comacd471f2011-05-03 21:26:46 +0000634 if (indices && indexCount > 0) {
635 fWriter.write32(indexCount);
636 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
637 }
reed@google.combb6992a2011-04-26 17:41:56 +0000638 }
639}
640
reed@google.comacd471f2011-05-03 21:26:46 +0000641void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
642 if (size && ptr) {
643 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000644 unsigned data = 0;
645 if (size < (1 << DRAWOPS_DATA_BITS)) {
646 data = (unsigned)size;
647 }
reed@google.comacd471f2011-05-03 21:26:46 +0000648 if (this->needOpBytes(4 + SkAlign4(size))) {
649 this->writeOp(kDrawData_DrawOp, 0, data);
650 if (0 == data) {
651 fWriter.write32(size);
652 }
reed@google.combb6793b2011-05-05 15:18:15 +0000653 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000654 }
655 }
656}
657
658///////////////////////////////////////////////////////////////////////////////
659
660template <typename T> uint32_t castToU32(T value) {
661 union {
662 T fSrc;
663 uint32_t fDst;
664 } data;
665 data.fSrc = value;
666 return data.fDst;
667}
668
reed@google.com31891582011-05-12 03:03:56 +0000669void SkGPipeCanvas::writePaint(const SkPaint& paint) {
670 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000671 uint32_t storage[32];
672 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000673
674 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000675 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000676 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000677 }
678 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000679 *ptr++ = PaintOp_packOp(kColor_PaintOp);
680 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000681 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000682 }
683 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000684 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000685 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000686 }
687 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000688 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000689 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000690 }
691 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000692 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000693 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000694 }
695 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000696 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
697 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000698 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000699 }
700 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000701 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
702 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000703 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000704 }
705 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000706 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000707 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000708 }
709 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000710 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000711 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000712 }
713 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000714 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000715 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000716 }
717 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000718 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
719 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000720 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000721 }
722 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000723 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
724 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000725 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000726 }
727 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000728 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
729 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000730 base.setTextSkewX(paint.getTextSkewX());
731 }
732
733 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
734 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000735 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
736 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000737 }
reed@google.combb6992a2011-04-26 17:41:56 +0000738
reed@google.comb55d1182011-05-11 00:42:04 +0000739 for (int i = 0; i < kCount_PaintFlats; i++) {
740 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
741 SkASSERT(index >= 0 && index <= fFlatArray.count());
742 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000743 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
744 fCurrFlatIndex[i] = index;
745 }
746 }
747
reed@google.comacd471f2011-05-03 21:26:46 +0000748 size_t size = (char*)ptr - (char*)storage;
749 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000750 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000751 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000752 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000753// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000754 }
755 }
reed@google.combb6992a2011-04-26 17:41:56 +0000756}
757
758///////////////////////////////////////////////////////////////////////////////
759
760#include "SkGPipe.h"
761
reed@google.comacd471f2011-05-03 21:26:46 +0000762SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000763 fCanvas = NULL;
764}
765
766SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000767 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000768 SkSafeUnref(fCanvas);
769}
770
reed@google.comacd471f2011-05-03 21:26:46 +0000771SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller) {
reed@google.combb6992a2011-04-26 17:41:56 +0000772 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000773 fWriter.reset(NULL, 0);
774 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter));
reed@google.combb6992a2011-04-26 17:41:56 +0000775 }
776 return fCanvas;
777}
778
779void SkGPipeWriter::endRecording() {
780 if (fCanvas) {
781 fCanvas->finish();
782 fCanvas->unref();
783 fCanvas = NULL;
784 }
785}
786