blob: fa93113946e324079e534f7612a69c146dccf2e4 [file] [log] [blame]
reed@google.combb6992a2011-04-26 17:41:56 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "SkCanvas.h"
reed@google.com8a85d0c2011-06-24 19:12:12 +000019#include "SkData.h"
reed@google.combb6793b2011-05-05 15:18:15 +000020#include "SkDevice.h"
reed@google.combb6992a2011-04-26 17:41:56 +000021#include "SkPaint.h"
reed@google.comacd471f2011-05-03 21:26:46 +000022#include "SkGPipe.h"
reed@google.combb6992a2011-04-26 17:41:56 +000023#include "SkGPipePriv.h"
reed@google.comf5842f72011-05-04 18:30:04 +000024#include "SkStream.h"
reed@google.comb55d1182011-05-11 00:42:04 +000025#include "SkTSearch.h"
reed@google.comf5842f72011-05-04 18:30:04 +000026#include "SkTypeface.h"
reed@google.combb6992a2011-04-26 17:41:56 +000027#include "SkWriter32.h"
reed@google.comb55d1182011-05-11 00:42:04 +000028#include "SkColorFilter.h"
reed@google.com0faac1e2011-05-11 05:58:58 +000029#include "SkDrawLooper.h"
reed@google.comb55d1182011-05-11 00:42:04 +000030#include "SkMaskFilter.h"
31#include "SkRasterizer.h"
32#include "SkShader.h"
33
34static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
35 SkASSERT(paintFlat < kCount_PaintFlats);
36 switch (paintFlat) {
37 case kColorFilter_PaintFlat: return paint.getColorFilter();
reed@google.com0faac1e2011-05-11 05:58:58 +000038 case kDrawLooper_PaintFlat: return paint.getLooper();
reed@google.comb55d1182011-05-11 00:42:04 +000039 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
40 case kPathEffect_PaintFlat: return paint.getPathEffect();
41 case kRasterizer_PaintFlat: return paint.getRasterizer();
42 case kShader_PaintFlat: return paint.getShader();
43 case kXfermode_PaintFlat: return paint.getXfermode();
44 }
45 SkASSERT(!"never gets here");
46 return NULL;
47}
reed@google.combb6992a2011-04-26 17:41:56 +000048
reed@google.comacd471f2011-05-03 21:26:46 +000049static size_t estimateFlattenSize(const SkPath& path) {
50 int n = path.countPoints();
51 size_t bytes = 3 * sizeof(int32_t);
52 bytes += n * sizeof(SkPoint);
53 bytes += SkAlign4(n + 2); // verbs: add 2 for move/close extras
54
55#ifdef SK_DEBUG
56 {
57 SkWriter32 writer(1024);
58 path.flatten(writer);
59 SkASSERT(writer.size() <= bytes);
60 }
61#endif
62 return bytes;
63}
64
reed@google.comf5842f72011-05-04 18:30:04 +000065static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
66 SkASSERT(typeface);
67 SkDynamicMemoryWStream stream;
68 typeface->serialize(&stream);
69 size_t size = stream.getOffset();
70 if (writer) {
71 writer->write32(size);
reed@google.com8a85d0c2011-06-24 19:12:12 +000072 SkAutoDataUnref data(stream.copyToData());
73 writer->write(data.data(), size);
reed@google.comf5842f72011-05-04 18:30:04 +000074 }
75 return 4 + size;
76}
77
reed@google.combb6992a2011-04-26 17:41:56 +000078///////////////////////////////////////////////////////////////////////////////
79
80class SkGPipeCanvas : public SkCanvas {
81public:
reed@google.comdde09562011-05-23 12:21:05 +000082 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
reed@google.combb6992a2011-04-26 17:41:56 +000083 virtual ~SkGPipeCanvas();
84
85 void finish() {
86 if (!fDone) {
87 this->writeOp(kDone_DrawOp);
reed@google.comeb5a8152011-05-23 21:09:13 +000088 this->doNotify();
reed@google.combb6992a2011-04-26 17:41:56 +000089 fDone = true;
90 }
91 }
92
93 // overrides from SkCanvas
94 virtual int save(SaveFlags);
95 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
96 virtual void restore();
97 virtual bool translate(SkScalar dx, SkScalar dy);
98 virtual bool scale(SkScalar sx, SkScalar sy);
99 virtual bool rotate(SkScalar degrees);
100 virtual bool skew(SkScalar sx, SkScalar sy);
101 virtual bool concat(const SkMatrix& matrix);
102 virtual void setMatrix(const SkMatrix& matrix);
103 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
104 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
105 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
106 virtual void clear(SkColor);
107 virtual void drawPaint(const SkPaint& paint);
108 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
109 const SkPaint&);
110 virtual void drawRect(const SkRect& rect, const SkPaint&);
111 virtual void drawPath(const SkPath& path, const SkPaint&);
112 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
113 const SkPaint*);
114 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
115 const SkRect& dst, const SkPaint*);
116 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
117 const SkPaint*);
118 virtual void drawSprite(const SkBitmap&, int left, int top,
119 const SkPaint*);
120 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
121 SkScalar y, const SkPaint&);
122 virtual void drawPosText(const void* text, size_t byteLength,
123 const SkPoint pos[], const SkPaint&);
124 virtual void drawPosTextH(const void* text, size_t byteLength,
125 const SkScalar xpos[], SkScalar constY, const SkPaint&);
126 virtual void drawTextOnPath(const void* text, size_t byteLength,
127 const SkPath& path, const SkMatrix* matrix,
128 const SkPaint&);
129 virtual void drawPicture(SkPicture& picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000130 virtual void drawVertices(VertexMode, int vertexCount,
131 const SkPoint vertices[], const SkPoint texs[],
132 const SkColor colors[], SkXfermode*,
133 const uint16_t indices[], int indexCount,
134 const SkPaint&);
135 virtual void drawData(const void*, size_t);
136
137private:
reed@google.comdde09562011-05-23 12:21:05 +0000138 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000139 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000140 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000141 size_t fBlockSize; // amount allocated for writer
142 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000143 bool fDone;
144
reed@google.comf5842f72011-05-04 18:30:04 +0000145 SkRefCntSet fTypefaceSet;
146
147 uint32_t getTypefaceID(SkTypeface*);
148
reed@google.comacd471f2011-05-03 21:26:46 +0000149 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000150 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
151 }
152
reed@google.comacd471f2011-05-03 21:26:46 +0000153 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000154 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
155 }
reed@google.comacd471f2011-05-03 21:26:46 +0000156
157 bool needOpBytes(size_t size = 0);
158
159 inline void doNotify() {
160 if (!fDone) {
161 size_t bytes = fWriter.size() - fBytesNotified;
162 fController->notifyWritten(bytes);
163 fBytesNotified += bytes;
164 }
165 }
reed@google.comb55d1182011-05-11 00:42:04 +0000166
167 struct FlatData {
168 uint32_t fIndex; // always > 0
169 uint32_t fSize;
170
171 void* data() { return (char*)this + sizeof(*this); }
172
173 static int Compare(const FlatData* a, const FlatData* b) {
174 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
175 }
176 };
177 SkTDArray<FlatData*> fFlatArray;
178 int fCurrFlatIndex[kCount_PaintFlats];
179 int flattenToIndex(SkFlattenable* obj, PaintFlats);
180
reed@google.com31891582011-05-12 03:03:56 +0000181 SkPaint fPaint;
182 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000183
reed@google.comacd471f2011-05-03 21:26:46 +0000184 class AutoPipeNotify {
185 public:
186 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
187 ~AutoPipeNotify() { fCanvas->doNotify(); }
188 private:
189 SkGPipeCanvas* fCanvas;
190 };
191 friend class AutoPipeNotify;
192
reed@google.combb6992a2011-04-26 17:41:56 +0000193 typedef SkCanvas INHERITED;
194};
195
reed@google.comb55d1182011-05-11 00:42:04 +0000196// return 0 for NULL (or unflattenable obj), or index-base-1
197int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
198 if (NULL == obj) {
199 return 0;
200 }
reed@google.comb55d1182011-05-11 00:42:04 +0000201
202 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.com6bac9472011-06-21 19:24:00 +0000203 tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
reed@google.comdde09562011-05-23 12:21:05 +0000204 tmpWriter.setFactoryRecorder(fFactorySet);
205
reed@google.comb55d1182011-05-11 00:42:04 +0000206 tmpWriter.writeFlattenable(obj);
207 size_t len = tmpWriter.size();
208 size_t allocSize = len + sizeof(FlatData);
209
210 SkAutoSMalloc<1024> storage(allocSize);
211 FlatData* flat = (FlatData*)storage.get();
212 flat->fSize = len;
213 tmpWriter.flatten(flat->data());
214
215 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
216 fFlatArray.count(), flat, sizeof(flat),
217 &FlatData::Compare);
218 if (index < 0) {
219 index = ~index;
220 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
221 memcpy(copy, flat, allocSize);
222 *fFlatArray.insert(index) = copy;
223 // call this after the insert, so that count() will have been grown
224 copy->fIndex = fFlatArray.count();
225// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
226
227 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000228 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000229 fWriter.write(copy->data(), len);
230 }
231 }
232 return fFlatArray[index]->fIndex;
233}
234
reed@google.combb6992a2011-04-26 17:41:56 +0000235///////////////////////////////////////////////////////////////////////////////
236
reed@google.comacd471f2011-05-03 21:26:46 +0000237#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000238
reed@google.comacd471f2011-05-03 21:26:46 +0000239SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000240 SkWriter32* writer, SkFactorySet* fset)
reed@google.com67908f22011-06-27 14:47:50 +0000241 : fWriter(*writer) {
242 fFactorySet = fset;
reed@google.comacd471f2011-05-03 21:26:46 +0000243 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000244 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000245 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000246 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000247
reed@google.combb6793b2011-05-05 15:18:15 +0000248 // we need a device to limit our clip
249 // should the caller give us the bounds?
yangsu@google.com06b4da12011-06-17 15:04:40 +0000250 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000251 SkBitmap bitmap;
252 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da12011-06-17 15:04:40 +0000253 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000254 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000255}
256
257SkGPipeCanvas::~SkGPipeCanvas() {
258 this->finish();
259
reed@google.comb55d1182011-05-11 00:42:04 +0000260 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000261}
262
reed@google.comacd471f2011-05-03 21:26:46 +0000263bool SkGPipeCanvas::needOpBytes(size_t needed) {
264 if (fDone) {
265 return false;
266 }
267
268 needed += 4; // size of DrawOp atom
269 if (fWriter.size() + needed > fBlockSize) {
270 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
271 if (NULL == block) {
272 fDone = true;
273 return false;
274 }
275 fWriter.reset(block, fBlockSize);
276 fBytesNotified = 0;
277 }
278 return true;
279}
280
reed@google.comf5842f72011-05-04 18:30:04 +0000281uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
282 uint32_t id = 0; // 0 means default/null typeface
283 if (face) {
284 id = fTypefaceSet.find(face);
285 if (0 == id) {
286 id = fTypefaceSet.add(face);
287 size_t size = writeTypeface(NULL, face);
288 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000289 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000290 writeTypeface(&fWriter, face);
291 }
292 }
293 }
294 return id;
295}
296
reed@google.combb6992a2011-04-26 17:41:56 +0000297///////////////////////////////////////////////////////////////////////////////
298
reed@google.comacd471f2011-05-03 21:26:46 +0000299#define NOTIFY_SETUP(canvas) \
300 AutoPipeNotify apn(canvas)
301
reed@google.combb6992a2011-04-26 17:41:56 +0000302int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000303 NOTIFY_SETUP(this);
304 if (this->needOpBytes()) {
305 this->writeOp(kSave_DrawOp, 0, flags);
306 }
reed@google.combb6992a2011-04-26 17:41:56 +0000307 return this->INHERITED::save(flags);
308}
309
310int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
311 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000312 NOTIFY_SETUP(this);
313 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000314 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000315
reed@google.combb6992a2011-04-26 17:41:56 +0000316 if (bounds) {
317 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000318 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000319 }
320 if (paint) {
321 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000322 this->writePaint(*paint);
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 }
reed@google.combb6992a2011-04-26 17:41:56 +0000330 }
331
332 // we just pass on the save, so we don't create a layer
333 return this->INHERITED::save(saveFlags);
334}
335
336void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000337 NOTIFY_SETUP(this);
338 if (this->needOpBytes()) {
339 this->writeOp(kRestore_DrawOp);
340 }
reed@google.combb6992a2011-04-26 17:41:56 +0000341 this->INHERITED::restore();
342}
343
344bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
345 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000346 NOTIFY_SETUP(this);
347 if (this->needOpBytes(2 * sizeof(SkScalar))) {
348 this->writeOp(kTranslate_DrawOp);
349 fWriter.writeScalar(dx);
350 fWriter.writeScalar(dy);
351 }
reed@google.combb6992a2011-04-26 17:41:56 +0000352 }
353 return this->INHERITED::translate(dx, dy);
354}
355
356bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
357 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000358 NOTIFY_SETUP(this);
359 if (this->needOpBytes(2 * sizeof(SkScalar))) {
360 this->writeOp(kScale_DrawOp);
361 fWriter.writeScalar(sx);
362 fWriter.writeScalar(sy);
363 }
reed@google.combb6992a2011-04-26 17:41:56 +0000364 }
365 return this->INHERITED::scale(sx, sy);
366}
367
368bool SkGPipeCanvas::rotate(SkScalar degrees) {
369 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000370 NOTIFY_SETUP(this);
371 if (this->needOpBytes(sizeof(SkScalar))) {
372 this->writeOp(kRotate_DrawOp);
373 fWriter.writeScalar(degrees);
374 }
reed@google.combb6992a2011-04-26 17:41:56 +0000375 }
376 return this->INHERITED::rotate(degrees);
377}
378
379bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
380 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000381 NOTIFY_SETUP(this);
382 if (this->needOpBytes(2 * sizeof(SkScalar))) {
383 this->writeOp(kSkew_DrawOp);
384 fWriter.writeScalar(sx);
385 fWriter.writeScalar(sy);
386 }
reed@google.combb6992a2011-04-26 17:41:56 +0000387 }
388 return this->INHERITED::skew(sx, sy);
389}
390
391bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
392 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000393 NOTIFY_SETUP(this);
394 if (this->needOpBytes(matrix.flatten(NULL))) {
395 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000396 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000397 }
reed@google.combb6992a2011-04-26 17:41:56 +0000398 }
399 return this->INHERITED::concat(matrix);
400}
401
402void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000403 NOTIFY_SETUP(this);
404 if (this->needOpBytes(matrix.flatten(NULL))) {
405 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000406 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000407 }
reed@google.combb6992a2011-04-26 17:41:56 +0000408 this->INHERITED::setMatrix(matrix);
409}
410
411bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000412 NOTIFY_SETUP(this);
413 if (this->needOpBytes(sizeof(SkRect))) {
414 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
415 fWriter.writeRect(rect);
416 }
reed@google.combb6992a2011-04-26 17:41:56 +0000417 return this->INHERITED::clipRect(rect, rgnOp);
418}
419
420bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000421 NOTIFY_SETUP(this);
422 if (this->needOpBytes(estimateFlattenSize(path))) {
423 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
424 path.flatten(fWriter);
425 }
reed@google.combb6992a2011-04-26 17:41:56 +0000426 // we just pass on the bounds of the path
427 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
428}
429
430bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000431 NOTIFY_SETUP(this);
432 if (this->needOpBytes(region.flatten(NULL))) {
433 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000434 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000435 }
reed@google.combb6992a2011-04-26 17:41:56 +0000436 return this->INHERITED::clipRegion(region, rgnOp);
437}
438
439///////////////////////////////////////////////////////////////////////////////
440
441void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000442 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000443 unsigned flags = 0;
444 if (color) {
445 flags |= kClear_HasColor_DrawOpFlag;
446 }
reed@google.comacd471f2011-05-03 21:26:46 +0000447 if (this->needOpBytes(sizeof(SkColor))) {
448 this->writeOp(kDrawClear_DrawOp, flags, 0);
449 if (color) {
450 fWriter.write32(color);
451 }
reed@google.combb6992a2011-04-26 17:41:56 +0000452 }
453}
454
455void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000456 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000457 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000458 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000459 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000460 }
reed@google.combb6992a2011-04-26 17:41:56 +0000461}
462
463void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
464 const SkPoint pts[], const SkPaint& paint) {
465 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000466 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000467 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000468 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000469 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000470 fWriter.write32(count);
471 fWriter.write(pts, count * sizeof(SkPoint));
472 }
reed@google.combb6992a2011-04-26 17:41:56 +0000473 }
474}
475
476void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000477 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000478 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000479 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000480 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000481 fWriter.writeRect(rect);
482 }
reed@google.combb6992a2011-04-26 17:41:56 +0000483}
484
485void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
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(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000489 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000490 path.flatten(fWriter);
491 }
reed@google.combb6992a2011-04-26 17:41:56 +0000492}
493
494void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
495 const SkPaint*) {
496 UNIMPLEMENTED
497}
498
499void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
500 const SkRect& dst, const SkPaint*) {
501 UNIMPLEMENTED
502}
503
504void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
505 const SkPaint*) {
506 UNIMPLEMENTED
507}
508
509void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
510 const SkPaint*) {
511 UNIMPLEMENTED
512}
513
514void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
515 SkScalar y, const SkPaint& paint) {
516 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000517 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000518 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000519 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000520 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000521 fWriter.write32(byteLength);
522 fWriter.writePad(text, byteLength);
523 fWriter.writeScalar(x);
524 fWriter.writeScalar(y);
525 }
reed@google.combb6992a2011-04-26 17:41:56 +0000526 }
527}
528
529void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
530 const SkPoint pos[], const SkPaint& paint) {
531 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000532 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000533 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000534 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000535 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000536 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000537 fWriter.write32(byteLength);
538 fWriter.writePad(text, byteLength);
539 fWriter.write32(count);
540 fWriter.write(pos, count * sizeof(SkPoint));
541 }
reed@google.combb6992a2011-04-26 17:41:56 +0000542 }
543}
544
545void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
546 const SkScalar xpos[], SkScalar constY,
547 const SkPaint& paint) {
548 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000549 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000550 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000551 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000552 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000553 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000554 fWriter.write32(byteLength);
555 fWriter.writePad(text, byteLength);
556 fWriter.write32(count);
557 fWriter.write(xpos, count * sizeof(SkScalar));
558 fWriter.writeScalar(constY);
559 }
reed@google.combb6992a2011-04-26 17:41:56 +0000560 }
561}
562
563void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
564 const SkPath& path, const SkMatrix* matrix,
565 const SkPaint& paint) {
566 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000567 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000568 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000569 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000570 if (matrix) {
571 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000572 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000573 }
reed@google.com31891582011-05-12 03:03:56 +0000574 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000575 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000576 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000577
reed@google.comacd471f2011-05-03 21:26:46 +0000578 fWriter.write32(byteLength);
579 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000580
reed@google.comacd471f2011-05-03 21:26:46 +0000581 path.flatten(fWriter);
582 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000583 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000584 }
reed@google.combb6992a2011-04-26 17:41:56 +0000585 }
586 }
587}
588
589void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000590 // we want to playback the picture into individual draw calls
591 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000592}
593
reed@google.combb6992a2011-04-26 17:41:56 +0000594void 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.comdde09562011-05-23 12:21:05 +0000771SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
772 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000773 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000774 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000775 fFactorySet.reset();
776 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
777 (flags & kCrossProcess_Flag) ?
778 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000779 }
780 return fCanvas;
781}
782
783void SkGPipeWriter::endRecording() {
784 if (fCanvas) {
785 fCanvas->finish();
786 fCanvas->unref();
787 fCanvas = NULL;
788 }
789}
790