blob: 428f864fe93c9e8260856879bda3fb7aa9b4a46a [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 }
200
201 SkFlattenable::Factory fact = obj->getFactory();
202 if (NULL == fact) {
203 return 0;
204 }
205
reed@google.comdde09562011-05-23 12:21:05 +0000206 if (fFactorySet) {
207 uint32_t id = fFactorySet->find((void*)fact);
208 if (0 == id) {
209 const char* name = SkFlattenable::FactoryToName(fact);
210 if (NULL == name) {
211 return 0;
212 }
213 size_t len = strlen(name);
214 size_t size = SkWriter32::WriteStringSize(name, len);
215 if (!this->needOpBytes(size)) {
216 return 0;
217 }
218 unsigned id = fFactorySet->add(fact);
219 this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
220 fWriter.writeString(name, len);
221 }
222 }
223
reed@google.comb55d1182011-05-11 00:42:04 +0000224 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.comdde09562011-05-23 12:21:05 +0000225 tmpWriter.setFactoryRecorder(fFactorySet);
226
reed@google.comb55d1182011-05-11 00:42:04 +0000227 tmpWriter.writeFlattenable(obj);
228 size_t len = tmpWriter.size();
229 size_t allocSize = len + sizeof(FlatData);
230
231 SkAutoSMalloc<1024> storage(allocSize);
232 FlatData* flat = (FlatData*)storage.get();
233 flat->fSize = len;
234 tmpWriter.flatten(flat->data());
235
236 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
237 fFlatArray.count(), flat, sizeof(flat),
238 &FlatData::Compare);
239 if (index < 0) {
240 index = ~index;
241 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
242 memcpy(copy, flat, allocSize);
243 *fFlatArray.insert(index) = copy;
244 // call this after the insert, so that count() will have been grown
245 copy->fIndex = fFlatArray.count();
246// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
247
248 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000249 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000250 fWriter.write(copy->data(), len);
251 }
252 }
253 return fFlatArray[index]->fIndex;
254}
255
reed@google.combb6992a2011-04-26 17:41:56 +0000256///////////////////////////////////////////////////////////////////////////////
257
reed@google.comacd471f2011-05-03 21:26:46 +0000258#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000259
reed@google.comacd471f2011-05-03 21:26:46 +0000260SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000261 SkWriter32* writer, SkFactorySet* fset)
262 : fWriter(*writer), fFactorySet(fset) {
reed@google.comacd471f2011-05-03 21:26:46 +0000263 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000264 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000265 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000266 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000267
reed@google.combb6793b2011-05-05 15:18:15 +0000268 // we need a device to limit our clip
269 // should the caller give us the bounds?
270 SkBitmap bitmap;
271 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
272 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
273 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000274}
275
276SkGPipeCanvas::~SkGPipeCanvas() {
277 this->finish();
278
reed@google.comb55d1182011-05-11 00:42:04 +0000279 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000280}
281
reed@google.comacd471f2011-05-03 21:26:46 +0000282bool SkGPipeCanvas::needOpBytes(size_t needed) {
283 if (fDone) {
284 return false;
285 }
286
287 needed += 4; // size of DrawOp atom
288 if (fWriter.size() + needed > fBlockSize) {
289 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
290 if (NULL == block) {
291 fDone = true;
292 return false;
293 }
294 fWriter.reset(block, fBlockSize);
295 fBytesNotified = 0;
296 }
297 return true;
298}
299
reed@google.comf5842f72011-05-04 18:30:04 +0000300uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
301 uint32_t id = 0; // 0 means default/null typeface
302 if (face) {
303 id = fTypefaceSet.find(face);
304 if (0 == id) {
305 id = fTypefaceSet.add(face);
306 size_t size = writeTypeface(NULL, face);
307 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000308 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000309 writeTypeface(&fWriter, face);
310 }
311 }
312 }
313 return id;
314}
315
reed@google.combb6992a2011-04-26 17:41:56 +0000316///////////////////////////////////////////////////////////////////////////////
317
reed@google.comacd471f2011-05-03 21:26:46 +0000318#define NOTIFY_SETUP(canvas) \
319 AutoPipeNotify apn(canvas)
320
reed@google.combb6992a2011-04-26 17:41:56 +0000321int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000322 NOTIFY_SETUP(this);
323 if (this->needOpBytes()) {
324 this->writeOp(kSave_DrawOp, 0, flags);
325 }
reed@google.combb6992a2011-04-26 17:41:56 +0000326 return this->INHERITED::save(flags);
327}
328
329int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
330 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000331 NOTIFY_SETUP(this);
332 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000333 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000334
reed@google.combb6992a2011-04-26 17:41:56 +0000335 if (bounds) {
336 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000337 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000338 }
339 if (paint) {
340 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000341 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000342 }
343
reed@google.comacd471f2011-05-03 21:26:46 +0000344 if (this->needOpBytes(size)) {
345 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
346 if (bounds) {
347 fWriter.writeRect(*bounds);
348 }
reed@google.combb6992a2011-04-26 17:41:56 +0000349 }
350
351 // we just pass on the save, so we don't create a layer
352 return this->INHERITED::save(saveFlags);
353}
354
355void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000356 NOTIFY_SETUP(this);
357 if (this->needOpBytes()) {
358 this->writeOp(kRestore_DrawOp);
359 }
reed@google.combb6992a2011-04-26 17:41:56 +0000360 this->INHERITED::restore();
361}
362
363bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
364 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000365 NOTIFY_SETUP(this);
366 if (this->needOpBytes(2 * sizeof(SkScalar))) {
367 this->writeOp(kTranslate_DrawOp);
368 fWriter.writeScalar(dx);
369 fWriter.writeScalar(dy);
370 }
reed@google.combb6992a2011-04-26 17:41:56 +0000371 }
372 return this->INHERITED::translate(dx, dy);
373}
374
375bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
376 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000377 NOTIFY_SETUP(this);
378 if (this->needOpBytes(2 * sizeof(SkScalar))) {
379 this->writeOp(kScale_DrawOp);
380 fWriter.writeScalar(sx);
381 fWriter.writeScalar(sy);
382 }
reed@google.combb6992a2011-04-26 17:41:56 +0000383 }
384 return this->INHERITED::scale(sx, sy);
385}
386
387bool SkGPipeCanvas::rotate(SkScalar degrees) {
388 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000389 NOTIFY_SETUP(this);
390 if (this->needOpBytes(sizeof(SkScalar))) {
391 this->writeOp(kRotate_DrawOp);
392 fWriter.writeScalar(degrees);
393 }
reed@google.combb6992a2011-04-26 17:41:56 +0000394 }
395 return this->INHERITED::rotate(degrees);
396}
397
398bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
399 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000400 NOTIFY_SETUP(this);
401 if (this->needOpBytes(2 * sizeof(SkScalar))) {
402 this->writeOp(kSkew_DrawOp);
403 fWriter.writeScalar(sx);
404 fWriter.writeScalar(sy);
405 }
reed@google.combb6992a2011-04-26 17:41:56 +0000406 }
407 return this->INHERITED::skew(sx, sy);
408}
409
410bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
411 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000412 NOTIFY_SETUP(this);
413 if (this->needOpBytes(matrix.flatten(NULL))) {
414 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000415 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000416 }
reed@google.combb6992a2011-04-26 17:41:56 +0000417 }
418 return this->INHERITED::concat(matrix);
419}
420
421void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000422 NOTIFY_SETUP(this);
423 if (this->needOpBytes(matrix.flatten(NULL))) {
424 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000425 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000426 }
reed@google.combb6992a2011-04-26 17:41:56 +0000427 this->INHERITED::setMatrix(matrix);
428}
429
430bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000431 NOTIFY_SETUP(this);
432 if (this->needOpBytes(sizeof(SkRect))) {
433 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
434 fWriter.writeRect(rect);
435 }
reed@google.combb6992a2011-04-26 17:41:56 +0000436 return this->INHERITED::clipRect(rect, rgnOp);
437}
438
439bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000440 NOTIFY_SETUP(this);
441 if (this->needOpBytes(estimateFlattenSize(path))) {
442 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
443 path.flatten(fWriter);
444 }
reed@google.combb6992a2011-04-26 17:41:56 +0000445 // we just pass on the bounds of the path
446 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
447}
448
449bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000450 NOTIFY_SETUP(this);
451 if (this->needOpBytes(region.flatten(NULL))) {
452 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000453 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000454 }
reed@google.combb6992a2011-04-26 17:41:56 +0000455 return this->INHERITED::clipRegion(region, rgnOp);
456}
457
458///////////////////////////////////////////////////////////////////////////////
459
460void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000461 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000462 unsigned flags = 0;
463 if (color) {
464 flags |= kClear_HasColor_DrawOpFlag;
465 }
reed@google.comacd471f2011-05-03 21:26:46 +0000466 if (this->needOpBytes(sizeof(SkColor))) {
467 this->writeOp(kDrawClear_DrawOp, flags, 0);
468 if (color) {
469 fWriter.write32(color);
470 }
reed@google.combb6992a2011-04-26 17:41:56 +0000471 }
472}
473
474void SkGPipeCanvas::drawPaint(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()) {
reed@google.com31891582011-05-12 03:03:56 +0000478 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000479 }
reed@google.combb6992a2011-04-26 17:41:56 +0000480}
481
482void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
483 const SkPoint pts[], const SkPaint& paint) {
484 if (count) {
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(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000488 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000489 fWriter.write32(count);
490 fWriter.write(pts, count * sizeof(SkPoint));
491 }
reed@google.combb6992a2011-04-26 17:41:56 +0000492 }
493}
494
495void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000496 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000497 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000498 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000499 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000500 fWriter.writeRect(rect);
501 }
reed@google.combb6992a2011-04-26 17:41:56 +0000502}
503
504void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000505 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000506 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000507 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000508 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000509 path.flatten(fWriter);
510 }
reed@google.combb6992a2011-04-26 17:41:56 +0000511}
512
513void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
514 const SkPaint*) {
515 UNIMPLEMENTED
516}
517
518void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
519 const SkRect& dst, const SkPaint*) {
520 UNIMPLEMENTED
521}
522
523void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
524 const SkPaint*) {
525 UNIMPLEMENTED
526}
527
528void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
529 const SkPaint*) {
530 UNIMPLEMENTED
531}
532
533void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
534 SkScalar y, const SkPaint& paint) {
535 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000536 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000537 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000538 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000539 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000540 fWriter.write32(byteLength);
541 fWriter.writePad(text, byteLength);
542 fWriter.writeScalar(x);
543 fWriter.writeScalar(y);
544 }
reed@google.combb6992a2011-04-26 17:41:56 +0000545 }
546}
547
548void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
549 const SkPoint pos[], const SkPaint& paint) {
550 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000551 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000552 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000553 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000554 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000555 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000556 fWriter.write32(byteLength);
557 fWriter.writePad(text, byteLength);
558 fWriter.write32(count);
559 fWriter.write(pos, count * sizeof(SkPoint));
560 }
reed@google.combb6992a2011-04-26 17:41:56 +0000561 }
562}
563
564void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
565 const SkScalar xpos[], SkScalar constY,
566 const SkPaint& paint) {
567 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000568 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000569 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000570 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000571 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000572 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000573 fWriter.write32(byteLength);
574 fWriter.writePad(text, byteLength);
575 fWriter.write32(count);
576 fWriter.write(xpos, count * sizeof(SkScalar));
577 fWriter.writeScalar(constY);
578 }
reed@google.combb6992a2011-04-26 17:41:56 +0000579 }
580}
581
582void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
583 const SkPath& path, const SkMatrix* matrix,
584 const SkPaint& paint) {
585 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000586 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000587 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000588 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000589 if (matrix) {
590 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000591 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000592 }
reed@google.com31891582011-05-12 03:03:56 +0000593 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000594 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000595 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000596
reed@google.comacd471f2011-05-03 21:26:46 +0000597 fWriter.write32(byteLength);
598 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000599
reed@google.comacd471f2011-05-03 21:26:46 +0000600 path.flatten(fWriter);
601 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000602 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000603 }
reed@google.combb6992a2011-04-26 17:41:56 +0000604 }
605 }
606}
607
608void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000609 // we want to playback the picture into individual draw calls
610 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000611}
612
613void SkGPipeCanvas::drawShape(SkShape* shape) {
614 UNIMPLEMENTED
615}
616
617void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
618 const SkPoint vertices[], const SkPoint texs[],
619 const SkColor colors[], SkXfermode*,
620 const uint16_t indices[], int indexCount,
621 const SkPaint& paint) {
622 if (0 == vertexCount) {
623 return;
624 }
625
reed@google.comacd471f2011-05-03 21:26:46 +0000626 NOTIFY_SETUP(this);
627 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000628 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000629 unsigned flags = 0;
630 if (texs) {
631 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000632 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000633 }
634 if (colors) {
635 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000636 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000637 }
638 if (indices && indexCount > 0) {
639 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000640 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000641 }
642
reed@google.comacd471f2011-05-03 21:26:46 +0000643 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000644 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000645 fWriter.write32(mode);
646 fWriter.write32(vertexCount);
647 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
648 if (texs) {
649 fWriter.write(texs, vertexCount * sizeof(SkPoint));
650 }
651 if (colors) {
652 fWriter.write(colors, vertexCount * sizeof(SkColor));
653 }
reed@google.combb6992a2011-04-26 17:41:56 +0000654
reed@google.comacd471f2011-05-03 21:26:46 +0000655 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000656
reed@google.comacd471f2011-05-03 21:26:46 +0000657 if (indices && indexCount > 0) {
658 fWriter.write32(indexCount);
659 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
660 }
reed@google.combb6992a2011-04-26 17:41:56 +0000661 }
662}
663
reed@google.comacd471f2011-05-03 21:26:46 +0000664void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
665 if (size && ptr) {
666 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000667 unsigned data = 0;
668 if (size < (1 << DRAWOPS_DATA_BITS)) {
669 data = (unsigned)size;
670 }
reed@google.comacd471f2011-05-03 21:26:46 +0000671 if (this->needOpBytes(4 + SkAlign4(size))) {
672 this->writeOp(kDrawData_DrawOp, 0, data);
673 if (0 == data) {
674 fWriter.write32(size);
675 }
reed@google.combb6793b2011-05-05 15:18:15 +0000676 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000677 }
678 }
679}
680
681///////////////////////////////////////////////////////////////////////////////
682
683template <typename T> uint32_t castToU32(T value) {
684 union {
685 T fSrc;
686 uint32_t fDst;
687 } data;
688 data.fSrc = value;
689 return data.fDst;
690}
691
reed@google.com31891582011-05-12 03:03:56 +0000692void SkGPipeCanvas::writePaint(const SkPaint& paint) {
693 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000694 uint32_t storage[32];
695 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000696
697 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000698 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000699 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000700 }
701 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000702 *ptr++ = PaintOp_packOp(kColor_PaintOp);
703 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000704 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000705 }
706 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000707 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000708 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000709 }
710 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000711 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000712 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000713 }
714 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000715 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000716 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000717 }
718 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000719 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
720 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000721 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000722 }
723 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000724 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
725 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000726 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000727 }
728 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000729 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000730 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000731 }
732 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000733 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000734 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000735 }
736 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000737 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000738 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000739 }
740 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000741 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
742 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000743 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000744 }
745 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000746 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
747 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000748 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000749 }
750 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000751 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
752 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000753 base.setTextSkewX(paint.getTextSkewX());
754 }
755
756 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
757 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000758 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
759 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000760 }
reed@google.combb6992a2011-04-26 17:41:56 +0000761
reed@google.comb55d1182011-05-11 00:42:04 +0000762 for (int i = 0; i < kCount_PaintFlats; i++) {
763 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
764 SkASSERT(index >= 0 && index <= fFlatArray.count());
765 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000766 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
767 fCurrFlatIndex[i] = index;
768 }
769 }
770
reed@google.comacd471f2011-05-03 21:26:46 +0000771 size_t size = (char*)ptr - (char*)storage;
772 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000773 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000774 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000775 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000776// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000777 }
778 }
reed@google.combb6992a2011-04-26 17:41:56 +0000779}
780
781///////////////////////////////////////////////////////////////////////////////
782
783#include "SkGPipe.h"
784
reed@google.comacd471f2011-05-03 21:26:46 +0000785SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000786 fCanvas = NULL;
787}
788
789SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000790 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000791 SkSafeUnref(fCanvas);
792}
793
reed@google.comdde09562011-05-23 12:21:05 +0000794SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
795 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000796 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000797 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000798 fFactorySet.reset();
799 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
800 (flags & kCrossProcess_Flag) ?
801 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000802 }
803 return fCanvas;
804}
805
806void SkGPipeWriter::endRecording() {
807 if (fCanvas) {
808 fCanvas->finish();
809 fCanvas->unref();
810 fCanvas = NULL;
811 }
812}
813