blob: 1ff7d4501f508ec112afc7ddd7a62a4aa13bf054 [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);
130 virtual void drawShape(SkShape*);
131 virtual void drawVertices(VertexMode, int vertexCount,
132 const SkPoint vertices[], const SkPoint texs[],
133 const SkColor colors[], SkXfermode*,
134 const uint16_t indices[], int indexCount,
135 const SkPaint&);
136 virtual void drawData(const void*, size_t);
137
138private:
reed@google.comdde09562011-05-23 12:21:05 +0000139 SkFactorySet* fFactorySet; // optional, only used if cross-process
reed@google.comacd471f2011-05-03 21:26:46 +0000140 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000141 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000142 size_t fBlockSize; // amount allocated for writer
143 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000144 bool fDone;
145
reed@google.comf5842f72011-05-04 18:30:04 +0000146 SkRefCntSet fTypefaceSet;
147
148 uint32_t getTypefaceID(SkTypeface*);
149
reed@google.comacd471f2011-05-03 21:26:46 +0000150 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000151 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
152 }
153
reed@google.comacd471f2011-05-03 21:26:46 +0000154 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000155 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
156 }
reed@google.comacd471f2011-05-03 21:26:46 +0000157
158 bool needOpBytes(size_t size = 0);
159
160 inline void doNotify() {
161 if (!fDone) {
162 size_t bytes = fWriter.size() - fBytesNotified;
163 fController->notifyWritten(bytes);
164 fBytesNotified += bytes;
165 }
166 }
reed@google.comb55d1182011-05-11 00:42:04 +0000167
168 struct FlatData {
169 uint32_t fIndex; // always > 0
170 uint32_t fSize;
171
172 void* data() { return (char*)this + sizeof(*this); }
173
174 static int Compare(const FlatData* a, const FlatData* b) {
175 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
176 }
177 };
178 SkTDArray<FlatData*> fFlatArray;
179 int fCurrFlatIndex[kCount_PaintFlats];
180 int flattenToIndex(SkFlattenable* obj, PaintFlats);
181
reed@google.com31891582011-05-12 03:03:56 +0000182 SkPaint fPaint;
183 void writePaint(const SkPaint&);
reed@google.combb6992a2011-04-26 17:41:56 +0000184
reed@google.comacd471f2011-05-03 21:26:46 +0000185 class AutoPipeNotify {
186 public:
187 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
188 ~AutoPipeNotify() { fCanvas->doNotify(); }
189 private:
190 SkGPipeCanvas* fCanvas;
191 };
192 friend class AutoPipeNotify;
193
reed@google.combb6992a2011-04-26 17:41:56 +0000194 typedef SkCanvas INHERITED;
195};
196
reed@google.comb55d1182011-05-11 00:42:04 +0000197// return 0 for NULL (or unflattenable obj), or index-base-1
198int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
199 if (NULL == obj) {
200 return 0;
201 }
reed@google.comb55d1182011-05-11 00:42:04 +0000202
203 SkFlattenableWriteBuffer tmpWriter(1024);
reed@google.com6bac9472011-06-21 19:24:00 +0000204 tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
reed@google.comdde09562011-05-23 12:21:05 +0000205 tmpWriter.setFactoryRecorder(fFactorySet);
206
reed@google.comb55d1182011-05-11 00:42:04 +0000207 tmpWriter.writeFlattenable(obj);
208 size_t len = tmpWriter.size();
209 size_t allocSize = len + sizeof(FlatData);
210
211 SkAutoSMalloc<1024> storage(allocSize);
212 FlatData* flat = (FlatData*)storage.get();
213 flat->fSize = len;
214 tmpWriter.flatten(flat->data());
215
216 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
217 fFlatArray.count(), flat, sizeof(flat),
218 &FlatData::Compare);
219 if (index < 0) {
220 index = ~index;
221 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
222 memcpy(copy, flat, allocSize);
223 *fFlatArray.insert(index) = copy;
224 // call this after the insert, so that count() will have been grown
225 copy->fIndex = fFlatArray.count();
226// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
227
228 if (this->needOpBytes(len)) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000229 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex);
reed@google.comb55d1182011-05-11 00:42:04 +0000230 fWriter.write(copy->data(), len);
231 }
232 }
233 return fFlatArray[index]->fIndex;
234}
235
reed@google.combb6992a2011-04-26 17:41:56 +0000236///////////////////////////////////////////////////////////////////////////////
237
reed@google.comacd471f2011-05-03 21:26:46 +0000238#define MIN_BLOCK_SIZE (16 * 1024)
reed@google.combb6992a2011-04-26 17:41:56 +0000239
reed@google.comacd471f2011-05-03 21:26:46 +0000240SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
reed@google.comdde09562011-05-23 12:21:05 +0000241 SkWriter32* writer, SkFactorySet* fset)
242 : fWriter(*writer), fFactorySet(fset) {
reed@google.comacd471f2011-05-03 21:26:46 +0000243 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000244 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000245 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000246 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000247
reed@google.combb6793b2011-05-05 15:18:15 +0000248 // we need a device to limit our clip
249 // should the caller give us the bounds?
yangsu@google.com06b4da162011-06-17 15:04:40 +0000250 // We don't allocate pixels for the bitmap
reed@google.combb6793b2011-05-05 15:18:15 +0000251 SkBitmap bitmap;
252 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
yangsu@google.com06b4da162011-06-17 15:04:40 +0000253 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
reed@google.combb6793b2011-05-05 15:18:15 +0000254 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000255}
256
257SkGPipeCanvas::~SkGPipeCanvas() {
258 this->finish();
259
reed@google.comb55d1182011-05-11 00:42:04 +0000260 fFlatArray.freeAll();
reed@google.combb6992a2011-04-26 17:41:56 +0000261}
262
reed@google.comacd471f2011-05-03 21:26:46 +0000263bool SkGPipeCanvas::needOpBytes(size_t needed) {
264 if (fDone) {
265 return false;
266 }
267
268 needed += 4; // size of DrawOp atom
269 if (fWriter.size() + needed > fBlockSize) {
270 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize);
271 if (NULL == block) {
272 fDone = true;
273 return false;
274 }
275 fWriter.reset(block, fBlockSize);
276 fBytesNotified = 0;
277 }
278 return true;
279}
280
reed@google.comf5842f72011-05-04 18:30:04 +0000281uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
282 uint32_t id = 0; // 0 means default/null typeface
283 if (face) {
284 id = fTypefaceSet.find(face);
285 if (0 == id) {
286 id = fTypefaceSet.add(face);
287 size_t size = writeTypeface(NULL, face);
288 if (this->needOpBytes(size)) {
reed@google.combb6793b2011-05-05 15:18:15 +0000289 this->writeOp(kDef_Typeface_DrawOp);
reed@google.comf5842f72011-05-04 18:30:04 +0000290 writeTypeface(&fWriter, face);
291 }
292 }
293 }
294 return id;
295}
296
reed@google.combb6992a2011-04-26 17:41:56 +0000297///////////////////////////////////////////////////////////////////////////////
298
reed@google.comacd471f2011-05-03 21:26:46 +0000299#define NOTIFY_SETUP(canvas) \
300 AutoPipeNotify apn(canvas)
301
reed@google.combb6992a2011-04-26 17:41:56 +0000302int SkGPipeCanvas::save(SaveFlags flags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000303 NOTIFY_SETUP(this);
304 if (this->needOpBytes()) {
305 this->writeOp(kSave_DrawOp, 0, flags);
306 }
reed@google.combb6992a2011-04-26 17:41:56 +0000307 return this->INHERITED::save(flags);
308}
309
310int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
311 SaveFlags saveFlags) {
reed@google.comacd471f2011-05-03 21:26:46 +0000312 NOTIFY_SETUP(this);
313 size_t size = 0;
reed@google.combb6992a2011-04-26 17:41:56 +0000314 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000315
reed@google.combb6992a2011-04-26 17:41:56 +0000316 if (bounds) {
317 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000318 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000319 }
320 if (paint) {
321 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
reed@google.com31891582011-05-12 03:03:56 +0000322 this->writePaint(*paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000323 }
324
reed@google.comacd471f2011-05-03 21:26:46 +0000325 if (this->needOpBytes(size)) {
326 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
327 if (bounds) {
328 fWriter.writeRect(*bounds);
329 }
reed@google.combb6992a2011-04-26 17:41:56 +0000330 }
331
332 // we just pass on the save, so we don't create a layer
333 return this->INHERITED::save(saveFlags);
334}
335
336void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000337 NOTIFY_SETUP(this);
338 if (this->needOpBytes()) {
339 this->writeOp(kRestore_DrawOp);
340 }
reed@google.combb6992a2011-04-26 17:41:56 +0000341 this->INHERITED::restore();
342}
343
344bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
345 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000346 NOTIFY_SETUP(this);
347 if (this->needOpBytes(2 * sizeof(SkScalar))) {
348 this->writeOp(kTranslate_DrawOp);
349 fWriter.writeScalar(dx);
350 fWriter.writeScalar(dy);
351 }
reed@google.combb6992a2011-04-26 17:41:56 +0000352 }
353 return this->INHERITED::translate(dx, dy);
354}
355
356bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
357 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000358 NOTIFY_SETUP(this);
359 if (this->needOpBytes(2 * sizeof(SkScalar))) {
360 this->writeOp(kScale_DrawOp);
361 fWriter.writeScalar(sx);
362 fWriter.writeScalar(sy);
363 }
reed@google.combb6992a2011-04-26 17:41:56 +0000364 }
365 return this->INHERITED::scale(sx, sy);
366}
367
368bool SkGPipeCanvas::rotate(SkScalar degrees) {
369 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000370 NOTIFY_SETUP(this);
371 if (this->needOpBytes(sizeof(SkScalar))) {
372 this->writeOp(kRotate_DrawOp);
373 fWriter.writeScalar(degrees);
374 }
reed@google.combb6992a2011-04-26 17:41:56 +0000375 }
376 return this->INHERITED::rotate(degrees);
377}
378
379bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
380 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000381 NOTIFY_SETUP(this);
382 if (this->needOpBytes(2 * sizeof(SkScalar))) {
383 this->writeOp(kSkew_DrawOp);
384 fWriter.writeScalar(sx);
385 fWriter.writeScalar(sy);
386 }
reed@google.combb6992a2011-04-26 17:41:56 +0000387 }
388 return this->INHERITED::skew(sx, sy);
389}
390
391bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
392 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000393 NOTIFY_SETUP(this);
394 if (this->needOpBytes(matrix.flatten(NULL))) {
395 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000396 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000397 }
reed@google.combb6992a2011-04-26 17:41:56 +0000398 }
399 return this->INHERITED::concat(matrix);
400}
401
402void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000403 NOTIFY_SETUP(this);
404 if (this->needOpBytes(matrix.flatten(NULL))) {
405 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000406 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000407 }
reed@google.combb6992a2011-04-26 17:41:56 +0000408 this->INHERITED::setMatrix(matrix);
409}
410
411bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000412 NOTIFY_SETUP(this);
413 if (this->needOpBytes(sizeof(SkRect))) {
414 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
415 fWriter.writeRect(rect);
416 }
reed@google.combb6992a2011-04-26 17:41:56 +0000417 return this->INHERITED::clipRect(rect, rgnOp);
418}
419
420bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000421 NOTIFY_SETUP(this);
422 if (this->needOpBytes(estimateFlattenSize(path))) {
423 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
424 path.flatten(fWriter);
425 }
reed@google.combb6992a2011-04-26 17:41:56 +0000426 // we just pass on the bounds of the path
427 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
428}
429
430bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000431 NOTIFY_SETUP(this);
432 if (this->needOpBytes(region.flatten(NULL))) {
433 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000434 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000435 }
reed@google.combb6992a2011-04-26 17:41:56 +0000436 return this->INHERITED::clipRegion(region, rgnOp);
437}
438
439///////////////////////////////////////////////////////////////////////////////
440
441void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000442 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000443 unsigned flags = 0;
444 if (color) {
445 flags |= kClear_HasColor_DrawOpFlag;
446 }
reed@google.comacd471f2011-05-03 21:26:46 +0000447 if (this->needOpBytes(sizeof(SkColor))) {
448 this->writeOp(kDrawClear_DrawOp, flags, 0);
449 if (color) {
450 fWriter.write32(color);
451 }
reed@google.combb6992a2011-04-26 17:41:56 +0000452 }
453}
454
455void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000456 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000457 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000458 if (this->needOpBytes()) {
reed@google.com31891582011-05-12 03:03:56 +0000459 this->writeOp(kDrawPaint_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000460 }
reed@google.combb6992a2011-04-26 17:41:56 +0000461}
462
463void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
464 const SkPoint pts[], const SkPaint& paint) {
465 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000466 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000467 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000468 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000469 this->writeOp(kDrawPoints_DrawOp, mode, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000470 fWriter.write32(count);
471 fWriter.write(pts, count * sizeof(SkPoint));
472 }
reed@google.combb6992a2011-04-26 17:41:56 +0000473 }
474}
475
476void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000477 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000478 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000479 if (this->needOpBytes(sizeof(SkRect))) {
reed@google.com31891582011-05-12 03:03:56 +0000480 this->writeOp(kDrawRect_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000481 fWriter.writeRect(rect);
482 }
reed@google.combb6992a2011-04-26 17:41:56 +0000483}
484
485void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000486 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000487 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000488 if (this->needOpBytes(estimateFlattenSize(path))) {
reed@google.com31891582011-05-12 03:03:56 +0000489 this->writeOp(kDrawPath_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000490 path.flatten(fWriter);
491 }
reed@google.combb6992a2011-04-26 17:41:56 +0000492}
493
494void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
495 const SkPaint*) {
496 UNIMPLEMENTED
497}
498
499void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
500 const SkRect& dst, const SkPaint*) {
501 UNIMPLEMENTED
502}
503
504void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
505 const SkPaint*) {
506 UNIMPLEMENTED
507}
508
509void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
510 const SkPaint*) {
511 UNIMPLEMENTED
512}
513
514void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
515 SkScalar y, const SkPaint& paint) {
516 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000517 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000518 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000519 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
reed@google.com31891582011-05-12 03:03:56 +0000520 this->writeOp(kDrawText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000521 fWriter.write32(byteLength);
522 fWriter.writePad(text, byteLength);
523 fWriter.writeScalar(x);
524 fWriter.writeScalar(y);
525 }
reed@google.combb6992a2011-04-26 17:41:56 +0000526 }
527}
528
529void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
530 const SkPoint pos[], const SkPaint& paint) {
531 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000532 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000533 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000534 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000535 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
reed@google.com31891582011-05-12 03:03:56 +0000536 this->writeOp(kDrawPosText_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000537 fWriter.write32(byteLength);
538 fWriter.writePad(text, byteLength);
539 fWriter.write32(count);
540 fWriter.write(pos, count * sizeof(SkPoint));
541 }
reed@google.combb6992a2011-04-26 17:41:56 +0000542 }
543}
544
545void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
546 const SkScalar xpos[], SkScalar constY,
547 const SkPaint& paint) {
548 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000549 NOTIFY_SETUP(this);
reed@google.com31891582011-05-12 03:03:56 +0000550 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000551 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000552 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
reed@google.com31891582011-05-12 03:03:56 +0000553 this->writeOp(kDrawPosTextH_DrawOp);
reed@google.comacd471f2011-05-03 21:26:46 +0000554 fWriter.write32(byteLength);
555 fWriter.writePad(text, byteLength);
556 fWriter.write32(count);
557 fWriter.write(xpos, count * sizeof(SkScalar));
558 fWriter.writeScalar(constY);
559 }
reed@google.combb6992a2011-04-26 17:41:56 +0000560 }
561}
562
563void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
564 const SkPath& path, const SkMatrix* matrix,
565 const SkPaint& paint) {
566 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000567 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000568 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000569 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000570 if (matrix) {
571 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000572 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000573 }
reed@google.com31891582011-05-12 03:03:56 +0000574 this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000575 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000576 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0);
reed@google.combb6992a2011-04-26 17:41:56 +0000577
reed@google.comacd471f2011-05-03 21:26:46 +0000578 fWriter.write32(byteLength);
579 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000580
reed@google.comacd471f2011-05-03 21:26:46 +0000581 path.flatten(fWriter);
582 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000583 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000584 }
reed@google.combb6992a2011-04-26 17:41:56 +0000585 }
586 }
587}
588
589void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000590 // we want to playback the picture into individual draw calls
591 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000592}
593
594void SkGPipeCanvas::drawShape(SkShape* shape) {
595 UNIMPLEMENTED
596}
597
598void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
599 const SkPoint vertices[], const SkPoint texs[],
600 const SkColor colors[], SkXfermode*,
601 const uint16_t indices[], int indexCount,
602 const SkPaint& paint) {
603 if (0 == vertexCount) {
604 return;
605 }
606
reed@google.comacd471f2011-05-03 21:26:46 +0000607 NOTIFY_SETUP(this);
608 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.com31891582011-05-12 03:03:56 +0000609 this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000610 unsigned flags = 0;
611 if (texs) {
612 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000613 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000614 }
615 if (colors) {
616 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000617 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000618 }
619 if (indices && indexCount > 0) {
620 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000621 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000622 }
623
reed@google.comacd471f2011-05-03 21:26:46 +0000624 if (this->needOpBytes(size)) {
reed@google.com31891582011-05-12 03:03:56 +0000625 this->writeOp(kDrawVertices_DrawOp, flags, 0);
reed@google.comacd471f2011-05-03 21:26:46 +0000626 fWriter.write32(mode);
627 fWriter.write32(vertexCount);
628 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
629 if (texs) {
630 fWriter.write(texs, vertexCount * sizeof(SkPoint));
631 }
632 if (colors) {
633 fWriter.write(colors, vertexCount * sizeof(SkColor));
634 }
reed@google.combb6992a2011-04-26 17:41:56 +0000635
reed@google.comacd471f2011-05-03 21:26:46 +0000636 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000637
reed@google.comacd471f2011-05-03 21:26:46 +0000638 if (indices && indexCount > 0) {
639 fWriter.write32(indexCount);
640 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
641 }
reed@google.combb6992a2011-04-26 17:41:56 +0000642 }
643}
644
reed@google.comacd471f2011-05-03 21:26:46 +0000645void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
646 if (size && ptr) {
647 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000648 unsigned data = 0;
649 if (size < (1 << DRAWOPS_DATA_BITS)) {
650 data = (unsigned)size;
651 }
reed@google.comacd471f2011-05-03 21:26:46 +0000652 if (this->needOpBytes(4 + SkAlign4(size))) {
653 this->writeOp(kDrawData_DrawOp, 0, data);
654 if (0 == data) {
655 fWriter.write32(size);
656 }
reed@google.combb6793b2011-05-05 15:18:15 +0000657 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000658 }
659 }
660}
661
662///////////////////////////////////////////////////////////////////////////////
663
664template <typename T> uint32_t castToU32(T value) {
665 union {
666 T fSrc;
667 uint32_t fDst;
668 } data;
669 data.fSrc = value;
670 return data.fDst;
671}
672
reed@google.com31891582011-05-12 03:03:56 +0000673void SkGPipeCanvas::writePaint(const SkPaint& paint) {
674 SkPaint& base = fPaint;
reed@google.combb6992a2011-04-26 17:41:56 +0000675 uint32_t storage[32];
676 uint32_t* ptr = storage;
reed@google.combb6992a2011-04-26 17:41:56 +0000677
678 if (base.getFlags() != paint.getFlags()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000679 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000680 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000681 }
682 if (base.getColor() != paint.getColor()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000683 *ptr++ = PaintOp_packOp(kColor_PaintOp);
684 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000685 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000686 }
687 if (base.getStyle() != paint.getStyle()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000688 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000689 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000690 }
691 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000692 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000693 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000694 }
695 if (base.getStrokeCap() != paint.getStrokeCap()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000696 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000697 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000698 }
699 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000700 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
701 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000702 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000703 }
704 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000705 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
706 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000707 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000708 }
709 if (base.getTextEncoding() != paint.getTextEncoding()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000710 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000711 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000712 }
713 if (base.getHinting() != paint.getHinting()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000714 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000715 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000716 }
717 if (base.getTextAlign() != paint.getTextAlign()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000718 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000719 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000720 }
721 if (base.getTextSize() != paint.getTextSize()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000722 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
723 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000724 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000725 }
726 if (base.getTextScaleX() != paint.getTextScaleX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000727 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
728 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000729 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000730 }
731 if (base.getTextSkewX() != paint.getTextSkewX()) {
reed@google.combb6992a2011-04-26 17:41:56 +0000732 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp);
733 *ptr++ = castToU32(paint.getTextSkewX());
reed@google.comf5842f72011-05-04 18:30:04 +0000734 base.setTextSkewX(paint.getTextSkewX());
735 }
736
737 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
738 uint32_t id = this->getTypefaceID(paint.getTypeface());
reed@google.comf5842f72011-05-04 18:30:04 +0000739 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
740 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000741 }
reed@google.combb6992a2011-04-26 17:41:56 +0000742
reed@google.comb55d1182011-05-11 00:42:04 +0000743 for (int i = 0; i < kCount_PaintFlats; i++) {
744 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
745 SkASSERT(index >= 0 && index <= fFlatArray.count());
746 if (index != fCurrFlatIndex[i]) {
reed@google.comb55d1182011-05-11 00:42:04 +0000747 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
748 fCurrFlatIndex[i] = index;
749 }
750 }
751
reed@google.comacd471f2011-05-03 21:26:46 +0000752 size_t size = (char*)ptr - (char*)storage;
753 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000754 this->writeOp(kPaintOp_DrawOp, 0, size);
reed@google.comb55d1182011-05-11 00:42:04 +0000755 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000756 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000757// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000758 }
759 }
reed@google.combb6992a2011-04-26 17:41:56 +0000760}
761
762///////////////////////////////////////////////////////////////////////////////
763
764#include "SkGPipe.h"
765
reed@google.comacd471f2011-05-03 21:26:46 +0000766SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000767 fCanvas = NULL;
768}
769
770SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000771 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000772 SkSafeUnref(fCanvas);
773}
774
reed@google.comdde09562011-05-23 12:21:05 +0000775SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller,
776 uint32_t flags) {
reed@google.combb6992a2011-04-26 17:41:56 +0000777 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000778 fWriter.reset(NULL, 0);
reed@google.comdde09562011-05-23 12:21:05 +0000779 fFactorySet.reset();
780 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
781 (flags & kCrossProcess_Flag) ?
782 &fFactorySet : NULL));
reed@google.combb6992a2011-04-26 17:41:56 +0000783 }
784 return fCanvas;
785}
786
787void SkGPipeWriter::endRecording() {
788 if (fCanvas) {
789 fCanvas->finish();
790 fCanvas->unref();
791 fCanvas = NULL;
792 }
793}
794