blob: 0cf56a8259192938f85ec6e3f6c5a58e7af082a2 [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.comc7e4a5a2012-10-04 13:00:33 +000024 SkDebugf(" -i inFile : file to file.\n");
25 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.com73743552013-02-05 20:51:49 +000043// Check for:
44// SAVE_LAYER
45// DRAW_BITMAP_RECT_TO_RECT
46// RESTORE
47// where the saveLayer's color can be moved into the drawBitmapRect
48static bool check_0(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
49 if (SAVE_LAYER != commands[curCommand]->getType() ||
50 commands.count() <= curCommand+2 ||
51 DRAW_BITMAP_RECT_TO_RECT != commands[curCommand+1]->getType() ||
52 RESTORE != commands[curCommand+2]->getType())
53 return false;
54
55 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
56 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+1];
57
58 const SkPaint* saveLayerPaint = saveLayer->paint();
59 SkPaint* dbmrPaint = dbmr->paint();
60
61 return NULL == saveLayerPaint ||
62 NULL == dbmrPaint ||
63 (is_simple(*saveLayerPaint) &&
64 (SkColorGetR(saveLayerPaint->getColor()) == SkColorGetR(dbmrPaint->getColor())) &&
65 (SkColorGetG(saveLayerPaint->getColor()) == SkColorGetG(dbmrPaint->getColor())) &&
66 (SkColorGetB(saveLayerPaint->getColor()) == SkColorGetB(dbmrPaint->getColor())));
67}
68
69// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
70// and restore
71static void apply_0(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
72 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
73 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+1];
74 Restore* restore = (Restore*) commands[curCommand+2];
75
76 const SkPaint* saveLayerPaint = saveLayer->paint();
77 SkPaint* dbmrPaint = dbmr->paint();
78
79 if (NULL == saveLayerPaint) {
80 saveLayer->setVisible(false);
81 restore->setVisible(false);
82 } else if (NULL == dbmrPaint) {
83 saveLayer->setVisible(false);
84 dbmr->setPaint(*saveLayerPaint);
85 restore->setVisible(false);
86 } else {
87 saveLayer->setVisible(false);
88 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
89 SkColorGetA(saveLayerPaint->getColor()));
90 dbmrPaint->setColor(newColor);
91 restore->setVisible(false);
92 }
93}
94
95// Check for:
96// SAVE_LAYER
97// SAVE
98// CLIP_RECT
99// DRAW_BITMAP_RECT_TO_RECT
100// RESTORE
101// RESTORE
102// where the saveLayer's color can be moved into the drawBitmapRect
103static bool check_1(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
104 if (SAVE_LAYER != commands[curCommand]->getType() ||
105 commands.count() <= curCommand+5 ||
106 SAVE != commands[curCommand+1]->getType() ||
107 CLIP_RECT != commands[curCommand+2]->getType() ||
108 DRAW_BITMAP_RECT_TO_RECT != commands[curCommand+3]->getType() ||
109 RESTORE != commands[curCommand+4]->getType() ||
110 RESTORE != commands[curCommand+5]->getType())
111 return false;
112
113 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
114 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+3];
115
116 const SkPaint* saveLayerPaint = saveLayer->paint();
117 SkPaint* dbmrPaint = dbmr->paint();
118
119 return NULL == saveLayerPaint ||
120 NULL == dbmrPaint ||
121 (is_simple(*saveLayerPaint) &&
122 (SkColorGetR(saveLayerPaint->getColor()) == SkColorGetR(dbmrPaint->getColor())) &&
123 (SkColorGetG(saveLayerPaint->getColor()) == SkColorGetG(dbmrPaint->getColor())) &&
124 (SkColorGetB(saveLayerPaint->getColor()) == SkColorGetB(dbmrPaint->getColor())));
125}
126
127// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
128// and restore
129static void apply_1(const SkTDArray<SkDrawCommand*>& commands, int curCommand) {
130 SaveLayer* saveLayer = (SaveLayer*) commands[curCommand];
131 DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[curCommand+3];
132 Restore* restore = (Restore*) commands[curCommand+5];
133
134 const SkPaint* saveLayerPaint = saveLayer->paint();
135 SkPaint* dbmrPaint = dbmr->paint();
136
137 if (NULL == saveLayerPaint) {
138 saveLayer->setVisible(false);
139 restore->setVisible(false);
140 } else if (NULL == dbmrPaint) {
141 saveLayer->setVisible(false);
142 dbmr->setPaint(*saveLayerPaint);
143 restore->setVisible(false);
144 } else {
145 saveLayer->setVisible(false);
146 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
147 SkColorGetA(saveLayerPaint->getColor()));
148 dbmrPaint->setColor(newColor);
149 restore->setVisible(false);
150 }
151}
152
153typedef bool (*PFCheck)(const SkTDArray<SkDrawCommand*>& commands, int curCommand);
154typedef void (*PFApply)(const SkTDArray<SkDrawCommand*>& commands, int curCommand);
155
156struct OptTableEntry {
157 PFCheck fCheck;
158 PFApply fApply;
159 int fNumTimesApplied;
160} gOptTable[] = {
161 { check_0, apply_0, 0 },
162 { check_1, apply_1, 0 },
163};
164
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000165static int filter_picture(const SkString& inFile, const SkString& outFile) {
djsollen@google.coma09e8832012-11-13 18:50:33 +0000166 SkPicture* inPicture = NULL;
167
168 SkFILEStream inStream(inFile.c_str());
169 if (inStream.isValid()) {
170 inPicture = SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeStream));
171 }
172
173 if (NULL == inPicture) {
174 SkDebugf("Could not read file %s\n", inFile.c_str());
175 return -1;
176 }
177
robertphillips@google.com73743552013-02-05 20:51:49 +0000178 int localCount[SK_ARRAY_COUNT(gOptTable)];
179
180 memset(localCount, 0, sizeof(localCount));
181
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000182 SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
183 debugCanvas.setBounds(inPicture->width(), inPicture->height());
184 inPicture->draw(&debugCanvas);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000185
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000186 const SkTDArray<SkDrawCommand*>& commands = debugCanvas.getDrawCommands();
djsollen@google.coma09e8832012-11-13 18:50:33 +0000187
robertphillips@google.com73743552013-02-05 20:51:49 +0000188 // hide the initial save and restore since replaying the commands will
189 // re-add them
190 if (commands.count() > 0) {
191 commands[0]->setVisible(false);
192 commands[commands.count()-1]->setVisible(false);
193 }
194
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000195 for (int i = 0; i < commands.count(); ++i) {
robertphillips@google.com73743552013-02-05 20:51:49 +0000196 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
197 if ((*gOptTable[opt].fCheck)(commands, i)) {
198 (*gOptTable[opt].fApply)(commands, i);
199 ++gOptTable[opt].fNumTimesApplied;
200 ++localCount[opt];
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000201 }
202 }
203 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000204
205 if (!outFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000206 SkPicture outPicture;
207
208 SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
209 debugCanvas.draw(canvas);
210 outPicture.endRecording();
211
djsollen@google.coma09e8832012-11-13 18:50:33 +0000212 SkFILEWStream outStream(outFile.c_str());
213
214 outPicture.serialize(&outStream);
215 }
216
robertphillips@google.com73743552013-02-05 20:51:49 +0000217 bool someOptFired = false;
218 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
219 if (0 != localCount[opt]) {
220 SkDebugf("%d: %d ", opt, localCount[opt]);
221 someOptFired = true;
222 }
223 }
224
225 if (!someOptFired) {
226 SkDebugf("No opts fired\n");
227 } else {
228 SkDebugf("\n");
229 }
230
djsollen@google.coma09e8832012-11-13 18:50:33 +0000231 return 0;
232}
233
tfarina@chromium.orga5b7cc02012-10-08 14:41:10 +0000234// This function is not marked as 'static' so it can be referenced externally
235// in the iOS build.
humper@google.com05af1af2013-01-07 16:47:43 +0000236int tool_main(int argc, char** argv); // suppress a warning on mac
237
caryclark@google.com9598f422012-10-09 12:32:37 +0000238int tool_main(int argc, char** argv) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000239 SkGraphics::Init();
240
robertphillips@google.com801cee12012-10-19 19:06:11 +0000241 if (argc < 3) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000242 usage();
243 return -1;
244 }
245
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000246 SkString inFile, outFile, inDir, outDir;
robertphillips@google.com801cee12012-10-19 19:06:11 +0000247
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000248 char* const* stop = argv + argc;
249 for (++argv; argv < stop; ++argv) {
250 if (strcmp(*argv, "-i") == 0) {
251 argv++;
252 if (argv < stop && **argv) {
253 inFile.set(*argv);
254 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000255 SkDebugf("missing arg for -i\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000256 usage();
257 return -1;
258 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000259 } else if (strcmp(*argv, "--input-dir") == 0) {
260 argv++;
261 if (argv < stop && **argv) {
262 inDir.set(*argv);
263 } else {
264 SkDebugf("missing arg for --input-dir\n");
265 usage();
266 return -1;
267 }
268 } else if (strcmp(*argv, "--output-dir") == 0) {
269 argv++;
270 if (argv < stop && **argv) {
271 outDir.set(*argv);
272 } else {
273 SkDebugf("missing arg for --output-dir\n");
274 usage();
275 return -1;
276 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000277 } else if (strcmp(*argv, "-o") == 0) {
278 argv++;
279 if (argv < stop && **argv) {
280 outFile.set(*argv);
281 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000282 SkDebugf("missing arg for -o\n");
283 usage();
284 return -1;
285 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000286 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
287 usage();
288 return 0;
289 } else {
290 SkDebugf("unknown arg %s\n", *argv);
291 usage();
292 return -1;
293 }
294 }
295
djsollen@google.coma09e8832012-11-13 18:50:33 +0000296 SkOSFile::Iter iter(inDir.c_str(), "skp");
humper@google.com05af1af2013-01-07 16:47:43 +0000297
djsollen@google.coma09e8832012-11-13 18:50:33 +0000298 SkString inputFilename, outputFilename;
299 if (iter.next(&inputFilename)) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000300
djsollen@google.coma09e8832012-11-13 18:50:33 +0000301 do {
302 sk_tools::make_filepath(&inFile, inDir, inputFilename);
303 if (!outDir.isEmpty()) {
304 sk_tools::make_filepath(&outFile, outDir, inputFilename);
305 }
306 SkDebugf("Executing %s\n", inputFilename.c_str());
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000307 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000308 } while(iter.next(&inputFilename));
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000309
djsollen@google.coma09e8832012-11-13 18:50:33 +0000310 } else if (!inFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000311 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000312 } else {
313 usage();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000314 return -1;
315 }
316
robertphillips@google.com73743552013-02-05 20:51:49 +0000317 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
318 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
319 }
320
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000321 SkGraphics::Term();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000322 return 0;
323}
324
325#if !defined SK_BUILD_FOR_IOS
326int main(int argc, char * const argv[]) {
caryclark@google.com9598f422012-10-09 12:32:37 +0000327 return tool_main(argc, (char**) argv);
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000328}
329#endif