blob: b1eebc87ce1f2a6e84a88225bf7457be1c0a291d [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)
241 : fWriter(*writer), fFactorySet(fset) {
reed@google.comacd471f2011-05-03 21:26:46 +0000242 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000243 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000244 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000245 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000246
reed@google.combb6793b2011-05-05 15:18:15 +0000247 // we need a device to limit our clip
248 // should the caller give us the bounds?
yangsu@google.com06b4da12011-06-17 15:04:40 +0000249 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000250 SkBitmap bitmap;
251 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da12011-06-17 15:04:40 +0000252 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000253 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000254}
255
256SkGPipeCanvas::~SkGPipeCanvas() {
257 this->finish();
258
reed@google.comb55d1182011-05-11 00:42:04 +0000259 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000260}
261
reed@google.comacd471f2011-05-03 21:26:46 +0000262bool SkGPipeCanvas::needOpBytes(size_t needed) {
263 if (fDone) {
264 return false;
265 }
266
267 needed += 4; // size of DrawOp atom
268 if (fWriter.size() + needed > fBlockSize) {
269 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
270 if (NULL == block) {
271 fDone = true;
272 return false;
273 }
274 fWriter.reset(block, fBlockSize);
275 fBytesNotified = 0;
276 }
277 return true;
278}
279
reed@google.comf5842f72011-05-04 18:30:04 +0000280uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
281 uint32_t id = 0; // 0 means default/null typeface
282 if (face) {
283 id = fTypefaceSet.find(face);
284 if (0 == id) {
285 id = fTypefaceSet.add(face);
286 size_t size = writeTypeface(NULL, face);
287 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000288 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000289 writeTypeface(&fWriter, face);
290 }
291 }
292 }
293 return id;
294}
295
reed@google.combb6992a2011-04-26 17:41:56 +0000296///////////////////////////////////////////////////////////////////////////////
297
reed@google.comacd471f2011-05-03 21:26:46 +0000298#define NOTIFY_SETUP(canvas) \
299 AutoPipeNotify apn(canvas)
300
reed@google.combb6992a2011-04-26 17:41:56 +0000301int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000302 NOTIFY_SETUP(this);
303 if (this->needOpBytes()) {
304 this->writeOp(kSave_DrawOp, 0, flags);
305 }
reed@google.combb6992a2011-04-26 17:41:56 +0000306 return this->INHERITED::save(flags);
307}
308
309int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
310 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000311 NOTIFY_SETUP(this);
312 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000313 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;
reed@google.com31891582011-05-12 03:03:56 +0000321 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000322 }
323
reed@google.comacd471f2011-05-03 21:26:46 +0000324 if (this->needOpBytes(size)) {
325 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
326 if (bounds) {
327 fWriter.writeRect(*bounds);
328 }
reed@google.combb6992a2011-04-26 17:41:56 +0000329 }
330
331 // we just pass on the save, so we don't create a layer
332 return this->INHERITED::save(saveFlags);
333}
334
335void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000336 NOTIFY_SETUP(this);
337 if (this->needOpBytes()) {
338 this->writeOp(kRestore_DrawOp);
339 }
reed@google.combb6992a2011-04-26 17:41:56 +0000340 this->INHERITED::restore();
341}
342
343bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
344 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000345 NOTIFY_SETUP(this);
346 if (this->needOpBytes(2 * sizeof(SkScalar))) {
347 this->writeOp(kTranslate_DrawOp);
348 fWriter.writeScalar(dx);
349 fWriter.writeScalar(dy);
350 }
reed@google.combb6992a2011-04-26 17:41:56 +0000351 }
352 return this->INHERITED::translate(dx, dy);
353}
354
355bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
356 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000357 NOTIFY_SETUP(this);
358 if (this->needOpBytes(2 * sizeof(SkScalar))) {
359 this->writeOp(kScale_DrawOp);
360 fWriter.writeScalar(sx);
361 fWriter.writeScalar(sy);
362 }
reed@google.combb6992a2011-04-26 17:41:56 +0000363 }
364 return this->INHERITED::scale(sx, sy);
365}
366
367bool SkGPipeCanvas::rotate(SkScalar degrees) {
368 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000369 NOTIFY_SETUP(this);
370 if (this->needOpBytes(sizeof(SkScalar))) {
371 this->writeOp(kRotate_DrawOp);
372 fWriter.writeScalar(degrees);
373 }
reed@google.combb6992a2011-04-26 17:41:56 +0000374 }
375 return this->INHERITED::rotate(degrees);
376}
377
378bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
379 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000380 NOTIFY_SETUP(this);
381 if (this->needOpBytes(2 * sizeof(SkScalar))) {
382 this->writeOp(kSkew_DrawOp);
383 fWriter.writeScalar(sx);
384 fWriter.writeScalar(sy);
385 }
reed@google.combb6992a2011-04-26 17:41:56 +0000386 }
387 return this->INHERITED::skew(sx, sy);
388}
389
390bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
391 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000392 NOTIFY_SETUP(this);
393 if (this->needOpBytes(matrix.flatten(NULL))) {
394 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000395 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000396 }
reed@google.combb6992a2011-04-26 17:41:56 +0000397 }
398 return this->INHERITED::concat(matrix);
399}
400
401void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000402 NOTIFY_SETUP(this);
403 if (this->needOpBytes(matrix.flatten(NULL))) {
404 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000405 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000406 }
reed@google.combb6992a2011-04-26 17:41:56 +0000407 this->INHERITED::setMatrix(matrix);
408}
409
410bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000411 NOTIFY_SETUP(this);
412 if (this->needOpBytes(sizeof(SkRect))) {
413 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
414 fWriter.writeRect(rect);
415 }
reed@google.combb6992a2011-04-26 17:41:56 +0000416 return this->INHERITED::clipRect(rect, rgnOp);
417}
418
419bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000420 NOTIFY_SETUP(this);
421 if (this->needOpBytes(estimateFlattenSize(path))) {
422 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
423 path.flatten(fWriter);
424 }
reed@google.combb6992a2011-04-26 17:41:56 +0000425 // we just pass on the bounds of the path
426 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
427}
428
429bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000430 NOTIFY_SETUP(this);
431 if (this->needOpBytes(region.flatten(NULL))) {
432 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000433 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000434 }
reed@google.combb6992a2011-04-26 17:41:56 +0000435 return this->INHERITED::clipRegion(region, rgnOp);
436}
437
438///////////////////////////////////////////////////////////////////////////////
439
440void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000441 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000442 unsigned flags = 0;
443 if (color) {
444 flags |= kClear_HasColor_DrawOpFlag;
445 }
reed@google.comacd471f2011-05-03 21:26:46 +0000446 if (this->needOpBytes(sizeof(SkColor))) {
447 this->writeOp(kDrawClear_DrawOp, flags, 0);
448 if (color) {
449 fWriter.write32(color);
450 }
reed@google.combb6992a2011-04-26 17:41:56 +0000451 }
452}
453
454void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000455 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000456 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000457 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000458 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000459 }
reed@google.combb6992a2011-04-26 17:41:56 +0000460}
461
462void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
463 const SkPoint pts[], const SkPaint& paint) {
464 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000465 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000466 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000467 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000468 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000469 fWriter.write32(count);
470 fWriter.write(pts, count * sizeof(SkPoint));
471 }
reed@google.combb6992a2011-04-26 17:41:56 +0000472 }
473}
474
475void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000476 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000477 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000478 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000479 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000480 fWriter.writeRect(rect);
481 }
reed@google.combb6992a2011-04-26 17:41:56 +0000482}
483
484void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000485 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000486 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000487 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000488 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000489 path.flatten(fWriter);
490 }
reed@google.combb6992a2011-04-26 17:41:56 +0000491}
492
493void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
494 const SkPaint*) {
495 UNIMPLEMENTED
496}
497
498void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
499 const SkRect& dst, const SkPaint*) {
500 UNIMPLEMENTED
501}
502
503void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
504 const SkPaint*) {
505 UNIMPLEMENTED
506}
507
508void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
509 const SkPaint*) {
510 UNIMPLEMENTED
511}
512
513void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
514 SkScalar y, const SkPaint& paint) {
515 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000516 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000517 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000518 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000519 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000520 fWriter.write32(byteLength);
521 fWriter.writePad(text, byteLength);
522 fWriter.writeScalar(x);
523 fWriter.writeScalar(y);
524 }
reed@google.combb6992a2011-04-26 17:41:56 +0000525 }
526}
527
528void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
529 const SkPoint pos[], const SkPaint& paint) {
530 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000531 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000532 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000533 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000534 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000535 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000536 fWriter.write32(byteLength);
537 fWriter.writePad(text, byteLength);
538 fWriter.write32(count);
539 fWriter.write(pos, count * sizeof(SkPoint));
540 }
reed@google.combb6992a2011-04-26 17:41:56 +0000541 }
542}
543
544void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
545 const SkScalar xpos[], SkScalar constY,
546 const SkPaint& paint) {
547 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000548 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000549 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000550 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000551 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000552 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000553 fWriter.write32(byteLength);
554 fWriter.writePad(text, byteLength);
555 fWriter.write32(count);
556 fWriter.write(xpos, count * sizeof(SkScalar));
557 fWriter.writeScalar(constY);
558 }
reed@google.combb6992a2011-04-26 17:41:56 +0000559 }
560}
561
562void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
563 const SkPath& path, const SkMatrix* matrix,
564 const SkPaint& paint) {
565 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000566 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000567 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000568 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000569 if (matrix) {
570 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000571 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000572 }
reed@google.com31891582011-05-12 03:03:56 +0000573 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000574 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000575 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000576
reed@google.comacd471f2011-05-03 21:26:46 +0000577 fWriter.write32(byteLength);
578 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000579
reed@google.comacd471f2011-05-03 21:26:46 +0000580 path.flatten(fWriter);
581 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000582 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000583 }
reed@google.combb6992a2011-04-26 17:41:56 +0000584 }
585 }
586}
587
588void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000589 // we want to playback the picture into individual draw calls
590 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000591}
592
reed@google.combb6992a2011-04-26 17:41:56 +0000593void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
594 const SkPoint vertices[], const SkPoint texs[],
595 const SkColor colors[], SkXfermode*,
596 const uint16_t indices[], int indexCount,
597 const SkPaint& paint) {
598 if (0 == vertexCount) {
599 return;
600 }
601
reed@google.comacd471f2011-05-03 21:26:46 +0000602 NOTIFY_SETUP(this);
603 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000604 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000605 unsigned flags = 0;
606 if (texs) {
607 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000608 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000609 }
610 if (colors) {
611 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000612 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000613 }
614 if (indices && indexCount > 0) {
615 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000616 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000617 }
618
reed@google.comacd471f2011-05-03 21:26:46 +0000619 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000620 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000621 fWriter.write32(mode);
622 fWriter.write32(vertexCount);
623 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
624 if (texs) {
625 fWriter.write(texs, vertexCount * sizeof(SkPoint));
626 }
627 if (colors) {
628 fWriter.write(colors, vertexCount * sizeof(SkColor));
629 }
reed@google.combb6992a2011-04-26 17:41:56 +0000630
reed@google.comacd471f2011-05-03 21:26:46 +0000631 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000632
reed@google.comacd471f2011-05-03 21:26:46 +0000633 if (indices && indexCount > 0) {
634 fWriter.write32(indexCount);
635 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
636 }
reed@google.combb6992a2011-04-26 17:41:56 +0000637 }
638}
639
reed@google.comacd471f2011-05-03 21:26:46 +0000640void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
641 if (size && ptr) {
642 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000643 unsigned data = 0;
644 if (size < (1 << DRAWOPS_DATA_BITS)) {
645 data = (unsigned)size;
646 }
reed@google.comacd471f2011-05-03 21:26:46 +0000647 if (this->needOpBytes(4 + SkAlign4(size))) {
648 this->writeOp(kDrawData_DrawOp, 0, data);
649 if (0 == data) {
650 fWriter.write32(size);
651 }
reed@google.combb6793b2011-05-05 15:18:15 +0000652 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000653 }
654 }
655}
656
657///////////////////////////////////////////////////////////////////////////////
658
659template <typename T> uint32_t castToU32(T value) {
660 union {
661 T fSrc;
662 uint32_t fDst;
663 } data;
664 data.fSrc = value;
665 return data.fDst;
666}
667
reed@google.com31891582011-05-12 03:03:56 +0000668void SkGPipeCanvas::writePaint(const SkPaint& paint) {
669 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000670 uint32_t storage[32];
671 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000672
673 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000674 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000675 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000676 }
677 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000678 *ptr++ = PaintOp_packOp(kColor_PaintOp);
679 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000680 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000681 }
682 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000683 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000684 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000685 }
686 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000687 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000688 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000689 }
690 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000691 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000692 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000693 }
694 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000695 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
696 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000697 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000698 }
699 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000700 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
701 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000702 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000703 }
704 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000705 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000706 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000707 }
708 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000709 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000710 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000711 }
712 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000713 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000714 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000715 }
716 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000717 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
718 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000719 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000720 }
721 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000722 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
723 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000724 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000725 }
726 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000727 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
728 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000729 base.setTextSkewX(paint.getTextSkewX());
730 }
731
732 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
733 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000734 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
735 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000736 }
reed@google.combb6992a2011-04-26 17:41:56 +0000737
reed@google.comb55d1182011-05-11 00:42:04 +0000738 for (int i = 0; i < kCount_PaintFlats; i++) {
739 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
740 SkASSERT(index >= 0 && index <= fFlatArray.count());
741 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000742 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
743 fCurrFlatIndex[i] = index;
744 }
745 }
746
reed@google.comacd471f2011-05-03 21:26:46 +0000747 size_t size = (char*)ptr - (char*)storage;
748 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000749 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000750 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000751 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000752// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000753 }
754 }
reed@google.combb6992a2011-04-26 17:41:56 +0000755}
756
757///////////////////////////////////////////////////////////////////////////////
758
759#include "SkGPipe.h"
760
reed@google.comacd471f2011-05-03 21:26:46 +0000761SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000762 fCanvas = NULL;
763}
764
765SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000766 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000767 SkSafeUnref(fCanvas);
768}
769
reed@google.comdde09562011-05-23 12:21:05 +0000770SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
771 uint32_t flags) {
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);
reed@google.comdde09562011-05-23 12:21:05 +0000774 fFactorySet.reset();
775 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
776 (flags & kCrossProcess_Flag) ?
777 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000778 }
779 return fCanvas;
780}
781
782void SkGPipeWriter::endRecording() {
783 if (fCanvas) {
784 fCanvas->finish();
785 fCanvas->unref();
786 fCanvas = NULL;
787 }
788}
789