blob: 199c4c9b0a1964eba349e27d7c4e4f7eecf33c4a [file] [log] [blame]
chudy@google.com902ebe52012-06-29 14:21:22 +00001
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
robertphillips@google.comf4741c12013-02-06 20:13:54 +000010#include "SkColorPriv.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000011#include "SkDebugCanvas.h"
12#include "SkDrawCommand.h"
robertphillips@google.comf4741c12013-02-06 20:13:54 +000013#include "SkDrawFilter.h"
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +000014#include "SkDevice.h"
robertphillips@google.comf4741c12013-02-06 20:13:54 +000015#include "SkXfermode.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000016
bsalomon@google.com50c79d82013-01-08 20:31:53 +000017#ifdef SK_BUILD_FOR_WIN
18 // iostream includes xlocale which generates warning 4530 because we're compiling without
19 // exceptions
20 #pragma warning(push)
21 #pragma warning(disable : 4530)
22#endif
23#include <iostream>
24#ifdef SK_BUILD_FOR_WIN
25 #pragma warning(pop)
26#endif
27
reed@google.com6ae24e02012-09-26 13:44:13 +000028static SkBitmap make_noconfig_bm(int width, int height) {
29 SkBitmap bm;
30 bm.setConfig(SkBitmap::kNo_Config, width, height);
31 return bm;
32}
33
34SkDebugCanvas::SkDebugCanvas(int width, int height)
tomhudson@google.com0699e022012-11-27 16:09:42 +000035 : INHERITED(make_noconfig_bm(width, height))
robertphillips@google.comf4741c12013-02-06 20:13:54 +000036 , fOverdrawViz(false)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000037 , fOverdrawFilter(NULL)
38 , fOutstandingSaveCount(0) {
chudy@google.com902ebe52012-06-29 14:21:22 +000039 // TODO(chudy): Free up memory from all draw commands in destructor.
chudy@google.com80a4a602012-07-30 18:54:07 +000040 fWidth = width;
41 fHeight = height;
reed@google.com6ae24e02012-09-26 13:44:13 +000042 // do we need fBm anywhere?
chudy@google.comb9ddd4e2012-07-10 14:14:50 +000043 fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
chudy@google.com902ebe52012-06-29 14:21:22 +000044 fFilter = false;
chudy@google.com830b8792012-08-01 15:57:52 +000045 fIndex = 0;
bungeman@google.come8cc6e82013-01-17 16:30:56 +000046 fUserMatrix.reset();
chudy@google.com902ebe52012-06-29 14:21:22 +000047}
48
chudy@google.com9cda6f72012-08-07 15:08:33 +000049SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000050 fCommandVector.deleteAll();
robertphillips@google.comf4741c12013-02-06 20:13:54 +000051 SkSafeUnref(fOverdrawFilter);
chudy@google.com9cda6f72012-08-07 15:08:33 +000052}
chudy@google.com902ebe52012-06-29 14:21:22 +000053
54void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000055 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000056}
57
58void SkDebugCanvas::draw(SkCanvas* canvas) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000059 if(!fCommandVector.isEmpty()) {
60 for (int i = 0; i < fCommandVector.count(); i++) {
61 if (fCommandVector[i]->isVisible()) {
62 fCommandVector[i]->execute(canvas);
chudy@google.com0ab03392012-07-28 20:16:11 +000063 }
chudy@google.com902ebe52012-06-29 14:21:22 +000064 }
65 }
robertphillips@google.com67baba42013-01-02 20:20:31 +000066 fIndex = fCommandVector.count() - 1;
chudy@google.com902ebe52012-06-29 14:21:22 +000067}
68
chudy@google.com830b8792012-08-01 15:57:52 +000069void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000070 canvas->concat(fUserMatrix);
chudy@google.com830b8792012-08-01 15:57:52 +000071}
72
73int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +000074 SkBitmap bitmap;
75 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
76 bitmap.allocPixels();
chudy@google.com902ebe52012-06-29 14:21:22 +000077
chudy@google.com0b5bbb02012-07-31 19:55:32 +000078 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +000079 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
chudy@google.com830b8792012-08-01 15:57:52 +000080 applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000081
82 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +000083 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000084 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000085 if (fCommandVector[i]->isVisible()) {
86 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000087 }
88 if (prev != bitmap.getColor(0,0)) {
89 layer = i;
90 }
91 prev = bitmap.getColor(0,0);
92 }
93 return layer;
94}
95
bsalomon@google.com383e2342013-02-06 21:44:21 +000096static SkPMColor OverdrawXferModeProc(SkPMColor src, SkPMColor dst) {
robertphillips@google.comf4741c12013-02-06 20:13:54 +000097 // This table encodes the color progression of the overdraw visualization
98 static const SkPMColor gTable[] = {
99 SkPackARGB32(0x00, 0x00, 0x00, 0x00),
100 SkPackARGB32(0xFF, 128, 158, 255),
101 SkPackARGB32(0xFF, 170, 185, 212),
102 SkPackARGB32(0xFF, 213, 195, 170),
103 SkPackARGB32(0xFF, 255, 192, 127),
104 SkPackARGB32(0xFF, 255, 185, 85),
105 SkPackARGB32(0xFF, 255, 165, 42),
106 SkPackARGB32(0xFF, 255, 135, 0),
107 SkPackARGB32(0xFF, 255, 95, 0),
108 SkPackARGB32(0xFF, 255, 50, 0),
109 SkPackARGB32(0xFF, 255, 0, 0)
110 };
111
robertphillips@google.com0b256e12013-02-06 20:42:14 +0000112 for (size_t i = 0; i < SK_ARRAY_COUNT(gTable)-1; ++i) {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000113 if (gTable[i] == dst) {
114 return gTable[i+1];
115 }
116 }
117
118 return gTable[SK_ARRAY_COUNT(gTable)-1];
119}
120
121// The OverdrawFilter modifies every paint to use an SkProcXfermode which
122// in turn invokes OverdrawXferModeProc
123class OverdrawFilter : public SkDrawFilter {
124public:
125 OverdrawFilter() {
126 fXferMode = new SkProcXfermode(OverdrawXferModeProc);
127 }
128
129 virtual ~OverdrawFilter() {
130 delete fXferMode;
131 }
132
133 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
134 p->setXfermode(fXferMode);
135 return true;
136 }
137
138protected:
139 SkXfermode* fXferMode;
140
141private:
142 typedef SkDrawFilter INHERITED;
143};
144
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000145void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000146 SkASSERT(!fCommandVector.isEmpty());
147 SkASSERT(index < fCommandVector.count());
chudy@google.com830b8792012-08-01 15:57:52 +0000148 int i;
149
150 // This only works assuming the canvas and device are the same ones that
151 // were previously drawn into because they need to preserve all saves
152 // and restores.
153 if (fIndex < index) {
154 i = fIndex + 1;
155 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000156 for (int j = 0; j < fOutstandingSaveCount; j++) {
157 canvas->restore();
158 }
chudy@google.com830b8792012-08-01 15:57:52 +0000159 i = 0;
junov@google.comdbfac8a2012-12-06 21:47:40 +0000160 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000161 canvas->resetMatrix();
skia.committer@gmail.com04ba4482012-09-07 02:01:30 +0000162 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth),
robertphillips@google.com94acc702012-09-06 18:43:21 +0000163 SkIntToScalar(fHeight));
chudy@google.com4c7962e2012-08-14 19:38:31 +0000164 canvas->clipRect(rect, SkRegion::kReplace_Op );
chudy@google.com830b8792012-08-01 15:57:52 +0000165 applyUserTransform(canvas);
tomhudson@google.com0699e022012-11-27 16:09:42 +0000166 fOutstandingSaveCount = 0;
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000167
168 // The setting of the draw filter has to go here (rather than in
169 // SkRasterWidget) due to the canvas restores this class performs.
170 // Since the draw filter is stored in the layer stack if we
171 // call setDrawFilter on anything but the root layer odd things happen
172 if (fOverdrawViz) {
173 if (NULL == fOverdrawFilter) {
174 fOverdrawFilter = new OverdrawFilter;
175 }
176
177 if (fOverdrawFilter != canvas->getDrawFilter()) {
178 canvas->setDrawFilter(fOverdrawFilter);
179 }
180 } else {
181 canvas->setDrawFilter(NULL);
182 }
chudy@google.com830b8792012-08-01 15:57:52 +0000183 }
184
185 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000186 if (i == index && fFilter) {
187 SkPaint p;
188 p.setColor(0xAAFFFFFF);
189 canvas->save();
190 canvas->resetMatrix();
191 SkRect mask;
192 mask.set(SkIntToScalar(0), SkIntToScalar(0),
193 SkIntToScalar(fWidth), SkIntToScalar(fHeight));
194 canvas->clipRect(mask, SkRegion::kReplace_Op, false);
195 canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
196 SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
197 canvas->restore();
198 }
199
robertphillips@google.com67baba42013-01-02 20:20:31 +0000200 if (fCommandVector[i]->isVisible()) {
201 fCommandVector[i]->execute(canvas);
202 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000203 }
204 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000205 fMatrix = canvas->getTotalMatrix();
206 fClip = canvas->getTotalClip().getBounds();
chudy@google.com830b8792012-08-01 15:57:52 +0000207 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000208}
209
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000210void SkDebugCanvas::deleteDrawCommandAt(int index) {
211 SkASSERT(index < fCommandVector.count());
212 delete fCommandVector[index];
213 fCommandVector.remove(index);
214}
215
chudy@google.com902ebe52012-06-29 14:21:22 +0000216SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000217 SkASSERT(index < fCommandVector.count());
218 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000219}
220
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000221void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
222 SkASSERT(index < fCommandVector.count());
223 delete fCommandVector[index];
224 fCommandVector[index] = command;
225}
226
chudy@google.com97cee972012-08-07 20:41:37 +0000227SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000228 SkASSERT(index < fCommandVector.count());
229 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000230}
chudy@google.com902ebe52012-06-29 14:21:22 +0000231
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000232bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000233 SkASSERT(index < fCommandVector.count());
234 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000235}
236
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000237const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000238 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000239}
240
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000241SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
242 return fCommandVector;
243}
244
chudy@google.com902ebe52012-06-29 14:21:22 +0000245// TODO(chudy): Free command string memory.
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000246SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000247 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
248 if (!fCommandVector.isEmpty()) {
249 for (int i = 0; i < fCommandVector.count(); i ++) {
250 commandString->push_back() = fCommandVector[i]->toString();
chudy@google.com902ebe52012-06-29 14:21:22 +0000251 }
252 }
253 return commandString;
254}
255
256void SkDebugCanvas::toggleFilter(bool toggle) {
257 fFilter = toggle;
258}
259
260void SkDebugCanvas::clear(SkColor color) {
261 addDrawCommand(new Clear(color));
262}
263
264bool SkDebugCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000265 addDrawCommand(new ClipPath(path, op, doAA));
chudy@google.com902ebe52012-06-29 14:21:22 +0000266 return true;
267}
268
269bool SkDebugCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
270 addDrawCommand(new ClipRect(rect, op, doAA));
271 return true;
272}
273
robertphillips@google.com67baba42013-01-02 20:20:31 +0000274bool SkDebugCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
275 addDrawCommand(new ClipRRect(rrect, op, doAA));
276 return true;
277}
278
chudy@google.com902ebe52012-06-29 14:21:22 +0000279bool SkDebugCanvas::clipRegion(const SkRegion& region, SkRegion::Op op) {
280 addDrawCommand(new ClipRegion(region, op));
281 return true;
282}
283
284bool SkDebugCanvas::concat(const SkMatrix& matrix) {
285 addDrawCommand(new Concat(matrix));
286 return true;
287}
288
289void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
290 SkScalar top, const SkPaint* paint = NULL) {
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000291 addDrawCommand(new DrawBitmap(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000292}
293
reed@google.com71121732012-09-18 15:14:33 +0000294void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
295 const SkRect* src, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000296 addDrawCommand(new DrawBitmapRect(bitmap, src, dst, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000297}
298
299void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
300 const SkMatrix& matrix, const SkPaint* paint) {
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000301 addDrawCommand(new DrawBitmapMatrix(bitmap, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000302}
303
304void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
305 const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000306 addDrawCommand(new DrawBitmapNine(bitmap, center, dst, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000307}
308
309void SkDebugCanvas::drawData(const void* data, size_t length) {
310 addDrawCommand(new DrawData(data, length));
311}
312
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000313void SkDebugCanvas::beginCommentGroup(const char* description) {
314 addDrawCommand(new BeginCommentGroup(description));
315}
316
317void SkDebugCanvas::addComment(const char* kywd, const char* value) {
318 addDrawCommand(new Comment(kywd, value));
319}
320
321void SkDebugCanvas::endCommentGroup() {
322 addDrawCommand(new EndCommentGroup());
323}
324
robertphillips@google.com67baba42013-01-02 20:20:31 +0000325void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
326 addDrawCommand(new DrawOval(oval, paint));
327}
328
chudy@google.com902ebe52012-06-29 14:21:22 +0000329void SkDebugCanvas::drawPaint(const SkPaint& paint) {
330 addDrawCommand(new DrawPaint(paint));
331}
332
333void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000334 addDrawCommand(new DrawPath(path, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000335}
336
337void SkDebugCanvas::drawPicture(SkPicture& picture) {
338 addDrawCommand(new DrawPicture(picture));
339}
340
341void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
robertphillips@google.coma3a09ab2013-03-22 12:25:30 +0000342 const SkPoint pts[], const SkPaint& paint) {
chudy@google.com902ebe52012-06-29 14:21:22 +0000343 addDrawCommand(new DrawPoints(mode, count, pts, paint));
344}
345
346void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
347 const SkPoint pos[], const SkPaint& paint) {
348 addDrawCommand(new DrawPosText(text, byteLength, pos, paint));
349}
350
351void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
352 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
353 addDrawCommand(new DrawPosTextH(text, byteLength, xpos, constY, paint));
354}
355
356void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
357 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
358 addDrawCommand(new DrawRectC(rect, paint));
359}
360
robertphillips@google.com67baba42013-01-02 20:20:31 +0000361void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
362 addDrawCommand(new DrawRRect(rrect, paint));
363}
364
chudy@google.com902ebe52012-06-29 14:21:22 +0000365void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000366 const SkPaint* paint = NULL) {
367 addDrawCommand(new DrawSprite(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000368}
369
370void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
371 SkScalar y, const SkPaint& paint) {
372 addDrawCommand(new DrawTextC(text, byteLength, x, y, paint));
373}
374
375void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
376 const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
377 addDrawCommand(new DrawTextOnPath(text, byteLength, path, matrix, paint));
378}
379
380void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
381 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
382 SkXfermode*, const uint16_t indices[], int indexCount,
383 const SkPaint& paint) {
384 addDrawCommand(new DrawVertices(vmode, vertexCount, vertices, texs, colors,
385 NULL, indices, indexCount, paint));
386}
387
388void SkDebugCanvas::restore() {
389 addDrawCommand(new Restore());
390}
391
392bool SkDebugCanvas::rotate(SkScalar degrees) {
393 addDrawCommand(new Rotate(degrees));
394 return true;
395}
396
397int SkDebugCanvas::save(SaveFlags flags) {
398 addDrawCommand(new Save(flags));
399 return true;
400}
401
402int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
403 SaveFlags flags) {
404 addDrawCommand(new SaveLayer(bounds, paint, flags));
405 return true;
406}
407
408bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
409 addDrawCommand(new Scale(sx, sy));
410 return true;
411}
412
413void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
414 addDrawCommand(new SetMatrix(matrix));
415}
416
417bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
418 addDrawCommand(new Skew(sx, sy));
419 return true;
420}
421
422bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
423 addDrawCommand(new Translate(dx, dy));
424 return true;
425}
426
chudy@google.com902ebe52012-06-29 14:21:22 +0000427void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000428 SkASSERT(index < fCommandVector.count());
429 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000430}