blob: 0a56be6d44bb4a9b95c51bd74cccc5cfe35a626c [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.comacd471f2011-05-03 21:26:46 +000080 SkGPipeCanvas(SkGPipeController*, SkWriter32*);
reed@google.combb6992a2011-04-26 17:41:56 +000081 virtual ~SkGPipeCanvas();
82
83 void finish() {
84 if (!fDone) {
85 this->writeOp(kDone_DrawOp);
86 fDone = true;
87 }
88 }
89
90 // overrides from SkCanvas
91 virtual int save(SaveFlags);
92 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
93 virtual void restore();
94 virtual bool translate(SkScalar dx, SkScalar dy);
95 virtual bool scale(SkScalar sx, SkScalar sy);
96 virtual bool rotate(SkScalar degrees);
97 virtual bool skew(SkScalar sx, SkScalar sy);
98 virtual bool concat(const SkMatrix& matrix);
99 virtual void setMatrix(const SkMatrix& matrix);
100 virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
101 virtual bool clipPath(const SkPath& path, SkRegion::Op op);
102 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
103 virtual void clear(SkColor);
104 virtual void drawPaint(const SkPaint& paint);
105 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
106 const SkPaint&);
107 virtual void drawRect(const SkRect& rect, const SkPaint&);
108 virtual void drawPath(const SkPath& path, const SkPaint&);
109 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
110 const SkPaint*);
111 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
112 const SkRect& dst, const SkPaint*);
113 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
114 const SkPaint*);
115 virtual void drawSprite(const SkBitmap&, int left, int top,
116 const SkPaint*);
117 virtual void drawText(const void* text, size_t byteLength, SkScalar x,
118 SkScalar y, const SkPaint&);
119 virtual void drawPosText(const void* text, size_t byteLength,
120 const SkPoint pos[], const SkPaint&);
121 virtual void drawPosTextH(const void* text, size_t byteLength,
122 const SkScalar xpos[], SkScalar constY, const SkPaint&);
123 virtual void drawTextOnPath(const void* text, size_t byteLength,
124 const SkPath& path, const SkMatrix* matrix,
125 const SkPaint&);
126 virtual void drawPicture(SkPicture& picture);
127 virtual void drawShape(SkShape*);
128 virtual void drawVertices(VertexMode, int vertexCount,
129 const SkPoint vertices[], const SkPoint texs[],
130 const SkColor colors[], SkXfermode*,
131 const uint16_t indices[], int indexCount,
132 const SkPaint&);
133 virtual void drawData(const void*, size_t);
134
135private:
reed@google.comacd471f2011-05-03 21:26:46 +0000136 SkGPipeController* fController;
reed@google.combb6992a2011-04-26 17:41:56 +0000137 SkWriter32& fWriter;
reed@google.comacd471f2011-05-03 21:26:46 +0000138 size_t fBlockSize; // amount allocated for writer
139 size_t fBytesNotified;
reed@google.combb6992a2011-04-26 17:41:56 +0000140 bool fDone;
141
reed@google.comf5842f72011-05-04 18:30:04 +0000142 SkRefCntSet fTypefaceSet;
143
144 uint32_t getTypefaceID(SkTypeface*);
145
reed@google.comacd471f2011-05-03 21:26:46 +0000146 inline void writeOp(DrawOps op, unsigned flags, unsigned data) {
reed@google.combb6992a2011-04-26 17:41:56 +0000147 fWriter.write32(DrawOp_packOpFlagData(op, flags, data));
148 }
149
reed@google.comacd471f2011-05-03 21:26:46 +0000150 inline void writeOp(DrawOps op) {
reed@google.combb6992a2011-04-26 17:41:56 +0000151 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0));
152 }
reed@google.comacd471f2011-05-03 21:26:46 +0000153
154 bool needOpBytes(size_t size = 0);
155
156 inline void doNotify() {
157 if (!fDone) {
158 size_t bytes = fWriter.size() - fBytesNotified;
159 fController->notifyWritten(bytes);
160 fBytesNotified += bytes;
161 }
162 }
reed@google.comb55d1182011-05-11 00:42:04 +0000163
164 struct FlatData {
165 uint32_t fIndex; // always > 0
166 uint32_t fSize;
167
168 void* data() { return (char*)this + sizeof(*this); }
169
170 static int Compare(const FlatData* a, const FlatData* b) {
171 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
172 }
173 };
174 SkTDArray<FlatData*> fFlatArray;
175 int fCurrFlatIndex[kCount_PaintFlats];
176 int flattenToIndex(SkFlattenable* obj, PaintFlats);
177
reed@google.combb6992a2011-04-26 17:41:56 +0000178 SkTDArray<SkPaint*> fPaints;
179 unsigned writePaint(const SkPaint&);
180
reed@google.comacd471f2011-05-03 21:26:46 +0000181 class AutoPipeNotify {
182 public:
183 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {}
184 ~AutoPipeNotify() { fCanvas->doNotify(); }
185 private:
186 SkGPipeCanvas* fCanvas;
187 };
188 friend class AutoPipeNotify;
189
reed@google.combb6992a2011-04-26 17:41:56 +0000190 typedef SkCanvas INHERITED;
191};
192
reed@google.comb55d1182011-05-11 00:42:04 +0000193// return 0 for NULL (or unflattenable obj), or index-base-1
194int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
195 if (NULL == obj) {
196 return 0;
197 }
198
199 SkFlattenable::Factory fact = obj->getFactory();
200 if (NULL == fact) {
201 return 0;
202 }
203
204 SkFlattenableWriteBuffer tmpWriter(1024);
205 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,
239 SkWriter32* writer) : fWriter(*writer) {
240 fController = controller;
reed@google.combb6992a2011-04-26 17:41:56 +0000241 fDone = false;
reed@google.comacd471f2011-05-03 21:26:46 +0000242 fBlockSize = 0; // need first block from controller
reed@google.comb55d1182011-05-11 00:42:04 +0000243 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
reed@google.comacd471f2011-05-03 21:26:46 +0000244
reed@google.combb6992a2011-04-26 17:41:56 +0000245 // always begin with 1 default paint
246 *fPaints.append() = SkNEW(SkPaint);
reed@google.combb6793b2011-05-05 15:18:15 +0000247
248 // we need a device to limit our clip
249 // should the caller give us the bounds?
250 SkBitmap bitmap;
251 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
252 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
253 this->setDevice(device)->unref();
reed@google.combb6992a2011-04-26 17:41:56 +0000254}
255
256SkGPipeCanvas::~SkGPipeCanvas() {
257 this->finish();
258
259 fPaints.deleteAll();
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 index = 0; // just to avoid the warning
315 unsigned opFlags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000316
reed@google.combb6992a2011-04-26 17:41:56 +0000317 if (bounds) {
318 opFlags |= kSaveLayer_HasBounds_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000319 size += sizeof(SkRect);
reed@google.combb6992a2011-04-26 17:41:56 +0000320 }
321 if (paint) {
322 opFlags |= kSaveLayer_HasPaint_DrawOpFlag;
323 index = this->writePaint(*paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000324 size += 4;
reed@google.combb6992a2011-04-26 17:41:56 +0000325 }
326
reed@google.comacd471f2011-05-03 21:26:46 +0000327 if (this->needOpBytes(size)) {
328 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags);
329 if (bounds) {
330 fWriter.writeRect(*bounds);
331 }
332 if (paint) {
333 fWriter.write32(index);
334 }
reed@google.combb6992a2011-04-26 17:41:56 +0000335 }
336
337 // we just pass on the save, so we don't create a layer
338 return this->INHERITED::save(saveFlags);
339}
340
341void SkGPipeCanvas::restore() {
reed@google.comacd471f2011-05-03 21:26:46 +0000342 NOTIFY_SETUP(this);
343 if (this->needOpBytes()) {
344 this->writeOp(kRestore_DrawOp);
345 }
reed@google.combb6992a2011-04-26 17:41:56 +0000346 this->INHERITED::restore();
347}
348
349bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) {
350 if (dx || dy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000351 NOTIFY_SETUP(this);
352 if (this->needOpBytes(2 * sizeof(SkScalar))) {
353 this->writeOp(kTranslate_DrawOp);
354 fWriter.writeScalar(dx);
355 fWriter.writeScalar(dy);
356 }
reed@google.combb6992a2011-04-26 17:41:56 +0000357 }
358 return this->INHERITED::translate(dx, dy);
359}
360
361bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) {
362 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000363 NOTIFY_SETUP(this);
364 if (this->needOpBytes(2 * sizeof(SkScalar))) {
365 this->writeOp(kScale_DrawOp);
366 fWriter.writeScalar(sx);
367 fWriter.writeScalar(sy);
368 }
reed@google.combb6992a2011-04-26 17:41:56 +0000369 }
370 return this->INHERITED::scale(sx, sy);
371}
372
373bool SkGPipeCanvas::rotate(SkScalar degrees) {
374 if (degrees) {
reed@google.comacd471f2011-05-03 21:26:46 +0000375 NOTIFY_SETUP(this);
376 if (this->needOpBytes(sizeof(SkScalar))) {
377 this->writeOp(kRotate_DrawOp);
378 fWriter.writeScalar(degrees);
379 }
reed@google.combb6992a2011-04-26 17:41:56 +0000380 }
381 return this->INHERITED::rotate(degrees);
382}
383
384bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) {
385 if (sx || sy) {
reed@google.comacd471f2011-05-03 21:26:46 +0000386 NOTIFY_SETUP(this);
387 if (this->needOpBytes(2 * sizeof(SkScalar))) {
388 this->writeOp(kSkew_DrawOp);
389 fWriter.writeScalar(sx);
390 fWriter.writeScalar(sy);
391 }
reed@google.combb6992a2011-04-26 17:41:56 +0000392 }
393 return this->INHERITED::skew(sx, sy);
394}
395
396bool SkGPipeCanvas::concat(const SkMatrix& matrix) {
397 if (!matrix.isIdentity()) {
reed@google.comacd471f2011-05-03 21:26:46 +0000398 NOTIFY_SETUP(this);
399 if (this->needOpBytes(matrix.flatten(NULL))) {
400 this->writeOp(kConcat_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000401 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000402 }
reed@google.combb6992a2011-04-26 17:41:56 +0000403 }
404 return this->INHERITED::concat(matrix);
405}
406
407void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) {
reed@google.comacd471f2011-05-03 21:26:46 +0000408 NOTIFY_SETUP(this);
409 if (this->needOpBytes(matrix.flatten(NULL))) {
410 this->writeOp(kSetMatrix_DrawOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000411 SkWriteMatrix(&fWriter, matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000412 }
reed@google.combb6992a2011-04-26 17:41:56 +0000413 this->INHERITED::setMatrix(matrix);
414}
415
416bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000417 NOTIFY_SETUP(this);
418 if (this->needOpBytes(sizeof(SkRect))) {
419 this->writeOp(kClipRect_DrawOp, 0, rgnOp);
420 fWriter.writeRect(rect);
421 }
reed@google.combb6992a2011-04-26 17:41:56 +0000422 return this->INHERITED::clipRect(rect, rgnOp);
423}
424
425bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000426 NOTIFY_SETUP(this);
427 if (this->needOpBytes(estimateFlattenSize(path))) {
428 this->writeOp(kClipPath_DrawOp, 0, rgnOp);
429 path.flatten(fWriter);
430 }
reed@google.combb6992a2011-04-26 17:41:56 +0000431 // we just pass on the bounds of the path
432 return this->INHERITED::clipRect(path.getBounds(), rgnOp);
433}
434
435bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) {
reed@google.comacd471f2011-05-03 21:26:46 +0000436 NOTIFY_SETUP(this);
437 if (this->needOpBytes(region.flatten(NULL))) {
438 this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
reed@google.comb55d1182011-05-11 00:42:04 +0000439 SkWriteRegion(&fWriter, region);
reed@google.comacd471f2011-05-03 21:26:46 +0000440 }
reed@google.combb6992a2011-04-26 17:41:56 +0000441 return this->INHERITED::clipRegion(region, rgnOp);
442}
443
444///////////////////////////////////////////////////////////////////////////////
445
446void SkGPipeCanvas::clear(SkColor color) {
reed@google.comacd471f2011-05-03 21:26:46 +0000447 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000448 unsigned flags = 0;
449 if (color) {
450 flags |= kClear_HasColor_DrawOpFlag;
451 }
reed@google.comacd471f2011-05-03 21:26:46 +0000452 if (this->needOpBytes(sizeof(SkColor))) {
453 this->writeOp(kDrawClear_DrawOp, flags, 0);
454 if (color) {
455 fWriter.write32(color);
456 }
reed@google.combb6992a2011-04-26 17:41:56 +0000457 }
458}
459
460void SkGPipeCanvas::drawPaint(const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000461 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000462 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000463 if (this->needOpBytes()) {
464 this->writeOp(kDrawPaint_DrawOp, 0, paintIndex);
465 }
reed@google.combb6992a2011-04-26 17:41:56 +0000466}
467
468void SkGPipeCanvas::drawPoints(PointMode mode, size_t count,
469 const SkPoint pts[], const SkPaint& paint) {
470 if (count) {
reed@google.comacd471f2011-05-03 21:26:46 +0000471 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000472 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000473 if (this->needOpBytes(4 + count * sizeof(SkPoint))) {
474 this->writeOp(kDrawPoints_DrawOp, mode, paintIndex);
475 fWriter.write32(count);
476 fWriter.write(pts, count * sizeof(SkPoint));
477 }
reed@google.combb6992a2011-04-26 17:41:56 +0000478 }
479}
480
481void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000482 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000483 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000484 if (this->needOpBytes(sizeof(SkRect))) {
485 this->writeOp(kDrawRect_DrawOp, 0, paintIndex);
486 fWriter.writeRect(rect);
487 }
reed@google.combb6992a2011-04-26 17:41:56 +0000488}
489
490void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
reed@google.comacd471f2011-05-03 21:26:46 +0000491 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000492 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000493 if (this->needOpBytes(estimateFlattenSize(path))) {
494 this->writeOp(kDrawPath_DrawOp, 0, paintIndex);
495 path.flatten(fWriter);
496 }
reed@google.combb6992a2011-04-26 17:41:56 +0000497}
498
499void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
500 const SkPaint*) {
501 UNIMPLEMENTED
502}
503
504void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src,
505 const SkRect& dst, const SkPaint*) {
506 UNIMPLEMENTED
507}
508
509void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
510 const SkPaint*) {
511 UNIMPLEMENTED
512}
513
514void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top,
515 const SkPaint*) {
516 UNIMPLEMENTED
517}
518
519void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
520 SkScalar y, const SkPaint& paint) {
521 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000522 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000523 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000524 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) {
525 this->writeOp(kDrawText_DrawOp, 0, paintIndex);
526 fWriter.write32(byteLength);
527 fWriter.writePad(text, byteLength);
528 fWriter.writeScalar(x);
529 fWriter.writeScalar(y);
530 }
reed@google.combb6992a2011-04-26 17:41:56 +0000531 }
532}
533
534void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength,
535 const SkPoint pos[], const SkPaint& paint) {
536 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000537 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000538 unsigned paintIndex = this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000539 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000540 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) {
541 this->writeOp(kDrawPosText_DrawOp, 0, paintIndex);
542 fWriter.write32(byteLength);
543 fWriter.writePad(text, byteLength);
544 fWriter.write32(count);
545 fWriter.write(pos, count * sizeof(SkPoint));
546 }
reed@google.combb6992a2011-04-26 17:41:56 +0000547 }
548}
549
550void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength,
551 const SkScalar xpos[], SkScalar constY,
552 const SkPaint& paint) {
553 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000554 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000555 unsigned paintIndex = this->writePaint(paint);
reed@google.combb6992a2011-04-26 17:41:56 +0000556 int count = paint.textToGlyphs(text, byteLength, NULL);
reed@google.comacd471f2011-05-03 21:26:46 +0000557 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) {
558 this->writeOp(kDrawPosTextH_DrawOp, 0, paintIndex);
559 fWriter.write32(byteLength);
560 fWriter.writePad(text, byteLength);
561 fWriter.write32(count);
562 fWriter.write(xpos, count * sizeof(SkScalar));
563 fWriter.writeScalar(constY);
564 }
reed@google.combb6992a2011-04-26 17:41:56 +0000565 }
566}
567
568void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength,
569 const SkPath& path, const SkMatrix* matrix,
570 const SkPaint& paint) {
571 if (byteLength) {
reed@google.comacd471f2011-05-03 21:26:46 +0000572 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000573 unsigned flags = 0;
reed@google.comacd471f2011-05-03 21:26:46 +0000574 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path);
reed@google.combb6992a2011-04-26 17:41:56 +0000575 if (matrix) {
576 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000577 size += matrix->flatten(NULL);
reed@google.combb6992a2011-04-26 17:41:56 +0000578 }
579 unsigned paintIndex = this->writePaint(paint);
reed@google.comacd471f2011-05-03 21:26:46 +0000580 if (this->needOpBytes(size)) {
581 this->writeOp(kDrawTextOnPath_DrawOp, flags, paintIndex);
reed@google.combb6992a2011-04-26 17:41:56 +0000582
reed@google.comacd471f2011-05-03 21:26:46 +0000583 fWriter.write32(byteLength);
584 fWriter.writePad(text, byteLength);
reed@google.combb6992a2011-04-26 17:41:56 +0000585
reed@google.comacd471f2011-05-03 21:26:46 +0000586 path.flatten(fWriter);
587 if (matrix) {
reed@google.comb55d1182011-05-11 00:42:04 +0000588 SkWriteMatrix(&fWriter, *matrix);
reed@google.comacd471f2011-05-03 21:26:46 +0000589 }
reed@google.combb6992a2011-04-26 17:41:56 +0000590 }
591 }
592}
593
594void SkGPipeCanvas::drawPicture(SkPicture& picture) {
reed@google.com0faac1e2011-05-11 05:58:58 +0000595 // we want to playback the picture into individual draw calls
596 this->INHERITED::drawPicture(picture);
reed@google.combb6992a2011-04-26 17:41:56 +0000597}
598
599void SkGPipeCanvas::drawShape(SkShape* shape) {
600 UNIMPLEMENTED
601}
602
603void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
604 const SkPoint vertices[], const SkPoint texs[],
605 const SkColor colors[], SkXfermode*,
606 const uint16_t indices[], int indexCount,
607 const SkPaint& paint) {
608 if (0 == vertexCount) {
609 return;
610 }
611
reed@google.comacd471f2011-05-03 21:26:46 +0000612 NOTIFY_SETUP(this);
613 size_t size = 4 + vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000614 unsigned paintIndex = this->writePaint(paint);
615 unsigned flags = 0;
616 if (texs) {
617 flags |= kDrawVertices_HasTexs_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000618 size += vertexCount * sizeof(SkPoint);
reed@google.combb6992a2011-04-26 17:41:56 +0000619 }
620 if (colors) {
621 flags |= kDrawVertices_HasColors_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000622 size += vertexCount * sizeof(SkColor);
reed@google.combb6992a2011-04-26 17:41:56 +0000623 }
624 if (indices && indexCount > 0) {
625 flags |= kDrawVertices_HasIndices_DrawOpFlag;
reed@google.comacd471f2011-05-03 21:26:46 +0000626 size += 4 + SkAlign4(indexCount * sizeof(uint16_t));
reed@google.combb6992a2011-04-26 17:41:56 +0000627 }
628
reed@google.comacd471f2011-05-03 21:26:46 +0000629 if (this->needOpBytes(size)) {
630 this->writeOp(kDrawVertices_DrawOp, flags, paintIndex);
631 fWriter.write32(mode);
632 fWriter.write32(vertexCount);
633 fWriter.write(vertices, vertexCount * sizeof(SkPoint));
634 if (texs) {
635 fWriter.write(texs, vertexCount * sizeof(SkPoint));
636 }
637 if (colors) {
638 fWriter.write(colors, vertexCount * sizeof(SkColor));
639 }
reed@google.combb6992a2011-04-26 17:41:56 +0000640
reed@google.comacd471f2011-05-03 21:26:46 +0000641 // TODO: flatten xfermode
reed@google.combb6992a2011-04-26 17:41:56 +0000642
reed@google.comacd471f2011-05-03 21:26:46 +0000643 if (indices && indexCount > 0) {
644 fWriter.write32(indexCount);
645 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
646 }
reed@google.combb6992a2011-04-26 17:41:56 +0000647 }
648}
649
reed@google.comacd471f2011-05-03 21:26:46 +0000650void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
651 if (size && ptr) {
652 NOTIFY_SETUP(this);
reed@google.combb6992a2011-04-26 17:41:56 +0000653 unsigned data = 0;
654 if (size < (1 << DRAWOPS_DATA_BITS)) {
655 data = (unsigned)size;
656 }
reed@google.comacd471f2011-05-03 21:26:46 +0000657 if (this->needOpBytes(4 + SkAlign4(size))) {
658 this->writeOp(kDrawData_DrawOp, 0, data);
659 if (0 == data) {
660 fWriter.write32(size);
661 }
reed@google.combb6793b2011-05-05 15:18:15 +0000662 fWriter.writePad(ptr, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000663 }
664 }
665}
666
667///////////////////////////////////////////////////////////////////////////////
668
669template <typename T> uint32_t castToU32(T value) {
670 union {
671 T fSrc;
672 uint32_t fDst;
673 } data;
674 data.fSrc = value;
675 return data.fDst;
676}
677
678unsigned SkGPipeCanvas::writePaint(const SkPaint& paint) {
reed@google.comf5842f72011-05-04 18:30:04 +0000679 SkPaint& base = *fPaints[0];
reed@google.combb6992a2011-04-26 17:41:56 +0000680 uint32_t storage[32];
681 uint32_t* ptr = storage;
682 uint32_t* last = NULL;
683
684 if (base.getFlags() != paint.getFlags()) {
685 last = ptr;
686 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags());
reed@google.comf5842f72011-05-04 18:30:04 +0000687 base.setFlags(paint.getFlags());
reed@google.combb6992a2011-04-26 17:41:56 +0000688 }
689 if (base.getColor() != paint.getColor()) {
690 last = ptr;
691 *ptr++ = PaintOp_packOp(kColor_PaintOp);
692 *ptr++ = paint.getColor();
reed@google.comf5842f72011-05-04 18:30:04 +0000693 base.setColor(paint.getColor());
reed@google.combb6992a2011-04-26 17:41:56 +0000694 }
695 if (base.getStyle() != paint.getStyle()) {
696 last = ptr;
697 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle());
reed@google.comf5842f72011-05-04 18:30:04 +0000698 base.setStyle(paint.getStyle());
reed@google.combb6992a2011-04-26 17:41:56 +0000699 }
700 if (base.getStrokeJoin() != paint.getStrokeJoin()) {
701 last = ptr;
702 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin());
reed@google.comf5842f72011-05-04 18:30:04 +0000703 base.setStrokeJoin(paint.getStrokeJoin());
reed@google.combb6992a2011-04-26 17:41:56 +0000704 }
705 if (base.getStrokeCap() != paint.getStrokeCap()) {
706 last = ptr;
707 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap());
reed@google.comf5842f72011-05-04 18:30:04 +0000708 base.setStrokeCap(paint.getStrokeCap());
reed@google.combb6992a2011-04-26 17:41:56 +0000709 }
710 if (base.getStrokeWidth() != paint.getStrokeWidth()) {
711 last = ptr;
712 *ptr++ = PaintOp_packOp(kWidth_PaintOp);
713 *ptr++ = castToU32(paint.getStrokeWidth());
reed@google.comf5842f72011-05-04 18:30:04 +0000714 base.setStrokeWidth(paint.getStrokeWidth());
reed@google.combb6992a2011-04-26 17:41:56 +0000715 }
716 if (base.getStrokeMiter() != paint.getStrokeMiter()) {
717 last = ptr;
718 *ptr++ = PaintOp_packOp(kMiter_PaintOp);
719 *ptr++ = castToU32(paint.getStrokeMiter());
reed@google.comf5842f72011-05-04 18:30:04 +0000720 base.setStrokeMiter(paint.getStrokeMiter());
reed@google.combb6992a2011-04-26 17:41:56 +0000721 }
722 if (base.getTextEncoding() != paint.getTextEncoding()) {
723 last = ptr;
724 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding());
reed@google.comf5842f72011-05-04 18:30:04 +0000725 base.setTextEncoding(paint.getTextEncoding());
reed@google.combb6992a2011-04-26 17:41:56 +0000726 }
727 if (base.getHinting() != paint.getHinting()) {
728 last = ptr;
729 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting());
reed@google.comf5842f72011-05-04 18:30:04 +0000730 base.setHinting(paint.getHinting());
reed@google.combb6992a2011-04-26 17:41:56 +0000731 }
732 if (base.getTextAlign() != paint.getTextAlign()) {
733 last = ptr;
734 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign());
reed@google.comf5842f72011-05-04 18:30:04 +0000735 base.setTextAlign(paint.getTextAlign());
reed@google.combb6992a2011-04-26 17:41:56 +0000736 }
737 if (base.getTextSize() != paint.getTextSize()) {
738 last = ptr;
739 *ptr++ = PaintOp_packOp(kTextSize_PaintOp);
740 *ptr++ = castToU32(paint.getTextSize());
reed@google.comf5842f72011-05-04 18:30:04 +0000741 base.setTextSize(paint.getTextSize());
reed@google.combb6992a2011-04-26 17:41:56 +0000742 }
743 if (base.getTextScaleX() != paint.getTextScaleX()) {
744 last = ptr;
745 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp);
746 *ptr++ = castToU32(paint.getTextScaleX());
reed@google.comf5842f72011-05-04 18:30:04 +0000747 base.setTextScaleX(paint.getTextScaleX());
reed@google.combb6992a2011-04-26 17:41:56 +0000748 }
749 if (base.getTextSkewX() != paint.getTextSkewX()) {
750 last = ptr;
751 *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());
758 last = ptr;
759 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
760 base.setTypeface(paint.getTypeface());
reed@google.combb6992a2011-04-26 17:41:56 +0000761 }
reed@google.combb6992a2011-04-26 17:41:56 +0000762
reed@google.comb55d1182011-05-11 00:42:04 +0000763 for (int i = 0; i < kCount_PaintFlats; i++) {
764 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
765 SkASSERT(index >= 0 && index <= fFlatArray.count());
766 if (index != fCurrFlatIndex[i]) {
767 last = ptr;
768 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
769 fCurrFlatIndex[i] = index;
770 }
771 }
772
reed@google.comacd471f2011-05-03 21:26:46 +0000773 size_t size = (char*)ptr - (char*)storage;
774 if (size && this->needOpBytes(size)) {
reed@google.comb55d1182011-05-11 00:42:04 +0000775 this->writeOp(kPaintOp_DrawOp, 0, size);
776// *last |= kLastOp_PaintOpFlag << PAINTOPS_DATA_BITS;
777 fWriter.write(storage, size);
reed@google.combb6992a2011-04-26 17:41:56 +0000778 for (size_t i = 0; i < size/4; i++) {
reed@google.comb55d1182011-05-11 00:42:04 +0000779// SkDebugf("[%d] %08X\n", i, storage[i]);
reed@google.combb6992a2011-04-26 17:41:56 +0000780 }
781 }
782 return 0;
783}
784
785///////////////////////////////////////////////////////////////////////////////
786
787#include "SkGPipe.h"
788
reed@google.comacd471f2011-05-03 21:26:46 +0000789SkGPipeWriter::SkGPipeWriter() : fWriter(0) {
reed@google.combb6992a2011-04-26 17:41:56 +0000790 fCanvas = NULL;
791}
792
793SkGPipeWriter::~SkGPipeWriter() {
reed@google.comacd471f2011-05-03 21:26:46 +0000794 this->endRecording();
reed@google.combb6992a2011-04-26 17:41:56 +0000795 SkSafeUnref(fCanvas);
796}
797
reed@google.comacd471f2011-05-03 21:26:46 +0000798SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller) {
reed@google.combb6992a2011-04-26 17:41:56 +0000799 if (NULL == fCanvas) {
reed@google.comacd471f2011-05-03 21:26:46 +0000800 fWriter.reset(NULL, 0);
801 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter));
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