blob: 18c3e60c9f6e9b03c4961c40c77b6cb6e2373507 [file] [log] [blame]
reed@google.combb6992a2011-04-26 17:41:56 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "SkCanvas.h"
reed@google.combb6793b2011-05-05 15:18:15 +000019#include "SkDevice.h"
reed@google.combb6992a2011-04-26 17:41:56 +000020#include "SkPaint.h"
reed@google.comacd471f2011-05-03 21:26:46 +000021#include "SkGPipe.h"
reed@google.combb6992a2011-04-26 17:41:56 +000022#include "SkGPipePriv.h"
reed@google.comf5842f72011-05-04 18:30:04 +000023#include "SkStream.h"
reed@google.comb55d1182011-05-11 00:42:04 +000024#include "SkTSearch.h"
reed@google.comf5842f72011-05-04 18:30:04 +000025#include "SkTypeface.h"
reed@google.combb6992a2011-04-26 17:41:56 +000026#include "SkWriter32.h"
reed@google.comb55d1182011-05-11 00:42:04 +000027#include "SkColorFilter.h"
reed@google.com0faac1e2011-05-11 05:58:58 +000028#include "SkDrawLooper.h"
reed@google.comb55d1182011-05-11 00:42:04 +000029#include "SkMaskFilter.h"
30#include "SkRasterizer.h"
31#include "SkShader.h"
32
33static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
34 SkASSERT(paintFlat < kCount_PaintFlats);
35 switch (paintFlat) {
36 case kColorFilter_PaintFlat: return paint.getColorFilter();
reed@google.com0faac1e2011-05-11 05:58:58 +000037 case kDrawLooper_PaintFlat: return paint.getLooper();
reed@google.comb55d1182011-05-11 00:42:04 +000038 case kMaskFilter_PaintFlat: return paint.getMaskFilter();
39 case kPathEffect_PaintFlat: return paint.getPathEffect();
40 case kRasterizer_PaintFlat: return paint.getRasterizer();
41 case kShader_PaintFlat: return paint.getShader();
42 case kXfermode_PaintFlat: return paint.getXfermode();
43 }
44 SkASSERT(!"never gets here");
45 return NULL;
46}
reed@google.combb6992a2011-04-26 17:41:56 +000047
reed@google.comacd471f2011-05-03 21:26:46 +000048static size_t estimateFlattenSize(const SkPath& path) {
49 int n = path.countPoints();
50 size_t bytes = 3 * sizeof(int32_t);
51 bytes += n * sizeof(SkPoint);
52 bytes += SkAlign4(n + 2); // verbs: add 2 for move/close extras
53
54#ifdef SK_DEBUG
55 {
56 SkWriter32 writer(1024);
57 path.flatten(writer);
58 SkASSERT(writer.size() <= bytes);
59 }
60#endif
61 return bytes;
62}
63
reed@google.comf5842f72011-05-04 18:30:04 +000064static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
65 SkASSERT(typeface);
66 SkDynamicMemoryWStream stream;
67 typeface->serialize(&stream);
68 size_t size = stream.getOffset();
69 if (writer) {
70 writer->write32(size);
71 writer->write(stream.getStream(), size);
72 }
73 return 4 + size;
74}
75
reed@google.combb6992a2011-04-26 17:41:56 +000076///////////////////////////////////////////////////////////////////////////////
77
78class SkGPipeCanvas : public SkCanvas {
79public:
reed@google.comdde09562011-05-23 12:21:05 +000080 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*);
reed@google.combb6992a2011-04-26 17:41:56 +000081 virtual ~SkGPipeCanvas();
82
83 void finish() {
84 if (!fDone) {
85 this->writeOp(kDone_DrawOp);
reed@google.comeb5a8152011-05-23 21:09:13 +000086 this->doNotify();
reed@google.combb6992a2011-04-26 17:41:56 +000087 fDone = true;
88 }
89 }
90
91 // overrides from SkCanvas
92 virtual int save(SaveFlags);
93 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
94 virtual void restore();
95 virtual bool translate(SkScalar dx, SkScalar dy);
96 virtual bool scale(SkScalar sx, SkScalar sy);
97 virtual bool rotate(SkScalar degrees);
98 virtual bool skew(SkScalar sx, SkScalar sy);
99 virtual bool concat(const SkMatrix& matrix);
100 virtual void setMatrix(const SkMatrix& matrix);
101 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
102 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
103 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
104 virtual void clear(SkColor);
105 virtual void drawPaint(const SkPaint& paint);
106 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
107 const SkPaint&);
108 virtual void drawRect(const SkRect& rect, const SkPaint&);
109 virtual void drawPath(const SkPath& path, const SkPaint&);
110 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
111 const SkPaint*);
112 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
113 const SkRect& dst, const SkPaint*);
114 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
115 const SkPaint*);
116 virtual void drawSprite(const SkBitmap&, int left, int top,
117 const SkPaint*);
118 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
119 SkScalar y, const SkPaint&);
120 virtual void drawPosText(const void* text, size_t byteLength,
121 const SkPoint pos[], const SkPaint&);
122 virtual void drawPosTextH(const void* text, size_t byteLength,
123 const SkScalar xpos[], SkScalar constY, const SkPaint&);
124 virtual void drawTextOnPath(const void* text, size_t byteLength,
125 const SkPath& path, const SkMatrix* matrix,
126 const SkPaint&);
127 virtual void drawPicture(SkPicture& picture);
128 virtual void drawShape(SkShape*);
129 virtual void drawVertices(VertexMode, int vertexCount,
130 const SkPoint vertices[], const SkPoint texs[],
131 const SkColor colors[], SkXfermode*,
132 const uint16_t indices[], int indexCount,
133 const SkPaint&);
134 virtual void drawData(const void*, size_t);
135
136private:
reed@google.comdde09562011-05-23 12:21:05 +0000137 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000138 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000139 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000140 size_t fBlockSize; // amount allocated for writer
141 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000142 bool fDone;
143
reed@google.comf5842f72011-05-04 18:30:04 +0000144 SkRefCntSet fTypefaceSet;
145
146 uint32_t getTypefaceID(SkTypeface*);
147
reed@google.comacd471f2011-05-03 21:26:46 +0000148 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000149 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
150 }
151
reed@google.comacd471f2011-05-03 21:26:46 +0000152 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000153 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
154 }
reed@google.comacd471f2011-05-03 21:26:46 +0000155
156 bool needOpBytes(size_t size = 0);
157
158 inline void doNotify() {
159 if (!fDone) {
160 size_t bytes = fWriter.size() - fBytesNotified;
161 fController->notifyWritten(bytes);
162 fBytesNotified += bytes;
163 }
164 }
reed@google.comb55d1182011-05-11 00:42:04 +0000165
166 struct FlatData {
167 uint32_t fIndex; // always > 0
168 uint32_t fSize;
169
170 void* data() { return (char*)this + sizeof(*this); }
171
172 static int Compare(const FlatData* a, const FlatData* b) {
173 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
174 }
175 };
176 SkTDArray<FlatData*> fFlatArray;
177 int fCurrFlatIndex[kCount_PaintFlats];
178 int flattenToIndex(SkFlattenable* obj, PaintFlats);
179
reed@google.com31891582011-05-12 03:03:56 +0000180 SkPaint fPaint;
181 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000182
reed@google.comacd471f2011-05-03 21:26:46 +0000183 class AutoPipeNotify {
184 public:
185 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
186 ~AutoPipeNotify() { fCanvas->doNotify(); }
187 private:
188 SkGPipeCanvas* fCanvas;
189 };
190 friend class AutoPipeNotify;
191
reed@google.combb6992a2011-04-26 17:41:56 +0000192 typedef SkCanvas INHERITED;
193};
194
reed@google.comb55d1182011-05-11 00:42:04 +0000195// return 0 for NULL (or unflattenable obj), or index-base-1
196int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
197 if (NULL == obj) {
198 return 0;
199 }
reed@google.comb55d1182011-05-11 00:42:04 +0000200
201 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.com6bac9472011-06-21 19:24:00 +0000202 tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
reed@google.comdde09562011-05-23 12:21:05 +0000203 tmpWriter.setFactoryRecorder(fFactorySet);
204
reed@google.comb55d1182011-05-11 00:42:04 +0000205 tmpWriter.writeFlattenable(obj);
206 size_t len = tmpWriter.size();
207 size_t allocSize = len + sizeof(FlatData);
208
209 SkAutoSMalloc<1024> storage(allocSize);
210 FlatData* flat = (FlatData*)storage.get();
211 flat->fSize = len;
212 tmpWriter.flatten(flat->data());
213
214 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
215 fFlatArray.count(), flat, sizeof(flat),
216 &FlatData::Compare);
217 if (index < 0) {
218 index = ~index;
219 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
220 memcpy(copy, flat, allocSize);
221 *fFlatArray.insert(index) = copy;
222 // call this after the insert, so that count() will have been grown
223 copy->fIndex = fFlatArray.count();
224// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
225
226 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000227 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000228 fWriter.write(copy->data(), len);
229 }
230 }
231 return fFlatArray[index]->fIndex;
232}
233
reed@google.combb6992a2011-04-26 17:41:56 +0000234///////////////////////////////////////////////////////////////////////////////
235
reed@google.comacd471f2011-05-03 21:26:46 +0000236#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000237
reed@google.comacd471f2011-05-03 21:26:46 +0000238SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000239 SkWriter32* writer, SkFactorySet* fset)
240 : fWriter(*writer), fFactorySet(fset) {
reed@google.comacd471f2011-05-03 21:26:46 +0000241 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000242 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000243 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000244 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000245
reed@google.combb6793b2011-05-05 15:18:15 +0000246 // we need a device to limit our clip
247 // should the caller give us the bounds?
yangsu@google.com06b4da162011-06-17 15:04:40 +0000248 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000249 SkBitmap bitmap;
250 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da162011-06-17 15:04:40 +0000251 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000252 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000253}
254
255SkGPipeCanvas::~SkGPipeCanvas() {
256 this->finish();
257
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 opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000313
reed@google.combb6992a2011-04-26 17:41:56 +0000314 if (bounds) {
315 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000316 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000317 }
318 if (paint) {
319 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000320 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000321 }
322
reed@google.comacd471f2011-05-03 21:26:46 +0000323 if (this->needOpBytes(size)) {
324 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
325 if (bounds) {
326 fWriter.writeRect(*bounds);
327 }
reed@google.combb6992a2011-04-26 17:41:56 +0000328 }
329
330 // we just pass on the save, so we don't create a layer
331 return this->INHERITED::save(saveFlags);
332}
333
334void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000335 NOTIFY_SETUP(this);
336 if (this->needOpBytes()) {
337 this->writeOp(kRestore_DrawOp);
338 }
reed@google.combb6992a2011-04-26 17:41:56 +0000339 this->INHERITED::restore();
340}
341
342bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
343 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000344 NOTIFY_SETUP(this);
345 if (this->needOpBytes(2 * sizeof(SkScalar))) {
346 this->writeOp(kTranslate_DrawOp);
347 fWriter.writeScalar(dx);
348 fWriter.writeScalar(dy);
349 }
reed@google.combb6992a2011-04-26 17:41:56 +0000350 }
351 return this->INHERITED::translate(dx, dy);
352}
353
354bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
355 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000356 NOTIFY_SETUP(this);
357 if (this->needOpBytes(2 * sizeof(SkScalar))) {
358 this->writeOp(kScale_DrawOp);
359 fWriter.writeScalar(sx);
360 fWriter.writeScalar(sy);
361 }
reed@google.combb6992a2011-04-26 17:41:56 +0000362 }
363 return this->INHERITED::scale(sx, sy);
364}
365
366bool SkGPipeCanvas::rotate(SkScalar degrees) {
367 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000368 NOTIFY_SETUP(this);
369 if (this->needOpBytes(sizeof(SkScalar))) {
370 this->writeOp(kRotate_DrawOp);
371 fWriter.writeScalar(degrees);
372 }
reed@google.combb6992a2011-04-26 17:41:56 +0000373 }
374 return this->INHERITED::rotate(degrees);
375}
376
377bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
378 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000379 NOTIFY_SETUP(this);
380 if (this->needOpBytes(2 * sizeof(SkScalar))) {
381 this->writeOp(kSkew_DrawOp);
382 fWriter.writeScalar(sx);
383 fWriter.writeScalar(sy);
384 }
reed@google.combb6992a2011-04-26 17:41:56 +0000385 }
386 return this->INHERITED::skew(sx, sy);
387}
388
389bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
390 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000391 NOTIFY_SETUP(this);
392 if (this->needOpBytes(matrix.flatten(NULL))) {
393 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000394 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000395 }
reed@google.combb6992a2011-04-26 17:41:56 +0000396 }
397 return this->INHERITED::concat(matrix);
398}
399
400void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000401 NOTIFY_SETUP(this);
402 if (this->needOpBytes(matrix.flatten(NULL))) {
403 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000404 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000405 }
reed@google.combb6992a2011-04-26 17:41:56 +0000406 this->INHERITED::setMatrix(matrix);
407}
408
409bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000410 NOTIFY_SETUP(this);
411 if (this->needOpBytes(sizeof(SkRect))) {
412 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
413 fWriter.writeRect(rect);
414 }
reed@google.combb6992a2011-04-26 17:41:56 +0000415 return this->INHERITED::clipRect(rect, rgnOp);
416}
417
418bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000419 NOTIFY_SETUP(this);
420 if (this->needOpBytes(estimateFlattenSize(path))) {
421 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
422 path.flatten(fWriter);
423 }
reed@google.combb6992a2011-04-26 17:41:56 +0000424 // we just pass on the bounds of the path
425 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
426}
427
428bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000429 NOTIFY_SETUP(this);
430 if (this->needOpBytes(region.flatten(NULL))) {
431 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000432 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000433 }
reed@google.combb6992a2011-04-26 17:41:56 +0000434 return this->INHERITED::clipRegion(region, rgnOp);
435}
436
437///////////////////////////////////////////////////////////////////////////////
438
439void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000440 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000441 unsigned flags = 0;
442 if (color) {
443 flags |= kClear_HasColor_DrawOpFlag;
444 }
reed@google.comacd471f2011-05-03 21:26:46 +0000445 if (this->needOpBytes(sizeof(SkColor))) {
446 this->writeOp(kDrawClear_DrawOp, flags, 0);
447 if (color) {
448 fWriter.write32(color);
449 }
reed@google.combb6992a2011-04-26 17:41:56 +0000450 }
451}
452
453void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000454 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000455 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000456 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000457 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000458 }
reed@google.combb6992a2011-04-26 17:41:56 +0000459}
460
461void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
462 const SkPoint pts[], const SkPaint& paint) {
463 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000464 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000465 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000466 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000467 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000468 fWriter.write32(count);
469 fWriter.write(pts, count * sizeof(SkPoint));
470 }
reed@google.combb6992a2011-04-26 17:41:56 +0000471 }
472}
473
474void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000475 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000476 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000477 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000478 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000479 fWriter.writeRect(rect);
480 }
reed@google.combb6992a2011-04-26 17:41:56 +0000481}
482
483void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000484 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000485 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000486 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000487 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000488 path.flatten(fWriter);
489 }
reed@google.combb6992a2011-04-26 17:41:56 +0000490}
491
492void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
493 const SkPaint*) {
494 UNIMPLEMENTED
495}
496
497void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
498 const SkRect& dst, const SkPaint*) {
499 UNIMPLEMENTED
500}
501
502void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
503 const SkPaint*) {
504 UNIMPLEMENTED
505}
506
507void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
508 const SkPaint*) {
509 UNIMPLEMENTED
510}
511
512void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
513 SkScalar y, const SkPaint& paint) {
514 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000515 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000516 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000517 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000518 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000519 fWriter.write32(byteLength);
520 fWriter.writePad(text, byteLength);
521 fWriter.writeScalar(x);
522 fWriter.writeScalar(y);
523 }
reed@google.combb6992a2011-04-26 17:41:56 +0000524 }
525}
526
527void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
528 const SkPoint pos[], const SkPaint& paint) {
529 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000530 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000531 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000532 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000533 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000534 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000535 fWriter.write32(byteLength);
536 fWriter.writePad(text, byteLength);
537 fWriter.write32(count);
538 fWriter.write(pos, count * sizeof(SkPoint));
539 }
reed@google.combb6992a2011-04-26 17:41:56 +0000540 }
541}
542
543void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
544 const SkScalar xpos[], SkScalar constY,
545 const SkPaint& paint) {
546 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000547 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000548 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000549 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000550 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000551 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000552 fWriter.write32(byteLength);
553 fWriter.writePad(text, byteLength);
554 fWriter.write32(count);
555 fWriter.write(xpos, count * sizeof(SkScalar));
556 fWriter.writeScalar(constY);
557 }
reed@google.combb6992a2011-04-26 17:41:56 +0000558 }
559}
560
561void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
562 const SkPath& path, const SkMatrix* matrix,
563 const SkPaint& paint) {
564 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000565 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000566 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000567 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000568 if (matrix) {
569 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000570 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000571 }
reed@google.com31891582011-05-12 03:03:56 +0000572 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000573 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000574 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000575
reed@google.comacd471f2011-05-03 21:26:46 +0000576 fWriter.write32(byteLength);
577 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000578
reed@google.comacd471f2011-05-03 21:26:46 +0000579 path.flatten(fWriter);
580 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000581 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000582 }
reed@google.combb6992a2011-04-26 17:41:56 +0000583 }
584 }
585}
586
587void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000588 // we want to playback the picture into individual draw calls
589 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000590}
591
592void SkGPipeCanvas::drawShape(SkShape* shape) {
593 UNIMPLEMENTED
594}
595
596void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
597 const SkPoint vertices[], const SkPoint texs[],
598 const SkColor colors[], SkXfermode*,
599 const uint16_t indices[], int indexCount,
600 const SkPaint& paint) {
601 if (0 == vertexCount) {
602 return;
603 }
604
reed@google.comacd471f2011-05-03 21:26:46 +0000605 NOTIFY_SETUP(this);
606 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000607 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000608 unsigned flags = 0;
609 if (texs) {
610 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000611 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000612 }
613 if (colors) {
614 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000615 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000616 }
617 if (indices && indexCount > 0) {
618 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000619 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000620 }
621
reed@google.comacd471f2011-05-03 21:26:46 +0000622 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000623 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000624 fWriter.write32(mode);
625 fWriter.write32(vertexCount);
626 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
627 if (texs) {
628 fWriter.write(texs, vertexCount * sizeof(SkPoint));
629 }
630 if (colors) {
631 fWriter.write(colors, vertexCount * sizeof(SkColor));
632 }
reed@google.combb6992a2011-04-26 17:41:56 +0000633
reed@google.comacd471f2011-05-03 21:26:46 +0000634 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000635
reed@google.comacd471f2011-05-03 21:26:46 +0000636 if (indices && indexCount > 0) {
637 fWriter.write32(indexCount);
638 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
639 }
reed@google.combb6992a2011-04-26 17:41:56 +0000640 }
641}
642
reed@google.comacd471f2011-05-03 21:26:46 +0000643void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
644 if (size && ptr) {
645 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000646 unsigned data = 0;
647 if (size < (1 << DRAWOPS_DATA_BITS)) {
648 data = (unsigned)size;
649 }
reed@google.comacd471f2011-05-03 21:26:46 +0000650 if (this->needOpBytes(4 + SkAlign4(size))) {
651 this->writeOp(kDrawData_DrawOp, 0, data);
652 if (0 == data) {
653 fWriter.write32(size);
654 }
reed@google.combb6793b2011-05-05 15:18:15 +0000655 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000656 }
657 }
658}
659
660///////////////////////////////////////////////////////////////////////////////
661
662template <typename T> uint32_t castToU32(T value) {
663 union {
664 T fSrc;
665 uint32_t fDst;
666 } data;
667 data.fSrc = value;
668 return data.fDst;
669}
670
reed@google.com31891582011-05-12 03:03:56 +0000671void SkGPipeCanvas::writePaint(const SkPaint& paint) {
672 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000673 uint32_t storage[32];
674 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000675
676 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000677 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000678 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000679 }
680 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000681 *ptr++ = PaintOp_packOp(kColor_PaintOp);
682 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000683 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000684 }
685 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000686 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000687 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000688 }
689 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000690 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000691 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000692 }
693 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000694 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000695 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000696 }
697 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000698 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
699 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000700 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000701 }
702 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000703 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
704 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000705 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000706 }
707 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000708 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000709 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000710 }
711 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000712 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000713 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000714 }
715 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000716 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000717 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000718 }
719 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000720 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
721 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000722 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000723 }
724 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000725 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
726 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000727 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000728 }
729 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000730 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
731 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000732 base.setTextSkewX(paint.getTextSkewX());
733 }
734
735 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
736 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000737 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
738 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000739 }
reed@google.combb6992a2011-04-26 17:41:56 +0000740
reed@google.comb55d1182011-05-11 00:42:04 +0000741 for (int i = 0; i < kCount_PaintFlats; i++) {
742 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
743 SkASSERT(index >= 0 && index <= fFlatArray.count());
744 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000745 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
746 fCurrFlatIndex[i] = index;
747 }
748 }
749
reed@google.comacd471f2011-05-03 21:26:46 +0000750 size_t size = (char*)ptr - (char*)storage;
751 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000752 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000753 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000754 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000755// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000756 }
757 }
reed@google.combb6992a2011-04-26 17:41:56 +0000758}
759
760///////////////////////////////////////////////////////////////////////////////
761
762#include "SkGPipe.h"
763
reed@google.comacd471f2011-05-03 21:26:46 +0000764SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000765 fCanvas = NULL;
766}
767
768SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000769 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000770 SkSafeUnref(fCanvas);
771}
772
reed@google.comdde09562011-05-23 12:21:05 +0000773SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
774 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000775 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000776 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000777 fFactorySet.reset();
778 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
779 (flags & kCrossProcess_Flag) ?
780 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000781 }
782 return fCanvas;
783}
784
785void SkGPipeWriter::endRecording() {
786 if (fCanvas) {
787 fCanvas->finish();
788 fCanvas->unref();
789 fCanvas = NULL;
790 }
791}
792