blob: 04625b7e5de376b3732f6712646488d52d3efd76 [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"
28#include "SkMaskFilter.h"
29#include "SkRasterizer.h"
30#include "SkShader.h"
31
32static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
33 SkASSERT(paintFlat < kCount_PaintFlats);
34 switch (paintFlat) {
35 case kColorFilter_PaintFlat: return paint.getColorFilter();
36 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
37 case kPathEffect_PaintFlat: return paint.getPathEffect();
38 case kRasterizer_PaintFlat: return paint.getRasterizer();
39 case kShader_PaintFlat: return paint.getShader();
40 case kXfermode_PaintFlat: return paint.getXfermode();
41 }
42 SkASSERT(!"never gets here");
43 return NULL;
44}
reed@google.combb6992a2011-04-26 17:41:56 +000045
reed@google.comacd471f2011-05-03 21:26:46 +000046static size_t estimateFlattenSize(const SkPath& path) {
47 int n = path.countPoints();
48 size_t bytes = 3 * sizeof(int32_t);
49 bytes += n * sizeof(SkPoint);
50 bytes += SkAlign4(n + 2); // verbs: add 2 for move/close extras
51
52#ifdef SK_DEBUG
53 {
54 SkWriter32 writer(1024);
55 path.flatten(writer);
56 SkASSERT(writer.size() <= bytes);
57 }
58#endif
59 return bytes;
60}
61
reed@google.comf5842f72011-05-04 18:30:04 +000062static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
63 SkASSERT(typeface);
64 SkDynamicMemoryWStream stream;
65 typeface->serialize(&stream);
66 size_t size = stream.getOffset();
67 if (writer) {
68 writer->write32(size);
69 writer->write(stream.getStream(), size);
70 }
71 return 4 + size;
72}
73
reed@google.combb6992a2011-04-26 17:41:56 +000074///////////////////////////////////////////////////////////////////////////////
75
76class SkGPipeCanvas : public SkCanvas {
77public:
reed@google.comacd471f2011-05-03 21:26:46 +000078 SkGPipeCanvas(SkGPipeController*, SkWriter32*);
reed@google.combb6992a2011-04-26 17:41:56 +000079 virtual ~SkGPipeCanvas();
80
81 void finish() {
82 if (!fDone) {
83 this->writeOp(kDone_DrawOp);
84 fDone = true;
85 }
86 }
87
88 // overrides from SkCanvas
89 virtual int save(SaveFlags);
90 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
91 virtual void restore();
92 virtual bool translate(SkScalar dx, SkScalar dy);
93 virtual bool scale(SkScalar sx, SkScalar sy);
94 virtual bool rotate(SkScalar degrees);
95 virtual bool skew(SkScalar sx, SkScalar sy);
96 virtual bool concat(const SkMatrix& matrix);
97 virtual void setMatrix(const SkMatrix& matrix);
98 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
99 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
100 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
101 virtual void clear(SkColor);
102 virtual void drawPaint(const SkPaint& paint);
103 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
104 const SkPaint&);
105 virtual void drawRect(const SkRect& rect, const SkPaint&);
106 virtual void drawPath(const SkPath& path, const SkPaint&);
107 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
108 const SkPaint*);
109 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
110 const SkRect& dst, const SkPaint*);
111 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
112 const SkPaint*);
113 virtual void drawSprite(const SkBitmap&, int left, int top,
114 const SkPaint*);
115 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
116 SkScalar y, const SkPaint&);
117 virtual void drawPosText(const void* text, size_t byteLength,
118 const SkPoint pos[], const SkPaint&);
119 virtual void drawPosTextH(const void* text, size_t byteLength,
120 const SkScalar xpos[], SkScalar constY, const SkPaint&);
121 virtual void drawTextOnPath(const void* text, size_t byteLength,
122 const SkPath& path, const SkMatrix* matrix,
123 const SkPaint&);
124 virtual void drawPicture(SkPicture& picture);
125 virtual void drawShape(SkShape*);
126 virtual void drawVertices(VertexMode, int vertexCount,
127 const SkPoint vertices[], const SkPoint texs[],
128 const SkColor colors[], SkXfermode*,
129 const uint16_t indices[], int indexCount,
130 const SkPaint&);
131 virtual void drawData(const void*, size_t);
132
133private:
reed@google.comacd471f2011-05-03 21:26:46 +0000134 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000135 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000136 size_t fBlockSize; // amount allocated for writer
137 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000138 bool fDone;
139
reed@google.comf5842f72011-05-04 18:30:04 +0000140 SkRefCntSet fTypefaceSet;
141
142 uint32_t getTypefaceID(SkTypeface*);
143
reed@google.comacd471f2011-05-03 21:26:46 +0000144 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000145 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
146 }
147
reed@google.comacd471f2011-05-03 21:26:46 +0000148 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000149 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
150 }
reed@google.comacd471f2011-05-03 21:26:46 +0000151
152 bool needOpBytes(size_t size = 0);
153
154 inline void doNotify() {
155 if (!fDone) {
156 size_t bytes = fWriter.size() - fBytesNotified;
157 fController->notifyWritten(bytes);
158 fBytesNotified += bytes;
159 }
160 }
reed@google.comb55d1182011-05-11 00:42:04 +0000161
162 struct FlatData {
163 uint32_t fIndex; // always > 0
164 uint32_t fSize;
165
166 void* data() { return (char*)this + sizeof(*this); }
167
168 static int Compare(const FlatData* a, const FlatData* b) {
169 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
170 }
171 };
172 SkTDArray<FlatData*> fFlatArray;
173 int fCurrFlatIndex[kCount_PaintFlats];
174 int flattenToIndex(SkFlattenable* obj, PaintFlats);
175
reed@google.combb6992a2011-04-26 17:41:56 +0000176 SkTDArray<SkPaint*> fPaints;
177 unsigned writePaint(const SkPaint&);
178
reed@google.comacd471f2011-05-03 21:26:46 +0000179 class AutoPipeNotify {
180 public:
181 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
182 ~AutoPipeNotify() { fCanvas->doNotify(); }
183 private:
184 SkGPipeCanvas* fCanvas;
185 };
186 friend class AutoPipeNotify;
187
reed@google.combb6992a2011-04-26 17:41:56 +0000188 typedef SkCanvas INHERITED;
189};
190
reed@google.comb55d1182011-05-11 00:42:04 +0000191// return 0 for NULL (or unflattenable obj), or index-base-1
192int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
193 if (NULL == obj) {
194 return 0;
195 }
196
197 SkFlattenable::Factory fact = obj->getFactory();
198 if (NULL == fact) {
199 return 0;
200 }
201
202 SkFlattenableWriteBuffer tmpWriter(1024);
203 tmpWriter.writeFlattenable(obj);
204 size_t len = tmpWriter.size();
205 size_t allocSize = len + sizeof(FlatData);
206
207 SkAutoSMalloc<1024> storage(allocSize);
208 FlatData* flat = (FlatData*)storage.get();
209 flat->fSize = len;
210 tmpWriter.flatten(flat->data());
211
212 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
213 fFlatArray.count(), flat, sizeof(flat),
214 &FlatData::Compare);
215 if (index < 0) {
216 index = ~index;
217 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
218 memcpy(copy, flat, allocSize);
219 *fFlatArray.insert(index) = copy;
220 // call this after the insert, so that count() will have been grown
221 copy->fIndex = fFlatArray.count();
222// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
223
224 if (this->needOpBytes(len)) {
225 this->writeOp(kDef_PaintFlat_DrawOp, paintflat, copy->fIndex);
226 fWriter.write(copy->data(), len);
227 }
228 }
229 return fFlatArray[index]->fIndex;
230}
231
reed@google.combb6992a2011-04-26 17:41:56 +0000232///////////////////////////////////////////////////////////////////////////////
233
reed@google.comacd471f2011-05-03 21:26:46 +0000234#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000235
reed@google.comacd471f2011-05-03 21:26:46 +0000236SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
237 SkWriter32* writer) : fWriter(*writer) {
238 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000239 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000240 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000241 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000242
reed@google.combb6992a2011-04-26 17:41:56 +0000243 // always begin with 1 default paint
244 *fPaints.append() = SkNEW(SkPaint);
reed@google.combb6793b2011-05-05 15:18:15 +0000245
246 // we need a device to limit our clip
247 // should the caller give us the bounds?
248 SkBitmap bitmap;
249 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
250 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
251 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000252}
253
254SkGPipeCanvas::~SkGPipeCanvas() {
255 this->finish();
256
257 fPaints.deleteAll();
reed@google.comb55d1182011-05-11 00:42:04 +0000258 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000259}
260
reed@google.comacd471f2011-05-03 21:26:46 +0000261bool SkGPipeCanvas::needOpBytes(size_t needed) {
262 if (fDone) {
263 return false;
264 }
265
266 needed += 4; // size of DrawOp atom
267 if (fWriter.size() + needed > fBlockSize) {
268 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
269 if (NULL == block) {
270 fDone = true;
271 return false;
272 }
273 fWriter.reset(block, fBlockSize);
274 fBytesNotified = 0;
275 }
276 return true;
277}
278
reed@google.comf5842f72011-05-04 18:30:04 +0000279uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
280 uint32_t id = 0; // 0 means default/null typeface
281 if (face) {
282 id = fTypefaceSet.find(face);
283 if (0 == id) {
284 id = fTypefaceSet.add(face);
285 size_t size = writeTypeface(NULL, face);
286 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000287 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000288 writeTypeface(&fWriter, face);
289 }
290 }
291 }
292 return id;
293}
294
reed@google.combb6992a2011-04-26 17:41:56 +0000295///////////////////////////////////////////////////////////////////////////////
296
reed@google.comacd471f2011-05-03 21:26:46 +0000297#define NOTIFY_SETUP(canvas) \
298 AutoPipeNotify apn(canvas)
299
reed@google.combb6992a2011-04-26 17:41:56 +0000300int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000301 NOTIFY_SETUP(this);
302 if (this->needOpBytes()) {
303 this->writeOp(kSave_DrawOp, 0, flags);
304 }
reed@google.combb6992a2011-04-26 17:41:56 +0000305 return this->INHERITED::save(flags);
306}
307
308int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
309 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000310 NOTIFY_SETUP(this);
311 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000312 unsigned index = 0; // just to avoid the warning
313 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000314
reed@google.combb6992a2011-04-26 17:41:56 +0000315 if (bounds) {
316 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000317 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000318 }
319 if (paint) {
320 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
321 index = this->writePaint(*paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000322 size += 4;
reed@google.combb6992a2011-04-26 17:41:56 +0000323 }
324
reed@google.comacd471f2011-05-03 21:26:46 +0000325 if (this->needOpBytes(size)) {
326 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
327 if (bounds) {
328 fWriter.writeRect(*bounds);
329 }
330 if (paint) {
331 fWriter.write32(index);
332 }
reed@google.combb6992a2011-04-26 17:41:56 +0000333 }
334
335 // we just pass on the save, so we don't create a layer
336 return this->INHERITED::save(saveFlags);
337}
338
339void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000340 NOTIFY_SETUP(this);
341 if (this->needOpBytes()) {
342 this->writeOp(kRestore_DrawOp);
343 }
reed@google.combb6992a2011-04-26 17:41:56 +0000344 this->INHERITED::restore();
345}
346
347bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
348 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000349 NOTIFY_SETUP(this);
350 if (this->needOpBytes(2 * sizeof(SkScalar))) {
351 this->writeOp(kTranslate_DrawOp);
352 fWriter.writeScalar(dx);
353 fWriter.writeScalar(dy);
354 }
reed@google.combb6992a2011-04-26 17:41:56 +0000355 }
356 return this->INHERITED::translate(dx, dy);
357}
358
359bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
360 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000361 NOTIFY_SETUP(this);
362 if (this->needOpBytes(2 * sizeof(SkScalar))) {
363 this->writeOp(kScale_DrawOp);
364 fWriter.writeScalar(sx);
365 fWriter.writeScalar(sy);
366 }
reed@google.combb6992a2011-04-26 17:41:56 +0000367 }
368 return this->INHERITED::scale(sx, sy);
369}
370
371bool SkGPipeCanvas::rotate(SkScalar degrees) {
372 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000373 NOTIFY_SETUP(this);
374 if (this->needOpBytes(sizeof(SkScalar))) {
375 this->writeOp(kRotate_DrawOp);
376 fWriter.writeScalar(degrees);
377 }
reed@google.combb6992a2011-04-26 17:41:56 +0000378 }
379 return this->INHERITED::rotate(degrees);
380}
381
382bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
383 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000384 NOTIFY_SETUP(this);
385 if (this->needOpBytes(2 * sizeof(SkScalar))) {
386 this->writeOp(kSkew_DrawOp);
387 fWriter.writeScalar(sx);
388 fWriter.writeScalar(sy);
389 }
reed@google.combb6992a2011-04-26 17:41:56 +0000390 }
391 return this->INHERITED::skew(sx, sy);
392}
393
394bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
395 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000396 NOTIFY_SETUP(this);
397 if (this->needOpBytes(matrix.flatten(NULL))) {
398 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000399 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000400 }
reed@google.combb6992a2011-04-26 17:41:56 +0000401 }
402 return this->INHERITED::concat(matrix);
403}
404
405void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000406 NOTIFY_SETUP(this);
407 if (this->needOpBytes(matrix.flatten(NULL))) {
408 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000409 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000410 }
reed@google.combb6992a2011-04-26 17:41:56 +0000411 this->INHERITED::setMatrix(matrix);
412}
413
414bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000415 NOTIFY_SETUP(this);
416 if (this->needOpBytes(sizeof(SkRect))) {
417 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
418 fWriter.writeRect(rect);
419 }
reed@google.combb6992a2011-04-26 17:41:56 +0000420 return this->INHERITED::clipRect(rect, rgnOp);
421}
422
423bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000424 NOTIFY_SETUP(this);
425 if (this->needOpBytes(estimateFlattenSize(path))) {
426 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
427 path.flatten(fWriter);
428 }
reed@google.combb6992a2011-04-26 17:41:56 +0000429 // we just pass on the bounds of the path
430 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
431}
432
433bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000434 NOTIFY_SETUP(this);
435 if (this->needOpBytes(region.flatten(NULL))) {
436 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000437 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000438 }
reed@google.combb6992a2011-04-26 17:41:56 +0000439 return this->INHERITED::clipRegion(region, rgnOp);
440}
441
442///////////////////////////////////////////////////////////////////////////////
443
444void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000445 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000446 unsigned flags = 0;
447 if (color) {
448 flags |= kClear_HasColor_DrawOpFlag;
449 }
reed@google.comacd471f2011-05-03 21:26:46 +0000450 if (this->needOpBytes(sizeof(SkColor))) {
451 this->writeOp(kDrawClear_DrawOp, flags, 0);
452 if (color) {
453 fWriter.write32(color);
454 }
reed@google.combb6992a2011-04-26 17:41:56 +0000455 }
456}
457
458void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000459 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000460 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000461 if (this->needOpBytes()) {
462 this->writeOp(kDrawPaint_DrawOp, 0, paintIndex);
463 }
reed@google.combb6992a2011-04-26 17:41:56 +0000464}
465
466void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
467 const SkPoint pts[], const SkPaint& paint) {
468 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000469 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000470 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000471 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
472 this->writeOp(kDrawPoints_DrawOp, mode, paintIndex);
473 fWriter.write32(count);
474 fWriter.write(pts, count * sizeof(SkPoint));
475 }
reed@google.combb6992a2011-04-26 17:41:56 +0000476 }
477}
478
479void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000480 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000481 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000482 if (this->needOpBytes(sizeof(SkRect))) {
483 this->writeOp(kDrawRect_DrawOp, 0, paintIndex);
484 fWriter.writeRect(rect);
485 }
reed@google.combb6992a2011-04-26 17:41:56 +0000486}
487
488void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000489 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000490 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000491 if (this->needOpBytes(estimateFlattenSize(path))) {
492 this->writeOp(kDrawPath_DrawOp, 0, paintIndex);
493 path.flatten(fWriter);
494 }
reed@google.combb6992a2011-04-26 17:41:56 +0000495}
496
497void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
498 const SkPaint*) {
499 UNIMPLEMENTED
500}
501
502void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
503 const SkRect& dst, const SkPaint*) {
504 UNIMPLEMENTED
505}
506
507void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
508 const SkPaint*) {
509 UNIMPLEMENTED
510}
511
512void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
513 const SkPaint*) {
514 UNIMPLEMENTED
515}
516
517void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
518 SkScalar y, const SkPaint& paint) {
519 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000520 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000521 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000522 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
523 this->writeOp(kDrawText_DrawOp, 0, paintIndex);
524 fWriter.write32(byteLength);
525 fWriter.writePad(text, byteLength);
526 fWriter.writeScalar(x);
527 fWriter.writeScalar(y);
528 }
reed@google.combb6992a2011-04-26 17:41:56 +0000529 }
530}
531
532void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
533 const SkPoint pos[], const SkPaint& paint) {
534 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000535 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000536 unsigned paintIndex = this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000537 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000538 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
539 this->writeOp(kDrawPosText_DrawOp, 0, paintIndex);
540 fWriter.write32(byteLength);
541 fWriter.writePad(text, byteLength);
542 fWriter.write32(count);
543 fWriter.write(pos, count * sizeof(SkPoint));
544 }
reed@google.combb6992a2011-04-26 17:41:56 +0000545 }
546}
547
548void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
549 const SkScalar xpos[], SkScalar constY,
550 const SkPaint& paint) {
551 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000552 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000553 unsigned paintIndex = 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(SkScalar) + 4)) {
556 this->writeOp(kDrawPosTextH_DrawOp, 0, paintIndex);
557 fWriter.write32(byteLength);
558 fWriter.writePad(text, byteLength);
559 fWriter.write32(count);
560 fWriter.write(xpos, count * sizeof(SkScalar));
561 fWriter.writeScalar(constY);
562 }
reed@google.combb6992a2011-04-26 17:41:56 +0000563 }
564}
565
566void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
567 const SkPath& path, const SkMatrix* matrix,
568 const SkPaint& paint) {
569 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000570 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000571 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000572 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000573 if (matrix) {
574 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000575 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000576 }
577 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000578 if (this->needOpBytes(size)) {
579 this->writeOp(kDrawTextOnPath_DrawOp, flags, paintIndex);
reed@google.combb6992a2011-04-26 17:41:56 +0000580
reed@google.comacd471f2011-05-03 21:26:46 +0000581 fWriter.write32(byteLength);
582 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000583
reed@google.comacd471f2011-05-03 21:26:46 +0000584 path.flatten(fWriter);
585 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000586 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000587 }
reed@google.combb6992a2011-04-26 17:41:56 +0000588 }
589 }
590}
591
592void SkGPipeCanvas::drawPicture(SkPicture& picture) {
593 UNIMPLEMENTED
594}
595
596void SkGPipeCanvas::drawShape(SkShape* shape) {
597 UNIMPLEMENTED
598}
599
600void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
601 const SkPoint vertices[], const SkPoint texs[],
602 const SkColor colors[], SkXfermode*,
603 const uint16_t indices[], int indexCount,
604 const SkPaint& paint) {
605 if (0 == vertexCount) {
606 return;
607 }
608
reed@google.comacd471f2011-05-03 21:26:46 +0000609 NOTIFY_SETUP(this);
610 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000611 unsigned paintIndex = this->writePaint(paint);
612 unsigned flags = 0;
613 if (texs) {
614 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000615 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000616 }
617 if (colors) {
618 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000619 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000620 }
621 if (indices && indexCount > 0) {
622 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000623 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000624 }
625
reed@google.comacd471f2011-05-03 21:26:46 +0000626 if (this->needOpBytes(size)) {
627 this->writeOp(kDrawVertices_DrawOp, flags, paintIndex);
628 fWriter.write32(mode);
629 fWriter.write32(vertexCount);
630 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
631 if (texs) {
632 fWriter.write(texs, vertexCount * sizeof(SkPoint));
633 }
634 if (colors) {
635 fWriter.write(colors, vertexCount * sizeof(SkColor));
636 }
reed@google.combb6992a2011-04-26 17:41:56 +0000637
reed@google.comacd471f2011-05-03 21:26:46 +0000638 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000639
reed@google.comacd471f2011-05-03 21:26:46 +0000640 if (indices && indexCount > 0) {
641 fWriter.write32(indexCount);
642 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
643 }
reed@google.combb6992a2011-04-26 17:41:56 +0000644 }
645}
646
reed@google.comacd471f2011-05-03 21:26:46 +0000647void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
648 if (size && ptr) {
649 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000650 unsigned data = 0;
651 if (size < (1 << DRAWOPS_DATA_BITS)) {
652 data = (unsigned)size;
653 }
reed@google.comacd471f2011-05-03 21:26:46 +0000654 if (this->needOpBytes(4 + SkAlign4(size))) {
655 this->writeOp(kDrawData_DrawOp, 0, data);
656 if (0 == data) {
657 fWriter.write32(size);
658 }
reed@google.combb6793b2011-05-05 15:18:15 +0000659 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000660 }
661 }
662}
663
664///////////////////////////////////////////////////////////////////////////////
665
666template <typename T> uint32_t castToU32(T value) {
667 union {
668 T fSrc;
669 uint32_t fDst;
670 } data;
671 data.fSrc = value;
672 return data.fDst;
673}
674
675unsigned SkGPipeCanvas::writePaint(const SkPaint& paint) {
reed@google.comf5842f72011-05-04 18:30:04 +0000676 SkPaint& base = *fPaints[0];
reed@google.combb6992a2011-04-26 17:41:56 +0000677 uint32_t storage[32];
678 uint32_t* ptr = storage;
679 uint32_t* last = NULL;
680
681 if (base.getFlags() != paint.getFlags()) {
682 last = ptr;
683 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000684 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000685 }
686 if (base.getColor() != paint.getColor()) {
687 last = ptr;
688 *ptr++ = PaintOp_packOp(kColor_PaintOp);
689 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000690 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000691 }
692 if (base.getStyle() != paint.getStyle()) {
693 last = ptr;
694 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000695 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000696 }
697 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
698 last = ptr;
699 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000700 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000701 }
702 if (base.getStrokeCap() != paint.getStrokeCap()) {
703 last = ptr;
704 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000705 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000706 }
707 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
708 last = ptr;
709 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
710 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000711 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000712 }
713 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
714 last = ptr;
715 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
716 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000717 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000718 }
719 if (base.getTextEncoding() != paint.getTextEncoding()) {
720 last = ptr;
721 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000722 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000723 }
724 if (base.getHinting() != paint.getHinting()) {
725 last = ptr;
726 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000727 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000728 }
729 if (base.getTextAlign() != paint.getTextAlign()) {
730 last = ptr;
731 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000732 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000733 }
734 if (base.getTextSize() != paint.getTextSize()) {
735 last = ptr;
736 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
737 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000738 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000739 }
740 if (base.getTextScaleX() != paint.getTextScaleX()) {
741 last = ptr;
742 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
743 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000744 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000745 }
746 if (base.getTextSkewX() != paint.getTextSkewX()) {
747 last = ptr;
748 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
749 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000750 base.setTextSkewX(paint.getTextSkewX());
751 }
752
753 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
754 uint32_t id = this->getTypefaceID(paint.getTypeface());
755 last = ptr;
756 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
757 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000758 }
reed@google.combb6992a2011-04-26 17:41:56 +0000759
reed@google.comb55d1182011-05-11 00:42:04 +0000760 for (int i = 0; i < kCount_PaintFlats; i++) {
761 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
762 SkASSERT(index >= 0 && index <= fFlatArray.count());
763 if (index != fCurrFlatIndex[i]) {
764 last = ptr;
765 *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);
773// *last |= kLastOp_PaintOpFlag << PAINTOPS_DATA_BITS;
774 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000775 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000776// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000777 }
778 }
779 return 0;
780}
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.comacd471f2011-05-03 21:26:46 +0000795SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller) {
reed@google.combb6992a2011-04-26 17:41:56 +0000796 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000797 fWriter.reset(NULL, 0);
798 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter));
reed@google.combb6992a2011-04-26 17:41:56 +0000799 }
800 return fCanvas;
801}
802
803void SkGPipeWriter::endRecording() {
804 if (fCanvas) {
805 fCanvas->finish();
806 fCanvas->unref();
807 fCanvas = NULL;
808 }
809}
810