blob: 58508ff3010564feab713be7be42c644c5aef10c [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.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.com1780a3c2013-02-13 13:27:44 +000064 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
65 // and the only difference in the colors is that the saveLayer's can have
66 // an alpha while the drawBitmapRect's is opaque.
67 // TODO: it should be possible to fold them together even if they both
68 // have different non-255 alphas but this is low priority since we have
69 // never seen that case
70 // If either operation lacks a paint then the collapse is trivial
71 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
72
robertphillips@google.com73743552013-02-05 20:51:49 +000073 return NULL == saveLayerPaint ||
74 NULL == dbmrPaint ||
robertphillips@google.com1780a3c2013-02-13 13:27:44 +000075 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
robertphillips@google.com73743552013-02-05 20:51:49 +000076}
77
78// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
79// and restore
robertphillips@google.com50c84da2013-04-01 18:18:49 +000080static void apply_0(SkDebugCanvas* canvas, int curCommand) {
81 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +000082 const SkPaint* saveLayerPaint = saveLayer->paint();
robertphillips@google.com73743552013-02-05 20:51:49 +000083
robertphillips@google.com50c84da2013-04-01 18:18:49 +000084 // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
85 if (NULL != saveLayerPaint) {
86 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+1);
87 SkPaint* dbmrPaint = dbmr->paint();
88
89 if (NULL == dbmrPaint) {
90 // if the DBMR doesn't have a paint just use the saveLayer's
91 dbmr->setPaint(*saveLayerPaint);
92 } else if (NULL != saveLayerPaint) {
93 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
94 SkColorGetA(saveLayerPaint->getColor()));
95 dbmrPaint->setColor(newColor);
96 }
robertphillips@google.com73743552013-02-05 20:51:49 +000097 }
robertphillips@google.com50c84da2013-04-01 18:18:49 +000098
99 canvas->deleteDrawCommandAt(curCommand+2); // restore
100 canvas->deleteDrawCommandAt(curCommand); // saveLayer
robertphillips@google.com73743552013-02-05 20:51:49 +0000101}
102
103// Check for:
104// SAVE_LAYER
105// SAVE
106// CLIP_RECT
107// DRAW_BITMAP_RECT_TO_RECT
108// RESTORE
109// RESTORE
110// where the saveLayer's color can be moved into the drawBitmapRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000111static bool check_1(SkDebugCanvas* canvas, int curCommand) {
112 if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
113 canvas->getSize() <= curCommand+5 ||
114 SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() ||
115 CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
116 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() ||
117 RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() ||
118 RESTORE != canvas->getDrawCommandAt(curCommand+5)->getType()) {
robertphillips@google.com73743552013-02-05 20:51:49 +0000119 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000120 }
robertphillips@google.com73743552013-02-05 20:51:49 +0000121
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000122 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
123 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+3);
robertphillips@google.com73743552013-02-05 20:51:49 +0000124
125 const SkPaint* saveLayerPaint = saveLayer->paint();
126 SkPaint* dbmrPaint = dbmr->paint();
127
skia.committer@gmail.com3d18d062013-02-14 07:01:34 +0000128 // For this optimization we only fold the saveLayer and drawBitmapRect
robertphillips@google.com1780a3c2013-02-13 13:27:44 +0000129 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
130 // and the only difference in the colors is that the saveLayer's can have
131 // an alpha while the drawBitmapRect's is opaque.
132 // TODO: it should be possible to fold them together even if they both
133 // have different non-255 alphas but this is low priority since we have
134 // never seen that case
135 // If either operation lacks a paint then the collapse is trivial
136 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
137
robertphillips@google.com73743552013-02-05 20:51:49 +0000138 return NULL == saveLayerPaint ||
139 NULL == dbmrPaint ||
robertphillips@google.com1780a3c2013-02-13 13:27:44 +0000140 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
robertphillips@google.com73743552013-02-05 20:51:49 +0000141}
142
143// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
144// and restore
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000145static void apply_1(SkDebugCanvas* canvas, int curCommand) {
146 SaveLayer* saveLayer = (SaveLayer*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +0000147 const SkPaint* saveLayerPaint = saveLayer->paint();
robertphillips@google.com73743552013-02-05 20:51:49 +0000148
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000149 // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
150 if (NULL != saveLayerPaint) {
151 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+3);
152 SkPaint* dbmrPaint = dbmr->paint();
153
154 if (NULL == dbmrPaint) {
155 dbmr->setPaint(*saveLayerPaint);
156 } else {
157 SkColor newColor = SkColorSetA(dbmrPaint->getColor(),
158 SkColorGetA(saveLayerPaint->getColor()));
159 dbmrPaint->setColor(newColor);
160 }
robertphillips@google.com73743552013-02-05 20:51:49 +0000161 }
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000162
163 canvas->deleteDrawCommandAt(curCommand+5); // restore
164 canvas->deleteDrawCommandAt(curCommand); // saveLayer
robertphillips@google.com73743552013-02-05 20:51:49 +0000165}
166
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000167// Check for:
168// SAVE
169// CLIP_RECT
170// DRAW_RECT
171// RESTORE
172// where the rect is entirely within the clip and the clip is an intersect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000173static bool check_2(SkDebugCanvas* canvas, int curCommand) {
174 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
175 canvas->getSize() <= curCommand+4 ||
176 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
177 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
178 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000179 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000180 }
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000181
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000182 ClipRect* cr = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
183 DrawRectC* dr = (DrawRectC*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000184
185 if (SkRegion::kIntersect_Op != cr->op()) {
186 return false;
187 }
188
189 return cr->rect().contains(dr->rect());
190}
191
192// Remove everything but the drawRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000193static void apply_2(SkDebugCanvas* canvas, int curCommand) {
194 canvas->deleteDrawCommandAt(curCommand+3); // restore
195 // drawRect
196 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
197 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000198}
199
200// Check for:
201// SAVE
202// CLIP_RRECT
203// DRAW_RECT
204// RESTORE
205// where the rect entirely encloses the clip
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000206static bool check_3(SkDebugCanvas* canvas, int curCommand) {
207 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
208 canvas->getSize() <= curCommand+4 ||
209 CLIP_RRECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
210 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
211 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000212 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000213 }
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000214
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000215 ClipRRect* crr = (ClipRRect*) canvas->getDrawCommandAt(curCommand+1);
216 DrawRectC* dr = (DrawRectC*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000217
218 if (SkRegion::kIntersect_Op != crr->op()) {
219 return false;
220 }
221
222 return dr->rect().contains(crr->rrect().rect());
223}
224
225// Replace everything with a drawRRect with the paint from the drawRect
226// and the AA settings from the clipRRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000227static void apply_3(SkDebugCanvas* canvas, int curCommand) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000228
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000229 canvas->deleteDrawCommandAt(curCommand+3); // restore
230
231 ClipRRect* crr = (ClipRRect*) canvas->getDrawCommandAt(curCommand+1);
232 DrawRectC* dr = (DrawRectC*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000233
234 // TODO: could skip paint re-creation if the AA settings already match
robertphillips@google.com91217d02013-03-17 18:33:46 +0000235 SkPaint newPaint = dr->paint();
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000236 newPaint.setAntiAlias(crr->doAA());
237 DrawRRect* drr = new DrawRRect(crr->rrect(), newPaint);
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000238 canvas->setDrawCommandAt(curCommand+2, drr);
239
240 canvas->deleteDrawCommandAt(curCommand+1); // clipRRect
241 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000242}
243
244// Check for:
245// SAVE
246// CLIP_RECT
247// DRAW_BITMAP_RECT_TO_RECT
248// RESTORE
249// where the rect and drawBitmapRect dst exactly match
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000250static bool check_4(SkDebugCanvas* canvas, int curCommand) {
251 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
252 canvas->getSize() <= curCommand+4 ||
253 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
254 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
255 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000256 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000257 }
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000258
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000259 ClipRect* cr = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
260 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000261
262 if (SkRegion::kIntersect_Op != cr->op()) {
263 return false;
264 }
265
266 return dbmr->dstRect() == cr->rect();
267}
268
269// Remove everything but the drawBitmapRect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000270static void apply_4(SkDebugCanvas* canvas, int curCommand) {
271 canvas->deleteDrawCommandAt(curCommand+3); // restore
272 // drawBitmapRectToRect
273 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
274 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000275}
276
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000277// Check for:
278// TRANSLATE
279// where the translate is zero
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000280static bool check_5(SkDebugCanvas* canvas, int curCommand) {
281 if (TRANSLATE != canvas->getDrawCommandAt(curCommand)->getType()) {
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000282 return false;
283 }
284
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000285 Translate* t = (Translate*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000286
287 return 0 == t->x() && 0 == t->y();
288}
289
290// Just remove the translate
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000291static void apply_5(SkDebugCanvas* canvas, int curCommand) {
292 canvas->deleteDrawCommandAt(curCommand); // translate
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000293}
294
295// Check for:
296// SCALE
297// where the scale is 1,1
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000298static bool check_6(SkDebugCanvas* canvas, int curCommand) {
299 if (SCALE != canvas->getDrawCommandAt(curCommand)->getType()) {
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000300 return false;
301 }
302
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000303 Scale* s = (Scale*) canvas->getDrawCommandAt(curCommand);
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000304
305 return SK_Scalar1 == s->x() && SK_Scalar1 == s->y();
306}
307
308// Just remove the scale
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000309static void apply_6(SkDebugCanvas* canvas, int curCommand) {
310 canvas->deleteDrawCommandAt(curCommand); // scale
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000311}
312
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000313// Check for:
314// SAVE
315// CLIP_RECT
316// SAVE_LAYER
317// SAVE
318// CLIP_RECT
319// SAVE_LAYER
320// SAVE
321// CLIP_RECT
322// DRAWBITMAPRECTTORECT
323// RESTORE
324// RESTORE
325// RESTORE
326// RESTORE
327// RESTORE
328// where:
329// all the clipRect's are BW, nested, intersections
330// the drawBitmapRectToRect is a 1-1 copy from src to dest
331// the last (smallest) clip rect is a subset of the drawBitmapRectToRect's dest rect
332// all the saveLayer's paints can be rolled into the drawBitmapRectToRect's paint
333// This pattern is used by Google spreadsheet when drawing the toolbar buttons
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000334static bool check_7(SkDebugCanvas* canvas, int curCommand) {
335 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
336 canvas->getSize() <= curCommand+13 ||
337 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
338 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+2)->getType() ||
339 SAVE != canvas->getDrawCommandAt(curCommand+3)->getType() ||
340 CLIP_RECT != canvas->getDrawCommandAt(curCommand+4)->getType() ||
341 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+5)->getType() ||
342 SAVE != canvas->getDrawCommandAt(curCommand+6)->getType() ||
343 CLIP_RECT != canvas->getDrawCommandAt(curCommand+7)->getType() ||
344 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+8)->getType() ||
345 RESTORE != canvas->getDrawCommandAt(curCommand+9)->getType() ||
346 RESTORE != canvas->getDrawCommandAt(curCommand+10)->getType() ||
347 RESTORE != canvas->getDrawCommandAt(curCommand+11)->getType() ||
348 RESTORE != canvas->getDrawCommandAt(curCommand+12)->getType() ||
349 RESTORE != canvas->getDrawCommandAt(curCommand+13)->getType()) {
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000350 return false;
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000351 }
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000352
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000353 ClipRect* clip0 = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
354 SaveLayer* saveLayer0 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+2);
355 ClipRect* clip1 = (ClipRect*) canvas->getDrawCommandAt(curCommand+4);
356 SaveLayer* saveLayer1 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+5);
357 ClipRect* clip2 = (ClipRect*) canvas->getDrawCommandAt(curCommand+7);
358 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+8);
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000359
360 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) {
361 return false;
362 }
363
364 if (SkRegion::kIntersect_Op != clip0->op() ||
365 SkRegion::kIntersect_Op != clip1->op() ||
366 SkRegion::kIntersect_Op != clip2->op()) {
367 return false;
368 }
369
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000370 if (!clip0->rect().contains(clip1->rect()) ||
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000371 !clip1->rect().contains(clip2->rect())) {
372 return false;
373 }
374
375 // The src->dest mapping needs to be 1-to-1
376 if (NULL == dbmr->srcRect()) {
377 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
378 dbmr->bitmap().height() != dbmr->dstRect().height()) {
379 return false;
380 }
381 } else {
382 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
383 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
384 return false;
385 }
386 }
387
388 if (!dbmr->dstRect().contains(clip2->rect())) {
389 return false;
390 }
391
392 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
393 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
394
395 if ((NULL != saveLayerPaint0 && !is_simple(*saveLayerPaint0)) ||
396 (NULL != saveLayerPaint1 && !is_simple(*saveLayerPaint1))) {
397 return false;
398 }
399
400 SkPaint* dbmrPaint = dbmr->paint();
401
402 if (NULL == dbmrPaint) {
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000403 return true;
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000404 }
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000405
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000406 if (NULL != saveLayerPaint0) {
407 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque
408 if (dbmrPaint->getColor() != layerColor0) {
409 return false;
410 }
411 }
412
413 if (NULL != saveLayerPaint1) {
414 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque
415 if (dbmrPaint->getColor() != layerColor1) {
416 return false;
417 }
418 }
419
420 return true;
421}
422
423// Reduce to a single drawBitmapRectToRect call by folding the clipRect's into
424// the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's
425// paint.
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000426static void apply_7(SkDebugCanvas* canvas, int curCommand) {
427 SaveLayer* saveLayer0 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+2);
428 SaveLayer* saveLayer1 = (SaveLayer*) canvas->getDrawCommandAt(curCommand+5);
429 ClipRect* clip2 = (ClipRect*) canvas->getDrawCommandAt(curCommand+7);
430 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+8);
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000431
432 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft;
433 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop;
434
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000435 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000436 clip2->rect().width(), clip2->rect().height());
437
438 dbmr->setSrcRect(newSrc);
439 dbmr->setDstRect(clip2->rect());
440
441 SkColor color = 0xFF000000;
442 int a0, a1;
443
444 const SkPaint* saveLayerPaint0 = saveLayer0->paint();
445 if (NULL != saveLayerPaint0) {
446 color = saveLayerPaint0->getColor();
447 a0 = SkColorGetA(color);
448 } else {
449 a0 = 0xFF;
450 }
451
452 const SkPaint* saveLayerPaint1 = saveLayer1->paint();
453 if (NULL != saveLayerPaint1) {
454 color = saveLayerPaint1->getColor();
455 a1 = SkColorGetA(color);
456 } else {
457 a1 = 0xFF;
458 }
459
460 int newA = (a0 * a1) / 255;
461 SkASSERT(newA <= 0xFF);
462
463 SkPaint* dbmrPaint = dbmr->paint();
464
465 if (NULL != dbmrPaint) {
466 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA);
467 dbmrPaint->setColor(newColor);
468 } else {
469 SkColor newColor = SkColorSetA(color, newA);
470
471 SkPaint newPaint;
472 newPaint.setColor(newColor);
473 dbmr->setPaint(newPaint);
474 }
475
476 // remove everything except the drawbitmaprect
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000477 canvas->deleteDrawCommandAt(curCommand+13); // restore
478 canvas->deleteDrawCommandAt(curCommand+12); // restore
479 canvas->deleteDrawCommandAt(curCommand+11); // restore
480 canvas->deleteDrawCommandAt(curCommand+10); // restore
481 canvas->deleteDrawCommandAt(curCommand+9); // restore
482 canvas->deleteDrawCommandAt(curCommand+7); // clipRect
483 canvas->deleteDrawCommandAt(curCommand+6); // save
484 canvas->deleteDrawCommandAt(curCommand+5); // saveLayer
485 canvas->deleteDrawCommandAt(curCommand+4); // clipRect
486 canvas->deleteDrawCommandAt(curCommand+3); // save
487 canvas->deleteDrawCommandAt(curCommand+2); // saveLayer
488 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
489 canvas->deleteDrawCommandAt(curCommand); // save
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000490}
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000491
commit-bot@chromium.org3bdf1642013-04-01 21:00:27 +0000492// Check for:
493// SAVE
494// CLIP_RECT
495// DRAWBITMAPRECTTORECT
496// RESTORE
497// where:
498// the drawBitmapRectToRect is a 1-1 copy from src to dest
499// the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect
500static bool check_8(SkDebugCanvas* canvas, int curCommand) {
501 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
502 canvas->getSize() <= curCommand+4 ||
503 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
504 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
505 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
506 return false;
507 }
508
509 ClipRect* clip = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
510 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
511
512 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
513 return false;
514 }
515
516 // The src->dest mapping needs to be 1-to-1
517 if (NULL == dbmr->srcRect()) {
518 if (dbmr->bitmap().width() != dbmr->dstRect().width() ||
519 dbmr->bitmap().height() != dbmr->dstRect().height()) {
520 return false;
521 }
522 } else {
523 if (dbmr->srcRect()->width() != dbmr->dstRect().width() ||
524 dbmr->srcRect()->height() != dbmr->dstRect().height()) {
525 return false;
526 }
527 }
528
529 if (!dbmr->dstRect().contains(clip->rect())) {
530 return false;
531 }
532
533 return true;
534}
535
536// Fold the clipRect into the drawBitmapRectToRect's src and dest rects
537static void apply_8(SkDebugCanvas* canvas, int curCommand) {
538 ClipRect* clip = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
539 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
540
541 SkScalar newSrcLeft, newSrcTop;
542
543 if (NULL != dbmr->srcRect()) {
544 newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect().fLeft;
545 newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect().fTop;
546 } else {
547 newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft;
548 newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop;
549 }
550
551 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop,
552 clip->rect().width(), clip->rect().height());
553
554 dbmr->setSrcRect(newSrc);
555 dbmr->setDstRect(clip->rect());
556
557 // remove everything except the drawbitmaprect
558 canvas->deleteDrawCommandAt(curCommand+3);
559 canvas->deleteDrawCommandAt(curCommand+1);
560 canvas->deleteDrawCommandAt(curCommand);
561}
562
563// Check for:
564// SAVE
565// CLIP_RECT
566// DRAWBITMAPRECTTORECT
567// RESTORE
568// where:
569// clipRect is BW and encloses the DBMR2R's dest rect
570static bool check_9(SkDebugCanvas* canvas, int curCommand) {
571 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() ||
572 canvas->getSize() <= curCommand+4 ||
573 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
574 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
575 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) {
576 return false;
577 }
578
579 ClipRect* clip = (ClipRect*) canvas->getDrawCommandAt(curCommand+1);
580 DrawBitmapRect* dbmr = (DrawBitmapRect*) canvas->getDrawCommandAt(curCommand+2);
581
582 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) {
583 return false;
584 }
585
586 if (!clip->rect().contains(dbmr->dstRect())) {
587 return false;
588 }
589
590 return true;
591}
592
593// remove everything except the drawbitmaprect
594static void apply_9(SkDebugCanvas* canvas, int curCommand) {
595 canvas->deleteDrawCommandAt(curCommand+3); // restore
596 // drawBitmapRectToRect
597 canvas->deleteDrawCommandAt(curCommand+1); // clipRect
598 canvas->deleteDrawCommandAt(curCommand); // save
599}
600
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000601typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand);
602typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand);
robertphillips@google.com73743552013-02-05 20:51:49 +0000603
604struct OptTableEntry {
605 PFCheck fCheck;
606 PFApply fApply;
607 int fNumTimesApplied;
608} gOptTable[] = {
609 { check_0, apply_0, 0 },
610 { check_1, apply_1, 0 },
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000611 { check_2, apply_2, 0 },
612 { check_3, apply_3, 0 },
613 { check_4, apply_4, 0 },
robertphillips@google.com9105ad02013-03-17 18:46:16 +0000614 { check_5, apply_5, 0 },
615 { check_6, apply_6, 0 },
robertphillips@google.comc3410b82013-03-28 12:25:25 +0000616 { check_7, apply_7, 0 },
commit-bot@chromium.org3bdf1642013-04-01 21:00:27 +0000617 { check_8, apply_8, 0 },
618 { check_9, apply_9, 0 },
robertphillips@google.com73743552013-02-05 20:51:49 +0000619};
620
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000621
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000622static int filter_picture(const SkString& inFile, const SkString& outFile) {
djsollen@google.coma09e8832012-11-13 18:50:33 +0000623 SkPicture* inPicture = NULL;
624
625 SkFILEStream inStream(inFile.c_str());
626 if (inStream.isValid()) {
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000627 inPicture = SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeMemory));
djsollen@google.coma09e8832012-11-13 18:50:33 +0000628 }
629
630 if (NULL == inPicture) {
631 SkDebugf("Could not read file %s\n", inFile.c_str());
632 return -1;
633 }
634
robertphillips@google.com73743552013-02-05 20:51:49 +0000635 int localCount[SK_ARRAY_COUNT(gOptTable)];
636
637 memset(localCount, 0, sizeof(localCount));
638
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000639 SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
640 debugCanvas.setBounds(inPicture->width(), inPicture->height());
641 inPicture->draw(&debugCanvas);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000642
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000643 // delete the initial save and restore since replaying the commands will
robertphillips@google.com73743552013-02-05 20:51:49 +0000644 // re-add them
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000645 if (debugCanvas.getSize() > 1) {
646 debugCanvas.deleteDrawCommandAt(0);
647 debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1);
robertphillips@google.com73743552013-02-05 20:51:49 +0000648 }
649
robertphillips@google.comd9c18532013-04-01 19:10:21 +0000650 bool changed = true;
651
652 while (changed) {
653 changed = false;
654 for (int i = 0; i < debugCanvas.getSize(); ++i) {
655 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
656 if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) {
657 (*gOptTable[opt].fApply)(&debugCanvas, i);
658
659 ++gOptTable[opt].fNumTimesApplied;
660 ++localCount[opt];
661
662 if (debugCanvas.getSize() == i) {
663 // the optimization removed all the remaining operations
664 break;
665 }
666
667 opt = 0; // try all the opts all over again
668 changed = true;
669 }
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000670 }
671 }
672 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000673
674 if (!outFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000675 SkPicture outPicture;
676
677 SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
678 debugCanvas.draw(canvas);
679 outPicture.endRecording();
680
djsollen@google.coma09e8832012-11-13 18:50:33 +0000681 SkFILEWStream outStream(outFile.c_str());
682
683 outPicture.serialize(&outStream);
684 }
685
robertphillips@google.com73743552013-02-05 20:51:49 +0000686 bool someOptFired = false;
687 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
688 if (0 != localCount[opt]) {
689 SkDebugf("%d: %d ", opt, localCount[opt]);
690 someOptFired = true;
691 }
692 }
693
694 if (!someOptFired) {
695 SkDebugf("No opts fired\n");
696 } else {
697 SkDebugf("\n");
698 }
699
djsollen@google.coma09e8832012-11-13 18:50:33 +0000700 return 0;
701}
702
tfarina@chromium.orga5b7cc02012-10-08 14:41:10 +0000703// This function is not marked as 'static' so it can be referenced externally
704// in the iOS build.
humper@google.com05af1af2013-01-07 16:47:43 +0000705int tool_main(int argc, char** argv); // suppress a warning on mac
706
caryclark@google.com9598f422012-10-09 12:32:37 +0000707int tool_main(int argc, char** argv) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000708 SkGraphics::Init();
709
robertphillips@google.com801cee12012-10-19 19:06:11 +0000710 if (argc < 3) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000711 usage();
712 return -1;
713 }
714
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000715 SkString inFile, outFile, inDir, outDir;
robertphillips@google.com801cee12012-10-19 19:06:11 +0000716
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000717 char* const* stop = argv + argc;
718 for (++argv; argv < stop; ++argv) {
719 if (strcmp(*argv, "-i") == 0) {
720 argv++;
721 if (argv < stop && **argv) {
722 inFile.set(*argv);
723 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000724 SkDebugf("missing arg for -i\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000725 usage();
726 return -1;
727 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000728 } else if (strcmp(*argv, "--input-dir") == 0) {
729 argv++;
730 if (argv < stop && **argv) {
731 inDir.set(*argv);
732 } else {
733 SkDebugf("missing arg for --input-dir\n");
734 usage();
735 return -1;
736 }
737 } else if (strcmp(*argv, "--output-dir") == 0) {
738 argv++;
739 if (argv < stop && **argv) {
740 outDir.set(*argv);
741 } else {
742 SkDebugf("missing arg for --output-dir\n");
743 usage();
744 return -1;
745 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000746 } else if (strcmp(*argv, "-o") == 0) {
747 argv++;
748 if (argv < stop && **argv) {
749 outFile.set(*argv);
750 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000751 SkDebugf("missing arg for -o\n");
752 usage();
753 return -1;
754 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000755 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
756 usage();
757 return 0;
758 } else {
759 SkDebugf("unknown arg %s\n", *argv);
760 usage();
761 return -1;
762 }
763 }
764
djsollen@google.coma09e8832012-11-13 18:50:33 +0000765 SkOSFile::Iter iter(inDir.c_str(), "skp");
humper@google.com05af1af2013-01-07 16:47:43 +0000766
djsollen@google.coma09e8832012-11-13 18:50:33 +0000767 SkString inputFilename, outputFilename;
768 if (iter.next(&inputFilename)) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000769
djsollen@google.coma09e8832012-11-13 18:50:33 +0000770 do {
771 sk_tools::make_filepath(&inFile, inDir, inputFilename);
772 if (!outDir.isEmpty()) {
773 sk_tools::make_filepath(&outFile, outDir, inputFilename);
774 }
775 SkDebugf("Executing %s\n", inputFilename.c_str());
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000776 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000777 } while(iter.next(&inputFilename));
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000778
djsollen@google.coma09e8832012-11-13 18:50:33 +0000779 } else if (!inFile.isEmpty()) {
robertphillips@google.com3b0a9fe2013-01-31 15:56:22 +0000780 filter_picture(inFile, outFile);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000781 } else {
782 usage();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000783 return -1;
784 }
785
robertphillips@google.com73743552013-02-05 20:51:49 +0000786 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
787 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
788 }
789
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000790 SkGraphics::Term();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000791 return 0;
792}
793
794#if !defined SK_BUILD_FOR_IOS
795int main(int argc, char * const argv[]) {
caryclark@google.com9598f422012-10-09 12:32:37 +0000796 return tool_main(argc, (char**) argv);
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000797}
798#endif