blob: beb670b1cb961ad02410847fb796b82020237341 [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
10#include <iostream>
11#include "SkDebugCanvas.h"
12#include "SkDrawCommand.h"
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +000013#include "SkDevice.h"
14#include "SkImageWidget.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000015
reed@google.com6ae24e02012-09-26 13:44:13 +000016static SkBitmap make_noconfig_bm(int width, int height) {
17 SkBitmap bm;
18 bm.setConfig(SkBitmap::kNo_Config, width, height);
19 return bm;
20}
21
22SkDebugCanvas::SkDebugCanvas(int width, int height)
tomhudson@google.com0699e022012-11-27 16:09:42 +000023 : INHERITED(make_noconfig_bm(width, height))
24 , fOutstandingSaveCount(0) {
chudy@google.com902ebe52012-06-29 14:21:22 +000025 // TODO(chudy): Free up memory from all draw commands in destructor.
chudy@google.com80a4a602012-07-30 18:54:07 +000026 fWidth = width;
27 fHeight = height;
reed@google.com6ae24e02012-09-26 13:44:13 +000028 // do we need fBm anywhere?
chudy@google.comb9ddd4e2012-07-10 14:14:50 +000029 fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
chudy@google.com902ebe52012-06-29 14:21:22 +000030 fFilter = false;
chudy@google.com830b8792012-08-01 15:57:52 +000031 fIndex = 0;
32 fUserOffset.set(0,0);
33 fUserScale = 1.0;
chudy@google.com902ebe52012-06-29 14:21:22 +000034}
35
chudy@google.com9cda6f72012-08-07 15:08:33 +000036SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000037 fCommandVector.deleteAll();
chudy@google.com9cda6f72012-08-07 15:08:33 +000038}
chudy@google.com902ebe52012-06-29 14:21:22 +000039
40void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000041 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000042}
43
44void SkDebugCanvas::draw(SkCanvas* canvas) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000045 if(!fCommandVector.isEmpty()) {
46 for (int i = 0; i < fCommandVector.count(); i++) {
47 if (fCommandVector[i]->isVisible()) {
48 fCommandVector[i]->execute(canvas);
chudy@google.com0ab03392012-07-28 20:16:11 +000049 }
chudy@google.com902ebe52012-06-29 14:21:22 +000050 }
51 }
robertphillips@google.com67baba42013-01-02 20:20:31 +000052 fIndex = fCommandVector.count() - 1;
chudy@google.com902ebe52012-06-29 14:21:22 +000053}
54
chudy@google.com830b8792012-08-01 15:57:52 +000055void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
skia.committer@gmail.com04ba4482012-09-07 02:01:30 +000056 canvas->translate(SkIntToScalar(fUserOffset.fX),
robertphillips@google.com94acc702012-09-06 18:43:21 +000057 SkIntToScalar(fUserOffset.fY));
chudy@google.com830b8792012-08-01 15:57:52 +000058 if (fUserScale < 0) {
robertphillips@google.com94acc702012-09-06 18:43:21 +000059 canvas->scale((1.0f / -fUserScale), (1.0f / -fUserScale));
chudy@google.com830b8792012-08-01 15:57:52 +000060 } else if (fUserScale > 0) {
61 canvas->scale(fUserScale, fUserScale);
62 }
63}
64
65int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +000066 SkBitmap bitmap;
67 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
68 bitmap.allocPixels();
chudy@google.com902ebe52012-06-29 14:21:22 +000069
chudy@google.com0b5bbb02012-07-31 19:55:32 +000070 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +000071 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
chudy@google.com830b8792012-08-01 15:57:52 +000072 applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000073
74 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +000075 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000076 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000077 if (fCommandVector[i]->isVisible()) {
78 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000079 }
80 if (prev != bitmap.getColor(0,0)) {
81 layer = i;
82 }
83 prev = bitmap.getColor(0,0);
84 }
85 return layer;
86}
87
88void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
89 int counter = 0;
robertphillips@google.com67baba42013-01-02 20:20:31 +000090 SkASSERT(!fCommandVector.isEmpty());
91 SkASSERT(index < fCommandVector.count());
chudy@google.com830b8792012-08-01 15:57:52 +000092 int i;
93
94 // This only works assuming the canvas and device are the same ones that
95 // were previously drawn into because they need to preserve all saves
96 // and restores.
97 if (fIndex < index) {
98 i = fIndex + 1;
99 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000100 for (int j = 0; j < fOutstandingSaveCount; j++) {
101 canvas->restore();
102 }
chudy@google.com830b8792012-08-01 15:57:52 +0000103 i = 0;
junov@google.comdbfac8a2012-12-06 21:47:40 +0000104 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000105 canvas->resetMatrix();
skia.committer@gmail.com04ba4482012-09-07 02:01:30 +0000106 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth),
robertphillips@google.com94acc702012-09-06 18:43:21 +0000107 SkIntToScalar(fHeight));
chudy@google.com4c7962e2012-08-14 19:38:31 +0000108 canvas->clipRect(rect, SkRegion::kReplace_Op );
chudy@google.com830b8792012-08-01 15:57:52 +0000109 applyUserTransform(canvas);
tomhudson@google.com0699e022012-11-27 16:09:42 +0000110 fOutstandingSaveCount = 0;
chudy@google.com830b8792012-08-01 15:57:52 +0000111 }
112
113 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000114 if (i == index && fFilter) {
115 SkPaint p;
116 p.setColor(0xAAFFFFFF);
117 canvas->save();
118 canvas->resetMatrix();
119 SkRect mask;
120 mask.set(SkIntToScalar(0), SkIntToScalar(0),
121 SkIntToScalar(fWidth), SkIntToScalar(fHeight));
122 canvas->clipRect(mask, SkRegion::kReplace_Op, false);
123 canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
124 SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
125 canvas->restore();
126 }
127
robertphillips@google.com67baba42013-01-02 20:20:31 +0000128 if (fCommandVector[i]->isVisible()) {
129 fCommandVector[i]->execute(canvas);
130 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000131 }
132 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000133 fMatrix = canvas->getTotalMatrix();
134 fClip = canvas->getTotalClip().getBounds();
chudy@google.com830b8792012-08-01 15:57:52 +0000135 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000136}
137
138SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000139 SkASSERT(index < fCommandVector.count());
140 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000141}
142
chudy@google.com97cee972012-08-07 20:41:37 +0000143SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000144 SkASSERT(index < fCommandVector.count());
145 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000146}
chudy@google.com902ebe52012-06-29 14:21:22 +0000147
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000148bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000149 SkASSERT(index < fCommandVector.count());
150 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000151}
152
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000153const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000154 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000155}
156
157// TODO(chudy): Free command string memory.
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000158SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000159 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
160 if (!fCommandVector.isEmpty()) {
161 for (int i = 0; i < fCommandVector.count(); i ++) {
162 commandString->push_back() = fCommandVector[i]->toString();
chudy@google.com902ebe52012-06-29 14:21:22 +0000163 }
164 }
165 return commandString;
166}
167
168void SkDebugCanvas::toggleFilter(bool toggle) {
169 fFilter = toggle;
170}
171
172void SkDebugCanvas::clear(SkColor color) {
173 addDrawCommand(new Clear(color));
174}
175
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000176static SkBitmap createBitmap(const SkPath& path) {
177 SkBitmap bitmap;
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000178 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
179 SkImageWidget::kImageWidgetWidth,
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000180 SkImageWidget::kImageWidgetHeight);
181 bitmap.allocPixels();
182 bitmap.eraseColor(SK_ColorWHITE);
183 SkDevice* device = new SkDevice(bitmap);
184
185 SkCanvas canvas(device);
186 device->unref();
187
188 const SkRect& bounds = path.getBounds();
189
190 if (bounds.width() > bounds.height()) {
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000191 canvas.scale(SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetWidth)/bounds.width()),
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000192 SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetHeight)/bounds.width()));
193 } else {
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000194 canvas.scale(SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetWidth)/bounds.height()),
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +0000195 SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetHeight)/bounds.height()));
196 }
197 canvas.translate(-bounds.fLeft+2, -bounds.fTop+2);
198
199 SkPaint p;
200 p.setColor(SK_ColorBLACK);
201 p.setStyle(SkPaint::kStroke_Style);
202
203 canvas.drawPath(path, p);
204
205 return bitmap;
206}
207
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000208static SkBitmap createBitmap(const SkBitmap& input, const SkRect* srcRect) {
209 SkBitmap bitmap;
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000210 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
211 SkImageWidget::kImageWidgetWidth,
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000212 SkImageWidget::kImageWidgetHeight);
213 bitmap.allocPixels();
214 bitmap.eraseColor(SK_ColorLTGRAY);
215 SkDevice* device = new SkDevice(bitmap);
216
217 SkCanvas canvas(device);
218 device->unref();
219
220 SkScalar xScale = (SkImageWidget::kImageWidgetWidth-2.0) / input.width();
221 SkScalar yScale = (SkImageWidget::kImageWidgetHeight-2.0) / input.height();
222
223 if (input.width() > input.height()) {
224 yScale *= input.height() / (float) input.width();
225 } else {
226 xScale *= input.width() / (float) input.height();
227 }
228
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000229 SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1,
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000230 xScale * input.width(),
231 yScale * input.height());
232
233 canvas.drawBitmapRect(input, NULL, dst);
234
235 if (NULL != srcRect) {
236 SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
237 srcRect->fTop * yScale + SK_Scalar1,
238 srcRect->fRight * xScale + SK_Scalar1,
239 srcRect->fBottom * yScale + SK_Scalar1);
240 SkPaint p;
241 p.setColor(SK_ColorRED);
242 p.setStyle(SkPaint::kStroke_Style);
243
244 canvas.drawRect(r, p);
245 }
246
247 return bitmap;
248}
249
chudy@google.com902ebe52012-06-29 14:21:22 +0000250bool SkDebugCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
rmistry@google.com44737652012-11-21 18:37:58 +0000251 SkBitmap bitmap = createBitmap(path);
252 addDrawCommand(new ClipPath(path, op, doAA, bitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000253 return true;
254}
255
256bool SkDebugCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
257 addDrawCommand(new ClipRect(rect, op, doAA));
258 return true;
259}
260
robertphillips@google.com67baba42013-01-02 20:20:31 +0000261bool SkDebugCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
262 addDrawCommand(new ClipRRect(rrect, op, doAA));
263 return true;
264}
265
chudy@google.com902ebe52012-06-29 14:21:22 +0000266bool SkDebugCanvas::clipRegion(const SkRegion& region, SkRegion::Op op) {
267 addDrawCommand(new ClipRegion(region, op));
268 return true;
269}
270
271bool SkDebugCanvas::concat(const SkMatrix& matrix) {
272 addDrawCommand(new Concat(matrix));
273 return true;
274}
275
276void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
277 SkScalar top, const SkPaint* paint = NULL) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000278 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
279 addDrawCommand(new DrawBitmap(bitmap, left, top, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000280}
281
reed@google.com71121732012-09-18 15:14:33 +0000282void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
283 const SkRect* src, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000284 SkBitmap resizedBitmap = createBitmap(bitmap, src);
285 addDrawCommand(new DrawBitmapRect(bitmap, src, dst, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000286}
287
288void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
289 const SkMatrix& matrix, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000290 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
291 addDrawCommand(new DrawBitmapMatrix(bitmap, matrix, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000292}
293
294void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
295 const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000296 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
297 addDrawCommand(new DrawBitmapNine(bitmap, center, dst, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000298}
299
300void SkDebugCanvas::drawData(const void* data, size_t length) {
301 addDrawCommand(new DrawData(data, length));
302}
303
robertphillips@google.com67baba42013-01-02 20:20:31 +0000304void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
305 addDrawCommand(new DrawOval(oval, paint));
306}
307
chudy@google.com902ebe52012-06-29 14:21:22 +0000308void SkDebugCanvas::drawPaint(const SkPaint& paint) {
309 addDrawCommand(new DrawPaint(paint));
310}
311
312void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
rmistry@google.com44737652012-11-21 18:37:58 +0000313 SkBitmap bitmap = createBitmap(path);
314 addDrawCommand(new DrawPath(path, paint, bitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000315}
316
317void SkDebugCanvas::drawPicture(SkPicture& picture) {
318 addDrawCommand(new DrawPicture(picture));
319}
320
321void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
322 const SkPoint pts[], const SkPaint& paint) {
323 addDrawCommand(new DrawPoints(mode, count, pts, paint));
324}
325
326void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
327 const SkPoint pos[], const SkPaint& paint) {
328 addDrawCommand(new DrawPosText(text, byteLength, pos, paint));
329}
330
331void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
332 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
333 addDrawCommand(new DrawPosTextH(text, byteLength, xpos, constY, paint));
334}
335
336void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
337 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
338 addDrawCommand(new DrawRectC(rect, paint));
339}
340
robertphillips@google.com67baba42013-01-02 20:20:31 +0000341void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
342 addDrawCommand(new DrawRRect(rrect, paint));
343}
344
chudy@google.com902ebe52012-06-29 14:21:22 +0000345void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
346 const SkPaint* paint = NULL) {
robertphillips@google.com53ec73d2012-11-26 13:09:17 +0000347 SkBitmap resizedBitmap = createBitmap(bitmap, NULL);
348 addDrawCommand(new DrawSprite(bitmap, left, top, paint, resizedBitmap));
chudy@google.com902ebe52012-06-29 14:21:22 +0000349}
350
351void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
352 SkScalar y, const SkPaint& paint) {
353 addDrawCommand(new DrawTextC(text, byteLength, x, y, paint));
354}
355
356void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
357 const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
358 addDrawCommand(new DrawTextOnPath(text, byteLength, path, matrix, paint));
359}
360
361void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
362 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
363 SkXfermode*, const uint16_t indices[], int indexCount,
364 const SkPaint& paint) {
365 addDrawCommand(new DrawVertices(vmode, vertexCount, vertices, texs, colors,
366 NULL, indices, indexCount, paint));
367}
368
369void SkDebugCanvas::restore() {
370 addDrawCommand(new Restore());
371}
372
373bool SkDebugCanvas::rotate(SkScalar degrees) {
374 addDrawCommand(new Rotate(degrees));
375 return true;
376}
377
378int SkDebugCanvas::save(SaveFlags flags) {
379 addDrawCommand(new Save(flags));
380 return true;
381}
382
383int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
384 SaveFlags flags) {
385 addDrawCommand(new SaveLayer(bounds, paint, flags));
386 return true;
387}
388
389bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
390 addDrawCommand(new Scale(sx, sy));
391 return true;
392}
393
394void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
395 addDrawCommand(new SetMatrix(matrix));
396}
397
398bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
399 addDrawCommand(new Skew(sx, sy));
400 return true;
401}
402
403bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
404 addDrawCommand(new Translate(dx, dy));
405 return true;
406}
407
chudy@google.com902ebe52012-06-29 14:21:22 +0000408void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000409 SkASSERT(index < fCommandVector.count());
410 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000411}