blob: 7be729ca3a6405ed2b77f82a1cb7fa9573ba174c [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"
chudy@google.com902ebe52012-06-29 14:21:22 +000013
bsalomon@google.com50c79d82013-01-08 20:31:53 +000014#ifdef SK_BUILD_FOR_WIN
15 // iostream includes xlocale which generates warning 4530 because we're compiling without
16 // exceptions
17 #pragma warning(push)
18 #pragma warning(disable : 4530)
19#endif
20#include <iostream>
21#ifdef SK_BUILD_FOR_WIN
22 #pragma warning(pop)
23#endif
24
reed@google.com6ae24e02012-09-26 13:44:13 +000025static SkBitmap make_noconfig_bm(int width, int height) {
26 SkBitmap bm;
27 bm.setConfig(SkBitmap::kNo_Config, width, height);
28 return bm;
29}
30
31SkDebugCanvas::SkDebugCanvas(int width, int height)
tomhudson@google.com0699e022012-11-27 16:09:42 +000032 : INHERITED(make_noconfig_bm(width, height))
33 , fOutstandingSaveCount(0) {
chudy@google.com902ebe52012-06-29 14:21:22 +000034 // TODO(chudy): Free up memory from all draw commands in destructor.
chudy@google.com80a4a602012-07-30 18:54:07 +000035 fWidth = width;
36 fHeight = height;
reed@google.com6ae24e02012-09-26 13:44:13 +000037 // do we need fBm anywhere?
chudy@google.comb9ddd4e2012-07-10 14:14:50 +000038 fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
chudy@google.com902ebe52012-06-29 14:21:22 +000039 fFilter = false;
chudy@google.com830b8792012-08-01 15:57:52 +000040 fIndex = 0;
bungeman@google.come8cc6e82013-01-17 16:30:56 +000041 fUserMatrix.reset();
chudy@google.com902ebe52012-06-29 14:21:22 +000042}
43
chudy@google.com9cda6f72012-08-07 15:08:33 +000044SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000045 fCommandVector.deleteAll();
chudy@google.com9cda6f72012-08-07 15:08:33 +000046}
chudy@google.com902ebe52012-06-29 14:21:22 +000047
48void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000049 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000050}
51
52void SkDebugCanvas::draw(SkCanvas* canvas) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000053 if(!fCommandVector.isEmpty()) {
54 for (int i = 0; i < fCommandVector.count(); i++) {
55 if (fCommandVector[i]->isVisible()) {
56 fCommandVector[i]->execute(canvas);
chudy@google.com0ab03392012-07-28 20:16:11 +000057 }
chudy@google.com902ebe52012-06-29 14:21:22 +000058 }
59 }
robertphillips@google.com67baba42013-01-02 20:20:31 +000060 fIndex = fCommandVector.count() - 1;
chudy@google.com902ebe52012-06-29 14:21:22 +000061}
62
chudy@google.com830b8792012-08-01 15:57:52 +000063void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000064 canvas->concat(fUserMatrix);
chudy@google.com830b8792012-08-01 15:57:52 +000065}
66
67int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +000068 SkBitmap bitmap;
69 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
70 bitmap.allocPixels();
chudy@google.com902ebe52012-06-29 14:21:22 +000071
chudy@google.com0b5bbb02012-07-31 19:55:32 +000072 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +000073 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
chudy@google.com830b8792012-08-01 15:57:52 +000074 applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000075
76 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +000077 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000078 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000079 if (fCommandVector[i]->isVisible()) {
80 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000081 }
82 if (prev != bitmap.getColor(0,0)) {
83 layer = i;
84 }
85 prev = bitmap.getColor(0,0);
86 }
87 return layer;
88}
89
90void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
91 int counter = 0;
robertphillips@google.com67baba42013-01-02 20:20:31 +000092 SkASSERT(!fCommandVector.isEmpty());
93 SkASSERT(index < fCommandVector.count());
chudy@google.com830b8792012-08-01 15:57:52 +000094 int i;
95
96 // This only works assuming the canvas and device are the same ones that
97 // were previously drawn into because they need to preserve all saves
98 // and restores.
99 if (fIndex < index) {
100 i = fIndex + 1;
101 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000102 for (int j = 0; j < fOutstandingSaveCount; j++) {
103 canvas->restore();
104 }
chudy@google.com830b8792012-08-01 15:57:52 +0000105 i = 0;
junov@google.comdbfac8a2012-12-06 21:47:40 +0000106 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000107 canvas->resetMatrix();
skia.committer@gmail.com04ba4482012-09-07 02:01:30 +0000108 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth),
robertphillips@google.com94acc702012-09-06 18:43:21 +0000109 SkIntToScalar(fHeight));
chudy@google.com4c7962e2012-08-14 19:38:31 +0000110 canvas->clipRect(rect, SkRegion::kReplace_Op );
chudy@google.com830b8792012-08-01 15:57:52 +0000111 applyUserTransform(canvas);
tomhudson@google.com0699e022012-11-27 16:09:42 +0000112 fOutstandingSaveCount = 0;
chudy@google.com830b8792012-08-01 15:57:52 +0000113 }
114
115 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000116 if (i == index && fFilter) {
117 SkPaint p;
118 p.setColor(0xAAFFFFFF);
119 canvas->save();
120 canvas->resetMatrix();
121 SkRect mask;
122 mask.set(SkIntToScalar(0), SkIntToScalar(0),
123 SkIntToScalar(fWidth), SkIntToScalar(fHeight));
124 canvas->clipRect(mask, SkRegion::kReplace_Op, false);
125 canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
126 SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
127 canvas->restore();
128 }
129
robertphillips@google.com67baba42013-01-02 20:20:31 +0000130 if (fCommandVector[i]->isVisible()) {
131 fCommandVector[i]->execute(canvas);
132 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000133 }
134 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000135 fMatrix = canvas->getTotalMatrix();
136 fClip = canvas->getTotalClip().getBounds();
chudy@google.com830b8792012-08-01 15:57:52 +0000137 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000138}
139
140SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000141 SkASSERT(index < fCommandVector.count());
142 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000143}
144
chudy@google.com97cee972012-08-07 20:41:37 +0000145SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000146 SkASSERT(index < fCommandVector.count());
147 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000148}
chudy@google.com902ebe52012-06-29 14:21:22 +0000149
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000150bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000151 SkASSERT(index < fCommandVector.count());
152 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000153}
154
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000155const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000156 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000157}
158
159// TODO(chudy): Free command string memory.
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000160SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000161 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
162 if (!fCommandVector.isEmpty()) {
163 for (int i = 0; i < fCommandVector.count(); i ++) {
164 commandString->push_back() = fCommandVector[i]->toString();
chudy@google.com902ebe52012-06-29 14:21:22 +0000165 }
166 }
167 return commandString;
168}
169
170void SkDebugCanvas::toggleFilter(bool toggle) {
171 fFilter = toggle;
172}
173
174void SkDebugCanvas::clear(SkColor color) {
175 addDrawCommand(new Clear(color));
176}
177
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000178static SkBitmap createBitmap(const SkPath& path) {
179 SkBitmap bitmap;
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000180 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000181 SkDebugCanvas::kVizImageWidth,
182 SkDebugCanvas::kVizImageHeight);
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000183 bitmap.allocPixels();
184 bitmap.eraseColor(SK_ColorWHITE);
185 SkDevice* device = new SkDevice(bitmap);
186
187 SkCanvas canvas(device);
188 device->unref();
189
190 const SkRect& bounds = path.getBounds();
191
192 if (bounds.width() > bounds.height()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000193 canvas.scale(SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageWidth)/bounds.width()),
194 SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageHeight)/bounds.width()));
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000195 } else {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000196 canvas.scale(SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageWidth)/bounds.height()),
197 SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageHeight)/bounds.height()));
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000198 }
199 canvas.translate(-bounds.fLeft+2, -bounds.fTop+2);
200
201 SkPaint p;
202 p.setColor(SK_ColorBLACK);
203 p.setStyle(SkPaint::kStroke_Style);
204
205 canvas.drawPath(path, p);
206
207 return bitmap;
208}
209
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000210static SkBitmap createBitmap(const SkBitmap& input, const SkRect* srcRect) {
211 SkBitmap bitmap;
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000212 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000213 SkDebugCanvas::kVizImageWidth,
214 SkDebugCanvas::kVizImageHeight);
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000215 bitmap.allocPixels();
216 bitmap.eraseColor(SK_ColorLTGRAY);
217 SkDevice* device = new SkDevice(bitmap);
218
219 SkCanvas canvas(device);
220 device->unref();
221
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000222 SkScalar xScale = SkIntToScalar(SkDebugCanvas::kVizImageWidth-2) / input.width();
223 SkScalar yScale = SkIntToScalar(SkDebugCanvas::kVizImageHeight-2) / input.height();
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000224
225 if (input.width() > input.height()) {
226 yScale *= input.height() / (float) input.width();
227 } else {
228 xScale *= input.width() / (float) input.height();
229 }
230
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000231 SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1,
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000232 xScale * input.width(),
233 yScale * input.height());
234
235 canvas.drawBitmapRect(input, NULL, dst);
236
237 if (NULL != srcRect) {
238 SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
239 srcRect->fTop * yScale + SK_Scalar1,
240 srcRect->fRight * xScale + SK_Scalar1,
241 srcRect->fBottom * yScale + SK_Scalar1);
242 SkPaint p;
243 p.setColor(SK_ColorRED);
244 p.setStyle(SkPaint::kStroke_Style);
245
246 canvas.drawRect(r, p);
247 }
248
249 return bitmap;
250}
251
chudy@google.com902ebe52012-06-29 14:21:22 +0000252bool SkDebugCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
rmistry@google.com44737652012-11-21 18:37:58 +0000253 SkBitmap bitmap = createBitmap(path);
254 addDrawCommand(new ClipPath(path, op, doAA, bitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000255 return true;
256}
257
258bool SkDebugCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
259 addDrawCommand(new ClipRect(rect, op, doAA));
260 return true;
261}
262
robertphillips@google.com67baba42013-01-02 20:20:31 +0000263bool SkDebugCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
264 addDrawCommand(new ClipRRect(rrect, op, doAA));
265 return true;
266}
267
chudy@google.com902ebe52012-06-29 14:21:22 +0000268bool SkDebugCanvas::clipRegion(const SkRegion& region, SkRegion::Op op) {
269 addDrawCommand(new ClipRegion(region, op));
270 return true;
271}
272
273bool SkDebugCanvas::concat(const SkMatrix& matrix) {
274 addDrawCommand(new Concat(matrix));
275 return true;
276}
277
278void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
279 SkScalar top, const SkPaint* paint = NULL) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000280 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
281 addDrawCommand(new DrawBitmap(bitmap, left, top, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000282}
283
reed@google.com71121732012-09-18 15:14:33 +0000284void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
285 const SkRect* src, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000286 SkBitmap resizedBitmap = createBitmap(bitmap, src);
287 addDrawCommand(new DrawBitmapRect(bitmap, src, dst, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000288}
289
290void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
291 const SkMatrix& matrix, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000292 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
293 addDrawCommand(new DrawBitmapMatrix(bitmap, matrix, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000294}
295
296void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
297 const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000298 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
299 addDrawCommand(new DrawBitmapNine(bitmap, center, dst, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000300}
301
302void SkDebugCanvas::drawData(const void* data, size_t length) {
303 addDrawCommand(new DrawData(data, length));
304}
305
robertphillips@google.com67baba42013-01-02 20:20:31 +0000306void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
307 addDrawCommand(new DrawOval(oval, paint));
308}
309
chudy@google.com902ebe52012-06-29 14:21:22 +0000310void SkDebugCanvas::drawPaint(const SkPaint& paint) {
311 addDrawCommand(new DrawPaint(paint));
312}
313
314void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
rmistry@google.com44737652012-11-21 18:37:58 +0000315 SkBitmap bitmap = createBitmap(path);
316 addDrawCommand(new DrawPath(path, paint, bitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000317}
318
319void SkDebugCanvas::drawPicture(SkPicture& picture) {
320 addDrawCommand(new DrawPicture(picture));
321}
322
323void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
324 const SkPoint pts[], const SkPaint& paint) {
325 addDrawCommand(new DrawPoints(mode, count, pts, paint));
326}
327
328void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
329 const SkPoint pos[], const SkPaint& paint) {
330 addDrawCommand(new DrawPosText(text, byteLength, pos, paint));
331}
332
333void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
334 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
335 addDrawCommand(new DrawPosTextH(text, byteLength, xpos, constY, paint));
336}
337
338void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
339 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
340 addDrawCommand(new DrawRectC(rect, paint));
341}
342
robertphillips@google.com67baba42013-01-02 20:20:31 +0000343void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
344 addDrawCommand(new DrawRRect(rrect, paint));
345}
346
chudy@google.com902ebe52012-06-29 14:21:22 +0000347void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
348 const SkPaint* paint = NULL) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000349 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
350 addDrawCommand(new DrawSprite(bitmap, left, top, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000351}
352
353void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
354 SkScalar y, const SkPaint& paint) {
355 addDrawCommand(new DrawTextC(text, byteLength, x, y, paint));
356}
357
358void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
359 const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
360 addDrawCommand(new DrawTextOnPath(text, byteLength, path, matrix, paint));
361}
362
363void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
364 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
365 SkXfermode*, const uint16_t indices[], int indexCount,
366 const SkPaint& paint) {
367 addDrawCommand(new DrawVertices(vmode, vertexCount, vertices, texs, colors,
368 NULL, indices, indexCount, paint));
369}
370
371void SkDebugCanvas::restore() {
372 addDrawCommand(new Restore());
373}
374
375bool SkDebugCanvas::rotate(SkScalar degrees) {
376 addDrawCommand(new Rotate(degrees));
377 return true;
378}
379
380int SkDebugCanvas::save(SaveFlags flags) {
381 addDrawCommand(new Save(flags));
382 return true;
383}
384
385int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
386 SaveFlags flags) {
387 addDrawCommand(new SaveLayer(bounds, paint, flags));
388 return true;
389}
390
391bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
392 addDrawCommand(new Scale(sx, sy));
393 return true;
394}
395
396void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
397 addDrawCommand(new SetMatrix(matrix));
398}
399
400bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
401 addDrawCommand(new Skew(sx, sy));
402 return true;
403}
404
405bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
406 addDrawCommand(new Translate(dx, dy));
407 return true;
408}
409
chudy@google.com902ebe52012-06-29 14:21:22 +0000410void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000411 SkASSERT(index < fCommandVector.count());
412 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000413}