blob: e4cfec8393c95b242b7b346ea3d40dfd080e45a9 [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
chudy@google.com902ebe52012-06-29 14:21:22 +000010#include "SkDebugCanvas.h"
11#include "SkDrawCommand.h"
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +000012#include "SkDevice.h"
13#include "SkImageWidget.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000014
bsalomon@google.com50c79d82013-01-08 20:31:53 +000015#ifdef SK_BUILD_FOR_WIN
16 // iostream includes xlocale which generates warning 4530 because we're compiling without
17 // exceptions
18 #pragma warning(push)
19 #pragma warning(disable : 4530)
20#endif
21#include <iostream>
22#ifdef SK_BUILD_FOR_WIN
23 #pragma warning(pop)
24#endif
25
reed@google.com6ae24e02012-09-26 13:44:13 +000026static SkBitmap make_noconfig_bm(int width, int height) {
27 SkBitmap bm;
28 bm.setConfig(SkBitmap::kNo_Config, width, height);
29 return bm;
30}
31
32SkDebugCanvas::SkDebugCanvas(int width, int height)
tomhudson@google.com0699e022012-11-27 16:09:42 +000033 : INHERITED(make_noconfig_bm(width, height))
34 , fOutstandingSaveCount(0) {
chudy@google.com902ebe52012-06-29 14:21:22 +000035 // TODO(chudy): Free up memory from all draw commands in destructor.
chudy@google.com80a4a602012-07-30 18:54:07 +000036 fWidth = width;
37 fHeight = height;
reed@google.com6ae24e02012-09-26 13:44:13 +000038 // do we need fBm anywhere?
chudy@google.comb9ddd4e2012-07-10 14:14:50 +000039 fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
chudy@google.com902ebe52012-06-29 14:21:22 +000040 fFilter = false;
chudy@google.com830b8792012-08-01 15:57:52 +000041 fIndex = 0;
bungeman@google.come8cc6e82013-01-17 16:30:56 +000042 fUserMatrix.reset();
chudy@google.com902ebe52012-06-29 14:21:22 +000043}
44
chudy@google.com9cda6f72012-08-07 15:08:33 +000045SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000046 fCommandVector.deleteAll();
chudy@google.com9cda6f72012-08-07 15:08:33 +000047}
chudy@google.com902ebe52012-06-29 14:21:22 +000048
49void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000050 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000051}
52
53void SkDebugCanvas::draw(SkCanvas* canvas) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000054 if(!fCommandVector.isEmpty()) {
55 for (int i = 0; i < fCommandVector.count(); i++) {
56 if (fCommandVector[i]->isVisible()) {
57 fCommandVector[i]->execute(canvas);
chudy@google.com0ab03392012-07-28 20:16:11 +000058 }
chudy@google.com902ebe52012-06-29 14:21:22 +000059 }
60 }
robertphillips@google.com67baba42013-01-02 20:20:31 +000061 fIndex = fCommandVector.count() - 1;
chudy@google.com902ebe52012-06-29 14:21:22 +000062}
63
chudy@google.com830b8792012-08-01 15:57:52 +000064void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000065 canvas->concat(fUserMatrix);
chudy@google.com830b8792012-08-01 15:57:52 +000066}
67
68int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +000069 SkBitmap bitmap;
70 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
71 bitmap.allocPixels();
chudy@google.com902ebe52012-06-29 14:21:22 +000072
chudy@google.com0b5bbb02012-07-31 19:55:32 +000073 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +000074 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
chudy@google.com830b8792012-08-01 15:57:52 +000075 applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000076
77 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +000078 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000079 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000080 if (fCommandVector[i]->isVisible()) {
81 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000082 }
83 if (prev != bitmap.getColor(0,0)) {
84 layer = i;
85 }
86 prev = bitmap.getColor(0,0);
87 }
88 return layer;
89}
90
91void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
92 int counter = 0;
robertphillips@google.com67baba42013-01-02 20:20:31 +000093 SkASSERT(!fCommandVector.isEmpty());
94 SkASSERT(index < fCommandVector.count());
chudy@google.com830b8792012-08-01 15:57:52 +000095 int i;
96
97 // This only works assuming the canvas and device are the same ones that
98 // were previously drawn into because they need to preserve all saves
99 // and restores.
100 if (fIndex < index) {
101 i = fIndex + 1;
102 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000103 for (int j = 0; j < fOutstandingSaveCount; j++) {
104 canvas->restore();
105 }
chudy@google.com830b8792012-08-01 15:57:52 +0000106 i = 0;
junov@google.comdbfac8a2012-12-06 21:47:40 +0000107 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000108 canvas->resetMatrix();
skia.committer@gmail.com04ba4482012-09-07 02:01:30 +0000109 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth),
robertphillips@google.com94acc702012-09-06 18:43:21 +0000110 SkIntToScalar(fHeight));
chudy@google.com4c7962e2012-08-14 19:38:31 +0000111 canvas->clipRect(rect, SkRegion::kReplace_Op );
chudy@google.com830b8792012-08-01 15:57:52 +0000112 applyUserTransform(canvas);
tomhudson@google.com0699e022012-11-27 16:09:42 +0000113 fOutstandingSaveCount = 0;
chudy@google.com830b8792012-08-01 15:57:52 +0000114 }
115
116 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000117 if (i == index && fFilter) {
118 SkPaint p;
119 p.setColor(0xAAFFFFFF);
120 canvas->save();
121 canvas->resetMatrix();
122 SkRect mask;
123 mask.set(SkIntToScalar(0), SkIntToScalar(0),
124 SkIntToScalar(fWidth), SkIntToScalar(fHeight));
125 canvas->clipRect(mask, SkRegion::kReplace_Op, false);
126 canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
127 SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
128 canvas->restore();
129 }
130
robertphillips@google.com67baba42013-01-02 20:20:31 +0000131 if (fCommandVector[i]->isVisible()) {
132 fCommandVector[i]->execute(canvas);
133 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000134 }
135 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000136 fMatrix = canvas->getTotalMatrix();
137 fClip = canvas->getTotalClip().getBounds();
chudy@google.com830b8792012-08-01 15:57:52 +0000138 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000139}
140
141SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000142 SkASSERT(index < fCommandVector.count());
143 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000144}
145
chudy@google.com97cee972012-08-07 20:41:37 +0000146SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000147 SkASSERT(index < fCommandVector.count());
148 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000149}
chudy@google.com902ebe52012-06-29 14:21:22 +0000150
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000151bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000152 SkASSERT(index < fCommandVector.count());
153 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000154}
155
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000156const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000157 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000158}
159
160// TODO(chudy): Free command string memory.
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000161SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000162 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
163 if (!fCommandVector.isEmpty()) {
164 for (int i = 0; i < fCommandVector.count(); i ++) {
165 commandString->push_back() = fCommandVector[i]->toString();
chudy@google.com902ebe52012-06-29 14:21:22 +0000166 }
167 }
168 return commandString;
169}
170
171void SkDebugCanvas::toggleFilter(bool toggle) {
172 fFilter = toggle;
173}
174
175void SkDebugCanvas::clear(SkColor color) {
176 addDrawCommand(new Clear(color));
177}
178
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000179static SkBitmap createBitmap(const SkPath& path) {
180 SkBitmap bitmap;
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000181 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
182 SkImageWidget::kImageWidgetWidth,
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000183 SkImageWidget::kImageWidgetHeight);
184 bitmap.allocPixels();
185 bitmap.eraseColor(SK_ColorWHITE);
186 SkDevice* device = new SkDevice(bitmap);
187
188 SkCanvas canvas(device);
189 device->unref();
190
191 const SkRect& bounds = path.getBounds();
192
193 if (bounds.width() > bounds.height()) {
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000194 canvas.scale(SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetWidth)/bounds.width()),
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000195 SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetHeight)/bounds.width()));
196 } else {
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000197 canvas.scale(SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetWidth)/bounds.height()),
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000198 SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetHeight)/bounds.height()));
199 }
200 canvas.translate(-bounds.fLeft+2, -bounds.fTop+2);
201
202 SkPaint p;
203 p.setColor(SK_ColorBLACK);
204 p.setStyle(SkPaint::kStroke_Style);
205
206 canvas.drawPath(path, p);
207
208 return bitmap;
209}
210
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000211static SkBitmap createBitmap(const SkBitmap& input, const SkRect* srcRect) {
212 SkBitmap bitmap;
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000213 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
214 SkImageWidget::kImageWidgetWidth,
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000215 SkImageWidget::kImageWidgetHeight);
216 bitmap.allocPixels();
217 bitmap.eraseColor(SK_ColorLTGRAY);
218 SkDevice* device = new SkDevice(bitmap);
219
220 SkCanvas canvas(device);
221 device->unref();
222
223 SkScalar xScale = (SkImageWidget::kImageWidgetWidth-2.0) / input.width();
224 SkScalar yScale = (SkImageWidget::kImageWidgetHeight-2.0) / input.height();
225
226 if (input.width() > input.height()) {
227 yScale *= input.height() / (float) input.width();
228 } else {
229 xScale *= input.width() / (float) input.height();
230 }
231
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000232 SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1,
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000233 xScale * input.width(),
234 yScale * input.height());
235
236 canvas.drawBitmapRect(input, NULL, dst);
237
238 if (NULL != srcRect) {
239 SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
240 srcRect->fTop * yScale + SK_Scalar1,
241 srcRect->fRight * xScale + SK_Scalar1,
242 srcRect->fBottom * yScale + SK_Scalar1);
243 SkPaint p;
244 p.setColor(SK_ColorRED);
245 p.setStyle(SkPaint::kStroke_Style);
246
247 canvas.drawRect(r, p);
248 }
249
250 return bitmap;
251}
252
chudy@google.com902ebe52012-06-29 14:21:22 +0000253bool SkDebugCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
rmistry@google.com44737652012-11-21 18:37:58 +0000254 SkBitmap bitmap = createBitmap(path);
255 addDrawCommand(new ClipPath(path, op, doAA, bitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000256 return true;
257}
258
259bool SkDebugCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
260 addDrawCommand(new ClipRect(rect, op, doAA));
261 return true;
262}
263
robertphillips@google.com67baba42013-01-02 20:20:31 +0000264bool SkDebugCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
265 addDrawCommand(new ClipRRect(rrect, op, doAA));
266 return true;
267}
268
chudy@google.com902ebe52012-06-29 14:21:22 +0000269bool SkDebugCanvas::clipRegion(const SkRegion& region, SkRegion::Op op) {
270 addDrawCommand(new ClipRegion(region, op));
271 return true;
272}
273
274bool SkDebugCanvas::concat(const SkMatrix& matrix) {
275 addDrawCommand(new Concat(matrix));
276 return true;
277}
278
279void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
280 SkScalar top, const SkPaint* paint = NULL) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000281 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
282 addDrawCommand(new DrawBitmap(bitmap, left, top, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000283}
284
reed@google.com71121732012-09-18 15:14:33 +0000285void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
286 const SkRect* src, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000287 SkBitmap resizedBitmap = createBitmap(bitmap, src);
288 addDrawCommand(new DrawBitmapRect(bitmap, src, dst, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000289}
290
291void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
292 const SkMatrix& matrix, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000293 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
294 addDrawCommand(new DrawBitmapMatrix(bitmap, matrix, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000295}
296
297void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
298 const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000299 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
300 addDrawCommand(new DrawBitmapNine(bitmap, center, dst, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000301}
302
303void SkDebugCanvas::drawData(const void* data, size_t length) {
304 addDrawCommand(new DrawData(data, length));
305}
306
robertphillips@google.com67baba42013-01-02 20:20:31 +0000307void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
308 addDrawCommand(new DrawOval(oval, paint));
309}
310
chudy@google.com902ebe52012-06-29 14:21:22 +0000311void SkDebugCanvas::drawPaint(const SkPaint& paint) {
312 addDrawCommand(new DrawPaint(paint));
313}
314
315void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
rmistry@google.com44737652012-11-21 18:37:58 +0000316 SkBitmap bitmap = createBitmap(path);
317 addDrawCommand(new DrawPath(path, paint, bitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000318}
319
320void SkDebugCanvas::drawPicture(SkPicture& picture) {
321 addDrawCommand(new DrawPicture(picture));
322}
323
324void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
325 const SkPoint pts[], const SkPaint& paint) {
326 addDrawCommand(new DrawPoints(mode, count, pts, paint));
327}
328
329void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
330 const SkPoint pos[], const SkPaint& paint) {
331 addDrawCommand(new DrawPosText(text, byteLength, pos, paint));
332}
333
334void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
335 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
336 addDrawCommand(new DrawPosTextH(text, byteLength, xpos, constY, paint));
337}
338
339void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
340 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
341 addDrawCommand(new DrawRectC(rect, paint));
342}
343
robertphillips@google.com67baba42013-01-02 20:20:31 +0000344void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
345 addDrawCommand(new DrawRRect(rrect, paint));
346}
347
chudy@google.com902ebe52012-06-29 14:21:22 +0000348void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
349 const SkPaint* paint = NULL) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000350 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
351 addDrawCommand(new DrawSprite(bitmap, left, top, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000352}
353
354void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
355 SkScalar y, const SkPaint& paint) {
356 addDrawCommand(new DrawTextC(text, byteLength, x, y, paint));
357}
358
359void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
360 const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
361 addDrawCommand(new DrawTextOnPath(text, byteLength, path, matrix, paint));
362}
363
364void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
365 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
366 SkXfermode*, const uint16_t indices[], int indexCount,
367 const SkPaint& paint) {
368 addDrawCommand(new DrawVertices(vmode, vertexCount, vertices, texs, colors,
369 NULL, indices, indexCount, paint));
370}
371
372void SkDebugCanvas::restore() {
373 addDrawCommand(new Restore());
374}
375
376bool SkDebugCanvas::rotate(SkScalar degrees) {
377 addDrawCommand(new Rotate(degrees));
378 return true;
379}
380
381int SkDebugCanvas::save(SaveFlags flags) {
382 addDrawCommand(new Save(flags));
383 return true;
384}
385
386int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
387 SaveFlags flags) {
388 addDrawCommand(new SaveLayer(bounds, paint, flags));
389 return true;
390}
391
392bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
393 addDrawCommand(new Scale(sx, sy));
394 return true;
395}
396
397void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
398 addDrawCommand(new SetMatrix(matrix));
399}
400
401bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
402 addDrawCommand(new Skew(sx, sy));
403 return true;
404}
405
406bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
407 addDrawCommand(new Translate(dx, dy));
408 return true;
409}
410
chudy@google.com902ebe52012-06-29 14:21:22 +0000411void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000412 SkASSERT(index < fCommandVector.count());
413 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000414}