blob: 47b82d1740179fe368cf44a7f32bc51aaf8ec92e [file] [log] [blame]
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +00008#include "SkDebugCanvas.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +00009#include "SkDevice.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000010#include "SkGraphics.h"
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000011#include "SkImageDecoder.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +000012#include "SkImageEncoder.h"
djsollen@google.coma09e8832012-11-13 18:50:33 +000013#include "SkOSFile.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000014#include "SkPicture.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +000015#include "SkPicturePlayback.h"
16#include "SkPictureRecord.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000017#include "SkStream.h"
djsollen@google.coma09e8832012-11-13 18:50:33 +000018#include "picture_utils.h"
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000019#include "path_utils.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000020
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000021static void usage() {
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000022 SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +000023 SkDebugf(" [-h|--help]\n\n");
robertphillips@google.com2e87ba02013-04-08 15:45:30 +000024 SkDebugf(" -i inFile : file to filter.\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000025 SkDebugf(" -o outFile : result of filtering.\n");
djsollen@google.coma09e8832012-11-13 18:50:33 +000026 SkDebugf(" --input-dir : process all files in dir with .skp extension.\n");
27 SkDebugf(" --output-dir : results of filtering the input dir.\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000028 SkDebugf(" -h|--help : Show this help message.\n");
29}
30
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +000031// Is the supplied paint simply a color?
32static bool is_simple(const SkPaint& p) {
33 return NULL == p.getPathEffect() &&
34 NULL == p.getShader() &&
35 NULL == p.getXfermode() &&
36 NULL == p.getMaskFilter() &&
37 NULL == p.getColorFilter() &&
38 NULL == p.getRasterizer() &&
39 NULL == p.getLooper() &&
40 NULL == p.getImageFilter();
41}
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000042
robertphillips@google.com50c84da2013-04-01 18:18:49 +000043
robertphillips@google.com73743552013-02-05 20:51:49 +000044// Check for:
45// SAVE_LAYER
46// DRAW_BITMAP_RECT_TO_RECT
47// RESTORE
48// where the saveLayer's color can be moved into the drawBitmapRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +000049static bool check_0(SkDebugCanvas* canvas, int curCommand) {
50 if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
51 canvas->getSize() <= curCommand+2 ||
52 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
53 RESTORE != canvas->getDrawCommandAt(curCommand+2)->getType()) {
robertphillips@google.com73743552013-02-05 20:51:49 +000054 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +000055 }
robertphillips@google.com73743552013-02-05 20:51:49 +000056
robertphillips@google.com50c84da2013-04-01 18:18:49 +000057 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
58 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+1);
robertphillips@google.com73743552013-02-05 20:51:49 +000059
60 const SkPaint* saveLayerPaint = saveLayer->paint();
61 SkPaint* dbmrPaint = dbmr->paint();
62
skia.committer@gmail.com3d18d062013-02-14 07:01:34 +000063 // For this optimization we only fold the saveLayer and drawBitmapRect
robertphillips@google.comc5257042013-04-02 15:30:03 +000064 // together if the saveLayer's draw is simple (i.e., no fancy effects)
65 // and the only difference in the colors is their alpha value
robertphillips@google.com1780a3c2013-02-13 13:27:44 +000066 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
robertphillips@google.comc5257042013-04-02 15:30:03 +000067 SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaque
robertphillips@google.com1780a3c2013-02-13 13:27:44 +000068
robertphillips@google.comc5257042013-04-02 15:30:03 +000069 // If either operation lacks a paint then the collapse is trivial
robertphillips@google.com73743552013-02-05 20:51:49 +000070 return NULL == saveLayerPaint ||
71 NULL == dbmrPaint ||
robertphillips@google.comc5257042013-04-02 15:30:03 +000072 (is_simple(*saveLayerPaint) && dbmrColor == layerColor);
robertphillips@google.com73743552013-02-05 20:51:49 +000073}
74
75// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
76// and restore
robertphillips@google.com50c84da2013-04-01 18:18:49 +000077static void apply_0(SkDebugCanvas* canvas, int curCommand) {
78 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +000079 const SkPaint* saveLayerPaint = saveLayer->paint();
robertphillips@google.com73743552013-02-05 20:51:49 +000080
robertphillips@google.com50c84da2013-04-01 18:18:49 +000081 // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +000082 if (NULL != saveLayerPaint) {
robertphillips@google.com50c84da2013-04-01 18:18:49 +000083 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+1);
84 SkPaint* dbmrPaint = dbmr->paint();
85
86 if (NULL == dbmrPaint) {
87 // if the DBMR doesn't have a paint just use the saveLayer's
88 dbmr->setPaint(*saveLayerPaint);
89 } else if (NULL != saveLayerPaint) {
robertphillips@google.comc5257042013-04-02 15:30:03 +000090 // Both paints are present so their alphas need to be combined
91 SkColor color = saveLayerPaint->getColor();
92 int a0 = SkColorGetA(color);
93
94 color = dbmrPaint->getColor();
95 int a1 = SkColorGetA(color);
96
97 int newA = SkMulDiv255Round(a0, a1);
98 SkASSERT(newA <= 0xFF);
99
100 SkColor newColor = SkColorSetA(color, newA);
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000101 dbmrPaint->setColor(newColor);
102 }
robertphillips@google.com73743552013-02-05 20:51:49 +0000103 }
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000104
105 canvas->deleteDrawCommandAt(curCommand+2); // restore
106 canvas->deleteDrawCommandAt(curCommand); // saveLayer
robertphillips@google.com73743552013-02-05 20:51:49 +0000107}
108
109// Check for:
110// SAVE_LAYER
111// SAVE
112// CLIP_RECT
113// DRAW_BITMAP_RECT_TO_RECT
114// RESTORE
115// RESTORE
116// where the saveLayer's color can be moved into the drawBitmapRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000117static bool check_1(SkDebugCanvas* canvas, int curCommand) {
118 if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
119 canvas->getSize() <= curCommand+5 ||
120 SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() ||
121 CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
122 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() ||
123 RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() ||
124 RESTORE != canvas->getDrawCommandAt(curCommand+5)->getType()) {
robertphillips@google.com73743552013-02-05 20:51:49 +0000125 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000126 }
robertphillips@google.com73743552013-02-05 20:51:49 +0000127
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000128 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
129 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+3);
robertphillips@google.com73743552013-02-05 20:51:49 +0000130
131 const SkPaint* saveLayerPaint = saveLayer->paint();
132 SkPaint* dbmrPaint = dbmr->paint();
133
skia.committer@gmail.com3d18d062013-02-14 07:01:34 +0000134 // For this optimization we only fold the saveLayer and drawBitmapRect
robertphillips@google.com1780a3c2013-02-13 13:27:44 +0000135 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
136 // and the only difference in the colors is that the saveLayer's can have
137 // an alpha while the drawBitmapRect's is opaque.
138 // TODO: it should be possible to fold them together even if they both
139 // have different non-255 alphas but this is low priority since we have
140 // never seen that case
141 // If either operation lacks a paint then the collapse is trivial
142 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
143
robertphillips@google.com73743552013-02-05 20:51:49 +0000144 return NULL == saveLayerPaint ||
145 NULL == dbmrPaint ||
robertphillips@google.com1780a3c2013-02-13 13:27:44 +0000146 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
robertphillips@google.com73743552013-02-05 20:51:49 +0000147}
148
149// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
150// and restore
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000151static void apply_1(SkDebugCanvas* canvas, int curCommand) {
152 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +0000153 const SkPaint* saveLayerPaint = saveLayer->paint();
robertphillips@google.com73743552013-02-05 20:51:49 +0000154
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000155 // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
156 if (NULL != saveLayerPaint) {
157 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+3);
158 SkPaint* dbmrPaint = dbmr->paint();
159
160 if (NULL == dbmrPaint) {
161 dbmr->setPaint(*saveLayerPaint);
162 } else {
163 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
164 SkColorGetA(saveLayerPaint->getColor()));
165 dbmrPaint->setColor(newColor);
166 }
robertphillips@google.com73743552013-02-05 20:51:49 +0000167 }
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000168
169 canvas->deleteDrawCommandAt(curCommand+5); // restore
170 canvas->deleteDrawCommandAt(curCommand); // saveLayer
robertphillips@google.com73743552013-02-05 20:51:49 +0000171}
172
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000173// Check for:
174// SAVE
175// CLIP_RECT
176// DRAW_RECT
177// RESTORE
178// where the rect is entirely within the clip and the clip is an intersect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000179static bool check_2(SkDebugCanvas* canvas, int curCommand) {
180 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
181 canvas->getSize() <= curCommand+4 ||
182 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
183 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
184 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000185 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000186 }
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000187
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000188 ClipRect* cr = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
189 DrawRectC* dr = (DrawRectC*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000190
191 if (SkRegion::kIntersect_Op != cr->op()) {
192 return false;
193 }
194
195 return cr->rect().contains(dr->rect());
196}
197
198// Remove everything but the drawRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000199static void apply_2(SkDebugCanvas* canvas, int curCommand) {
200 canvas->deleteDrawCommandAt(curCommand+3); // restore
201 // drawRect
202 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
203 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000204}
205
206// Check for:
207// SAVE
208// CLIP_RRECT
209// DRAW_RECT
210// RESTORE
211// where the rect entirely encloses the clip
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000212static bool check_3(SkDebugCanvas* canvas, int curCommand) {
213 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
214 canvas->getSize() <= curCommand+4 ||
215 CLIP_RRECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
216 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
217 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000218 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000219 }
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000220
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000221 ClipRRect* crr = (ClipRRect*) canvas->getDrawCommandAt(curCommand+1);
222 DrawRectC* dr = (DrawRectC*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000223
224 if (SkRegion::kIntersect_Op != crr->op()) {
225 return false;
226 }
227
228 return dr->rect().contains(crr->rrect().rect());
229}
230
231// Replace everything with a drawRRect with the paint from the drawRect
232// and the AA settings from the clipRRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000233static void apply_3(SkDebugCanvas* canvas, int curCommand) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000234
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000235 canvas->deleteDrawCommandAt(curCommand+3); // restore
236
237 ClipRRect* crr = (ClipRRect*) canvas->getDrawCommandAt(curCommand+1);
238 DrawRectC* dr = (DrawRectC*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000239
240 // TODO: could skip paint re-creation if the AA settings already match
robertphillips@google.com91217d02013-03-17 18:33:46 +0000241 SkPaint newPaint = dr->paint();
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000242 newPaint.setAntiAlias(crr->doAA());
243 DrawRRect* drr = new DrawRRect(crr->rrect(), newPaint);
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000244 canvas->setDrawCommandAt(curCommand+2, drr);
245
246 canvas->deleteDrawCommandAt(curCommand+1); // clipRRect
247 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000248}
249
250// Check for:
251// SAVE
252// CLIP_RECT
253// DRAW_BITMAP_RECT_TO_RECT
254// RESTORE
255// where the rect and drawBitmapRect dst exactly match
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000256static bool check_4(SkDebugCanvas* canvas, int curCommand) {
257 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
258 canvas->getSize() <= curCommand+4 ||
259 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
260 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
261 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000262 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000263 }
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000264
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000265 ClipRect* cr = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
266 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000267
268 if (SkRegion::kIntersect_Op != cr->op()) {
269 return false;
270 }
271
272 return dbmr->dstRect() == cr->rect();
273}
274
275// Remove everything but the drawBitmapRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000276static void apply_4(SkDebugCanvas* canvas, int curCommand) {
277 canvas->deleteDrawCommandAt(curCommand+3); // restore
278 // drawBitmapRectToRect
279 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
280 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000281}
282
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000283// Check for:
284// TRANSLATE
285// where the translate is zero
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000286static bool check_5(SkDebugCanvas* canvas, int curCommand) {
287 if (TRANSLATE != canvas->getDrawCommandAt(curCommand)->getType()) {
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000288 return false;
289 }
290
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000291 Translate* t = (Translate*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000292
293 return 0 == t->x() && 0 == t->y();
294}
295
296// Just remove the translate
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000297static void apply_5(SkDebugCanvas* canvas, int curCommand) {
298 canvas->deleteDrawCommandAt(curCommand); // translate
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000299}
300
301// Check for:
302// SCALE
303// where the scale is 1,1
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000304static bool check_6(SkDebugCanvas* canvas, int curCommand) {
305 if (SCALE != canvas->getDrawCommandAt(curCommand)->getType()) {
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000306 return false;
307 }
308
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000309 Scale* s = (Scale*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000310
311 return SK_Scalar1 == s->x() && SK_Scalar1 == s->y();
312}
313
314// Just remove the scale
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000315static void apply_6(SkDebugCanvas* canvas, int curCommand) {
316 canvas->deleteDrawCommandAt(curCommand); // scale
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000317}
318
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000319// Check for:
320// SAVE
321// CLIP_RECT
322// SAVE_LAYER
323// SAVE
324// CLIP_RECT
325// SAVE_LAYER
326// SAVE
327// CLIP_RECT
328// DRAWBITMAPRECTTORECT
329// RESTORE
330// RESTORE
331// RESTORE
332// RESTORE
333// RESTORE
334// where:
335// all the clipRect's are BW, nested, intersections
336// the drawBitmapRectToRect is a 1-1 copy from src to dest
337// the last (smallest) clip rect is a subset of the drawBitmapRectToRect's dest rect
338// all the saveLayer's paints can be rolled into the drawBitmapRectToRect's paint
339// This pattern is used by Google spreadsheet when drawing the toolbar buttons
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000340static bool check_7(SkDebugCanvas* canvas, int curCommand) {
341 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
342 canvas->getSize() <= curCommand+13 ||
343 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
344 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+2)->getType() ||
345 SAVE != canvas->getDrawCommandAt(curCommand+3)->getType() ||
346 CLIP_RECT != canvas->getDrawCommandAt(curCommand+4)->getType() ||
347 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+5)->getType() ||
348 SAVE != canvas->getDrawCommandAt(curCommand+6)->getType() ||
349 CLIP_RECT != canvas->getDrawCommandAt(curCommand+7)->getType() ||
350 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+8)->getType() ||
351 RESTORE != canvas->getDrawCommandAt(curCommand+9)->getType() ||
352 RESTORE != canvas->getDrawCommandAt(curCommand+10)->getType() ||
353 RESTORE != canvas->getDrawCommandAt(curCommand+11)->getType() ||
354 RESTORE != canvas->getDrawCommandAt(curCommand+12)->getType() ||
355 RESTORE != canvas->getDrawCommandAt(curCommand+13)->getType()) {
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000356 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000357 }
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000358
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000359 ClipRect* clip0 = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
360 SaveLayer* saveLayer0 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+2);
361 ClipRect* clip1 = (ClipRect*) canvas->getDrawCommandAt(curCommand+4);
362 SaveLayer* saveLayer1 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+5);
363 ClipRect* clip2 = (ClipRect*) canvas->getDrawCommandAt(curCommand+7);
364 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+8);
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000365
366 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) {
367 return false;
368 }
369
370 if (SkRegion::kIntersect_Op != clip0->op() ||
371 SkRegion::kIntersect_Op != clip1->op() ||
372 SkRegion::kIntersect_Op != clip2->op()) {
373 return false;
374 }
375
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000376 if (!clip0->rect().contains(clip1->rect()) ||
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000377 !clip1->rect().contains(clip2->rect())) {
378 return false;
379 }
380
381 // The src->dest mapping needs to be 1-to-1
382 if (NULL == dbmr->srcRect()) {
383 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
384 dbmr->bitmap().height() != dbmr->dstRect().height()) {
385 return false;
386 }
387 } else {
388 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
389 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
390 return false;
391 }
392 }
393
394 if (!dbmr->dstRect().contains(clip2->rect())) {
395 return false;
396 }
397
398 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
399 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
400
401 if ((NULL != saveLayerPaint0 && !is_simple(*saveLayerPaint0)) ||
402 (NULL != saveLayerPaint1 && !is_simple(*saveLayerPaint1))) {
403 return false;
404 }
405
406 SkPaint* dbmrPaint = dbmr->paint();
407
408 if (NULL == dbmrPaint) {
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000409 return true;
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000410 }
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000411
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000412 if (NULL != saveLayerPaint0) {
413 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque
414 if (dbmrPaint->getColor() != layerColor0) {
415 return false;
416 }
417 }
418
419 if (NULL != saveLayerPaint1) {
420 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque
421 if (dbmrPaint->getColor() != layerColor1) {
422 return false;
423 }
424 }
425
426 return true;
427}
428
429// Reduce to a single drawBitmapRectToRect call by folding the clipRect's into
430// the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's
431// paint.
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000432static void apply_7(SkDebugCanvas* canvas, int curCommand) {
433 SaveLayer* saveLayer0 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+2);
434 SaveLayer* saveLayer1 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+5);
435 ClipRect* clip2 = (ClipRect*) canvas->getDrawCommandAt(curCommand+7);
436 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+8);
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000437
438 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft;
439 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop;
440
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000441 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000442 clip2->rect().width(), clip2->rect().height());
443
444 dbmr->setSrcRect(newSrc);
445 dbmr->setDstRect(clip2->rect());
446
447 SkColor color = 0xFF000000;
448 int a0, a1;
449
450 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
451 if (NULL != saveLayerPaint0) {
452 color = saveLayerPaint0->getColor();
453 a0 = SkColorGetA(color);
454 } else {
455 a0 = 0xFF;
456 }
457
458 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
459 if (NULL != saveLayerPaint1) {
460 color = saveLayerPaint1->getColor();
461 a1 = SkColorGetA(color);
462 } else {
463 a1 = 0xFF;
464 }
465
robertphillips@google.comc5257042013-04-02 15:30:03 +0000466 int newA = SkMulDiv255Round(a0, a1);
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000467 SkASSERT(newA <= 0xFF);
468
469 SkPaint* dbmrPaint = dbmr->paint();
470
471 if (NULL != dbmrPaint) {
472 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA);
473 dbmrPaint->setColor(newColor);
474 } else {
475 SkColor newColor = SkColorSetA(color, newA);
476
477 SkPaint newPaint;
478 newPaint.setColor(newColor);
479 dbmr->setPaint(newPaint);
480 }
481
482 // remove everything except the drawbitmaprect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000483 canvas->deleteDrawCommandAt(curCommand+13); // restore
484 canvas->deleteDrawCommandAt(curCommand+12); // restore
485 canvas->deleteDrawCommandAt(curCommand+11); // restore
486 canvas->deleteDrawCommandAt(curCommand+10); // restore
487 canvas->deleteDrawCommandAt(curCommand+9); // restore
488 canvas->deleteDrawCommandAt(curCommand+7); // clipRect
489 canvas->deleteDrawCommandAt(curCommand+6); // save
490 canvas->deleteDrawCommandAt(curCommand+5); // saveLayer
491 canvas->deleteDrawCommandAt(curCommand+4); // clipRect
492 canvas->deleteDrawCommandAt(curCommand+3); // save
493 canvas->deleteDrawCommandAt(curCommand+2); // saveLayer
494 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
495 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000496}
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000497
commit-bot@chromium.org3bdf1642013-04-01 21:00:27 +0000498// Check for:
499// SAVE
500// CLIP_RECT
501// DRAWBITMAPRECTTORECT
502// RESTORE
503// where:
504// the drawBitmapRectToRect is a 1-1 copy from src to dest
505// the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect
506static bool check_8(SkDebugCanvas* canvas, int curCommand) {
507 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
508 canvas->getSize() <= curCommand+4 ||
509 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
510 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
511 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
512 return false;
513 }
514
515 ClipRect* clip = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
516 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
517
518 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
519 return false;
520 }
521
522 // The src->dest mapping needs to be 1-to-1
523 if (NULL == dbmr->srcRect()) {
524 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
525 dbmr->bitmap().height() != dbmr->dstRect().height()) {
526 return false;
527 }
528 } else {
529 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
530 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
531 return false;
532 }
533 }
534
535 if (!dbmr->dstRect().contains(clip->rect())) {
536 return false;
537 }
538
539 return true;
540}
541
542// Fold the clipRect into the drawBitmapRectToRect's src and dest rects
543static void apply_8(SkDebugCanvas* canvas, int curCommand) {
544 ClipRect* clip = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
545 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
546
547 SkScalar newSrcLeft, newSrcTop;
548
549 if (NULL != dbmr->srcRect()) {
550 newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect().fLeft;
551 newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect().fTop;
552 } else {
553 newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft;
554 newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop;
555 }
556
557 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
558 clip->rect().width(), clip->rect().height());
559
560 dbmr->setSrcRect(newSrc);
561 dbmr->setDstRect(clip->rect());
562
563 // remove everything except the drawbitmaprect
564 canvas->deleteDrawCommandAt(curCommand+3);
565 canvas->deleteDrawCommandAt(curCommand+1);
566 canvas->deleteDrawCommandAt(curCommand);
567}
568
569// Check for:
570// SAVE
571// CLIP_RECT
572// DRAWBITMAPRECTTORECT
573// RESTORE
574// where:
575// clipRect is BW and encloses the DBMR2R's dest rect
576static bool check_9(SkDebugCanvas* canvas, int curCommand) {
577 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
578 canvas->getSize() <= curCommand+4 ||
579 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
580 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
581 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
582 return false;
583 }
584
585 ClipRect* clip = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
586 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
587
588 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
589 return false;
590 }
591
592 if (!clip->rect().contains(dbmr->dstRect())) {
593 return false;
594 }
595
596 return true;
597}
598
599// remove everything except the drawbitmaprect
600static void apply_9(SkDebugCanvas* canvas, int curCommand) {
601 canvas->deleteDrawCommandAt(curCommand+3); // restore
602 // drawBitmapRectToRect
603 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
604 canvas->deleteDrawCommandAt(curCommand); // save
605}
606
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000607typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand);
608typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +0000609
610struct OptTableEntry {
611 PFCheck fCheck;
612 PFApply fApply;
613 int fNumTimesApplied;
614} gOptTable[] = {
615 { check_0, apply_0, 0 },
616 { check_1, apply_1, 0 },
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000617 { check_2, apply_2, 0 },
618 { check_3, apply_3, 0 },
619 { check_4, apply_4, 0 },
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000620 { check_5, apply_5, 0 },
621 { check_6, apply_6, 0 },
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000622 { check_7, apply_7, 0 },
commit-bot@chromium.org3bdf1642013-04-01 21:00:27 +0000623 { check_8, apply_8, 0 },
624 { check_9, apply_9, 0 },
robertphillips@google.com73743552013-02-05 20:51:49 +0000625};
626
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000627
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000628static int filter_picture(const SkString& inFile, const SkString& outFile) {
robertphillips@google.com4d98b742013-05-10 14:51:54 +0000629 SkAutoTDelete<SkPicture> inPicture;
djsollen@google.coma09e8832012-11-13 18:50:33 +0000630
631 SkFILEStream inStream(inFile.c_str());
632 if (inStream.isValid()) {
robertphillips@google.com4d98b742013-05-10 14:51:54 +0000633 inPicture.reset(SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeMemory)));
djsollen@google.coma09e8832012-11-13 18:50:33 +0000634 }
635
robertphillips@google.com4d98b742013-05-10 14:51:54 +0000636 if (NULL == inPicture.get()) {
djsollen@google.coma09e8832012-11-13 18:50:33 +0000637 SkDebugf("Could not read file %s\n", inFile.c_str());
638 return -1;
639 }
640
robertphillips@google.com73743552013-02-05 20:51:49 +0000641 int localCount[SK_ARRAY_COUNT(gOptTable)];
642
643 memset(localCount, 0, sizeof(localCount));
644
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000645 SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
646 debugCanvas.setBounds(inPicture->width(), inPicture->height());
647 inPicture->draw(&debugCanvas);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000648
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000649 // delete the initial save and restore since replaying the commands will
robertphillips@google.com73743552013-02-05 20:51:49 +0000650 // re-add them
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000651 if (debugCanvas.getSize() > 1) {
652 debugCanvas.deleteDrawCommandAt(0);
653 debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1);
robertphillips@google.com73743552013-02-05 20:51:49 +0000654 }
655
robertphillips@google.comd9c18532013-04-01 19:10:21 +0000656 bool changed = true;
robertphillips@google.com2e87ba02013-04-08 15:45:30 +0000657 int numBefore = debugCanvas.getSize();
robertphillips@google.comd9c18532013-04-01 19:10:21 +0000658
659 while (changed) {
660 changed = false;
661 for (int i = 0; i < debugCanvas.getSize(); ++i) {
662 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
663 if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) {
664 (*gOptTable[opt].fApply)(&debugCanvas, i);
665
666 ++gOptTable[opt].fNumTimesApplied;
667 ++localCount[opt];
668
669 if (debugCanvas.getSize() == i) {
670 // the optimization removed all the remaining operations
671 break;
672 }
673
674 opt = 0; // try all the opts all over again
675 changed = true;
676 }
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000677 }
678 }
679 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000680
robertphillips@google.com2e87ba02013-04-08 15:45:30 +0000681 int numAfter = debugCanvas.getSize();
682
djsollen@google.coma09e8832012-11-13 18:50:33 +0000683 if (!outFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000684 SkPicture outPicture;
685
686 SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
687 debugCanvas.draw(canvas);
688 outPicture.endRecording();
689
djsollen@google.coma09e8832012-11-13 18:50:33 +0000690 SkFILEWStream outStream(outFile.c_str());
691
692 outPicture.serialize(&outStream);
693 }
694
robertphillips@google.com73743552013-02-05 20:51:49 +0000695 bool someOptFired = false;
696 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
697 if (0 != localCount[opt]) {
698 SkDebugf("%d: %d ", opt, localCount[opt]);
699 someOptFired = true;
700 }
701 }
702
703 if (!someOptFired) {
704 SkDebugf("No opts fired\n");
705 } else {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000706 SkDebugf("\t before: %d after: %d delta: %d\n",
robertphillips@google.com2e87ba02013-04-08 15:45:30 +0000707 numBefore, numAfter, numBefore-numAfter);
robertphillips@google.com73743552013-02-05 20:51:49 +0000708 }
709
djsollen@google.coma09e8832012-11-13 18:50:33 +0000710 return 0;
711}
712
tfarina@chromium.orga5b7cc02012-10-08 14:41:10 +0000713// This function is not marked as 'static' so it can be referenced externally
714// in the iOS build.
humper@google.com05af1af2013-01-07 16:47:43 +0000715int tool_main(int argc, char** argv); // suppress a warning on mac
716
caryclark@google.com9598f422012-10-09 12:32:37 +0000717int tool_main(int argc, char** argv) {
robertphillips@google.com4d98b742013-05-10 14:51:54 +0000718#if SK_ENABLE_INST_COUNT
719 gPrintInstCount = true;
720#endif
721
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000722 SkGraphics::Init();
723
robertphillips@google.com801cee12012-10-19 19:06:11 +0000724 if (argc < 3) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000725 usage();
726 return -1;
727 }
728
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000729 SkString inFile, outFile, inDir, outDir;
robertphillips@google.com801cee12012-10-19 19:06:11 +0000730
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000731 char* const* stop = argv + argc;
732 for (++argv; argv < stop; ++argv) {
733 if (strcmp(*argv, "-i") == 0) {
734 argv++;
735 if (argv < stop && **argv) {
736 inFile.set(*argv);
737 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000738 SkDebugf("missing arg for -i\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000739 usage();
740 return -1;
741 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000742 } else if (strcmp(*argv, "--input-dir") == 0) {
743 argv++;
744 if (argv < stop && **argv) {
745 inDir.set(*argv);
746 } else {
747 SkDebugf("missing arg for --input-dir\n");
748 usage();
749 return -1;
750 }
751 } else if (strcmp(*argv, "--output-dir") == 0) {
752 argv++;
753 if (argv < stop && **argv) {
754 outDir.set(*argv);
755 } else {
756 SkDebugf("missing arg for --output-dir\n");
757 usage();
758 return -1;
759 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000760 } else if (strcmp(*argv, "-o") == 0) {
761 argv++;
762 if (argv < stop && **argv) {
763 outFile.set(*argv);
764 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000765 SkDebugf("missing arg for -o\n");
766 usage();
767 return -1;
768 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000769 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
770 usage();
771 return 0;
772 } else {
773 SkDebugf("unknown arg %s\n", *argv);
774 usage();
775 return -1;
776 }
777 }
778
djsollen@google.coma09e8832012-11-13 18:50:33 +0000779 SkOSFile::Iter iter(inDir.c_str(), "skp");
humper@google.com05af1af2013-01-07 16:47:43 +0000780
djsollen@google.coma09e8832012-11-13 18:50:33 +0000781 SkString inputFilename, outputFilename;
782 if (iter.next(&inputFilename)) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000783
djsollen@google.coma09e8832012-11-13 18:50:33 +0000784 do {
785 sk_tools::make_filepath(&inFile, inDir, inputFilename);
786 if (!outDir.isEmpty()) {
787 sk_tools::make_filepath(&outFile, outDir, inputFilename);
788 }
789 SkDebugf("Executing %s\n", inputFilename.c_str());
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000790 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000791 } while(iter.next(&inputFilename));
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000792
djsollen@google.coma09e8832012-11-13 18:50:33 +0000793 } else if (!inFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000794 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000795 } else {
796 usage();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000797 return -1;
798 }
799
robertphillips@google.com73743552013-02-05 20:51:49 +0000800 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
801 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
802 }
803
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000804 SkGraphics::Term();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000805 return 0;
806}
807
808#if !defined SK_BUILD_FOR_IOS
809int main(int argc, char * const argv[]) {
caryclark@google.com9598f422012-10-09 12:32:37 +0000810 return tool_main(argc, (char**) argv);
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000811}
812#endif