| OLD | NEW |
| (Empty) |
| 1 /* | |
| 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 | |
| 8 #include "SkDebugCanvas.h" | |
| 9 #include "SkDevice.h" | |
| 10 #include "SkForceLinking.h" | |
| 11 #include "SkGraphics.h" | |
| 12 #include "SkImageDecoder.h" | |
| 13 #include "SkImageEncoder.h" | |
| 14 #include "SkOSFile.h" | |
| 15 #include "SkPicture.h" | |
| 16 #include "SkPictureRecord.h" | |
| 17 #include "SkPictureRecorder.h" | |
| 18 #include "SkStream.h" | |
| 19 #include "picture_utils.h" | |
| 20 | |
| 21 __SK_FORCE_IMAGE_DECODER_LINKING; | |
| 22 | |
| 23 static void usage() { | |
| 24 SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-
dir path]\n"); | |
| 25 SkDebugf(" [-h|--help]\n\n"); | |
| 26 SkDebugf(" -i inFile : file to filter.\n"); | |
| 27 SkDebugf(" -o outFile : result of filtering.\n"); | |
| 28 SkDebugf(" --input-dir : process all files in dir with .skp extension.\n"
); | |
| 29 SkDebugf(" --output-dir : results of filtering the input dir.\n"); | |
| 30 SkDebugf(" -h|--help : Show this help message.\n"); | |
| 31 } | |
| 32 | |
| 33 // Is the supplied paint simply a color? | |
| 34 static bool is_simple(const SkPaint& p) { | |
| 35 return nullptr == p.getPathEffect() && | |
| 36 nullptr == p.getShader() && | |
| 37 nullptr == p.getXfermode() && | |
| 38 nullptr == p.getMaskFilter() && | |
| 39 nullptr == p.getColorFilter() && | |
| 40 nullptr == p.getRasterizer() && | |
| 41 nullptr == p.getLooper() && | |
| 42 nullptr == p.getImageFilter(); | |
| 43 } | |
| 44 | |
| 45 | |
| 46 // Check for: | |
| 47 // SAVE_LAYER | |
| 48 // DRAW_BITMAP_RECT_TO_RECT | |
| 49 // RESTORE | |
| 50 // where the saveLayer's color can be moved into the drawBitmapRect | |
| 51 static bool check_0(SkDebugCanvas* canvas, int curCommand) { | |
| 52 if (SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand)
->getType() || | |
| 53 canvas->getSize() <= curCommand+2 || | |
| 54 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+1)->getType() || | |
| 55 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+2)
->getType()) { | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 SkSaveLayerCommand* saveLayer = | |
| 60 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
| 61 SkDrawBitmapRectCommand* dbmr = | |
| 62 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 63 | |
| 64 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
| 65 SkPaint* dbmrPaint = dbmr->paint(); | |
| 66 | |
| 67 // For this optimization we only fold the saveLayer and drawBitmapRect | |
| 68 // together if the saveLayer's draw is simple (i.e., no fancy effects) | |
| 69 // and the only difference in the colors is their alpha value | |
| 70 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaqu
e | |
| 71 SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaqu
e | |
| 72 | |
| 73 // If either operation lacks a paint then the collapse is trivial | |
| 74 return nullptr == saveLayerPaint || | |
| 75 nullptr == dbmrPaint || | |
| 76 (is_simple(*saveLayerPaint) && dbmrColor == layerColor); | |
| 77 } | |
| 78 | |
| 79 // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer | |
| 80 // and restore | |
| 81 static void apply_0(SkDebugCanvas* canvas, int curCommand) { | |
| 82 SkSaveLayerCommand* saveLayer = | |
| 83 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
| 84 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
| 85 | |
| 86 // if (nullptr == saveLayerPaint) the dbmr's paint doesn't need to be change
d | |
| 87 if (saveLayerPaint) { | |
| 88 SkDrawBitmapRectCommand* dbmr = | |
| 89 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 90 SkPaint* dbmrPaint = dbmr->paint(); | |
| 91 | |
| 92 if (nullptr == dbmrPaint) { | |
| 93 // if the DBMR doesn't have a paint just use the saveLayer's | |
| 94 dbmr->setPaint(*saveLayerPaint); | |
| 95 } else if (saveLayerPaint) { | |
| 96 // Both paints are present so their alphas need to be combined | |
| 97 SkColor color = saveLayerPaint->getColor(); | |
| 98 int a0 = SkColorGetA(color); | |
| 99 | |
| 100 color = dbmrPaint->getColor(); | |
| 101 int a1 = SkColorGetA(color); | |
| 102 | |
| 103 int newA = SkMulDiv255Round(a0, a1); | |
| 104 SkASSERT(newA <= 0xFF); | |
| 105 | |
| 106 SkColor newColor = SkColorSetA(color, newA); | |
| 107 dbmrPaint->setColor(newColor); | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 canvas->deleteDrawCommandAt(curCommand+2); // restore | |
| 112 canvas->deleteDrawCommandAt(curCommand); // saveLayer | |
| 113 } | |
| 114 | |
| 115 // Check for: | |
| 116 // SAVE_LAYER | |
| 117 // SAVE | |
| 118 // CLIP_RECT | |
| 119 // DRAW_BITMAP_RECT_TO_RECT | |
| 120 // RESTORE | |
| 121 // RESTORE | |
| 122 // where the saveLayer's color can be moved into the drawBitmapRect | |
| 123 static bool check_1(SkDebugCanvas* canvas, int curCommand) { | |
| 124 if (SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand)
->getType() || | |
| 125 canvas->getSize() <= curCommand+5 || | |
| 126 SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+1)->g
etType() || | |
| 127 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+2
)->getType() || | |
| 128 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+3)->getType() || | |
| 129 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+4)
->getType() || | |
| 130 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+5)
->getType()) { | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 134 SkSaveLayerCommand* saveLayer = | |
| 135 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
| 136 SkDrawBitmapRectCommand* dbmr = | |
| 137 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); | |
| 138 | |
| 139 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
| 140 SkPaint* dbmrPaint = dbmr->paint(); | |
| 141 | |
| 142 // For this optimization we only fold the saveLayer and drawBitmapRect | |
| 143 // together if the saveLayer's draw is simple (i.e., no fancy effects) and | |
| 144 // and the only difference in the colors is that the saveLayer's can have | |
| 145 // an alpha while the drawBitmapRect's is opaque. | |
| 146 // TODO: it should be possible to fold them together even if they both | |
| 147 // have different non-255 alphas but this is low priority since we have | |
| 148 // never seen that case | |
| 149 // If either operation lacks a paint then the collapse is trivial | |
| 150 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaqu
e | |
| 151 | |
| 152 return nullptr == saveLayerPaint || | |
| 153 nullptr == dbmrPaint || | |
| 154 (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor); | |
| 155 } | |
| 156 | |
| 157 // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer | |
| 158 // and restore | |
| 159 static void apply_1(SkDebugCanvas* canvas, int curCommand) { | |
| 160 SkSaveLayerCommand* saveLayer = | |
| 161 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); | |
| 162 const SkPaint* saveLayerPaint = saveLayer->paint(); | |
| 163 | |
| 164 // if (nullptr == saveLayerPaint) the dbmr's paint doesn't need to be change
d | |
| 165 if (saveLayerPaint) { | |
| 166 SkDrawBitmapRectCommand* dbmr = | |
| 167 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); | |
| 168 SkPaint* dbmrPaint = dbmr->paint(); | |
| 169 | |
| 170 if (nullptr == dbmrPaint) { | |
| 171 dbmr->setPaint(*saveLayerPaint); | |
| 172 } else { | |
| 173 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), | |
| 174 SkColorGetA(saveLayerPaint->getColor(
))); | |
| 175 dbmrPaint->setColor(newColor); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 canvas->deleteDrawCommandAt(curCommand+5); // restore | |
| 180 canvas->deleteDrawCommandAt(curCommand); // saveLayer | |
| 181 } | |
| 182 | |
| 183 // Check for: | |
| 184 // SAVE | |
| 185 // CLIP_RECT | |
| 186 // DRAW_RECT | |
| 187 // RESTORE | |
| 188 // where the rect is entirely within the clip and the clip is an intersect | |
| 189 static bool check_2(SkDebugCanvas* canvas, int curCommand) { | |
| 190 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
| 191 canvas->getSize() <= curCommand+4 || | |
| 192 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
| 193 SkDrawCommand::kDrawRect_OpType != canvas->getDrawCommandAt(curCommand+2
)->getType() || | |
| 194 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
| 195 return false; | |
| 196 } | |
| 197 | |
| 198 SkClipRectCommand* cr = | |
| 199 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 200 SkDrawRectCommand* dr = | |
| 201 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 202 | |
| 203 if (SkRegion::kIntersect_Op != cr->op()) { | |
| 204 return false; | |
| 205 } | |
| 206 | |
| 207 return cr->rect().contains(dr->rect()); | |
| 208 } | |
| 209 | |
| 210 // Remove everything but the drawRect | |
| 211 static void apply_2(SkDebugCanvas* canvas, int curCommand) { | |
| 212 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
| 213 // drawRect | |
| 214 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
| 215 canvas->deleteDrawCommandAt(curCommand); // save | |
| 216 } | |
| 217 | |
| 218 // Check for: | |
| 219 // SAVE | |
| 220 // CLIP_RRECT | |
| 221 // DRAW_RECT | |
| 222 // RESTORE | |
| 223 // where the rect entirely encloses the clip | |
| 224 static bool check_3(SkDebugCanvas* canvas, int curCommand) { | |
| 225 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
| 226 canvas->getSize() <= curCommand+4 || | |
| 227 SkDrawCommand::kClipRRect_OpType != canvas->getDrawCommandAt(curCommand+
1)->getType() || | |
| 228 SkDrawCommand::kDrawRect_OpType != canvas->getDrawCommandAt(curCommand+2
)->getType() || | |
| 229 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 SkClipRRectCommand* crr = | |
| 234 (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 235 SkDrawRectCommand* dr = | |
| 236 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 237 | |
| 238 if (SkRegion::kIntersect_Op != crr->op()) { | |
| 239 return false; | |
| 240 } | |
| 241 | |
| 242 return dr->rect().contains(crr->rrect().rect()); | |
| 243 } | |
| 244 | |
| 245 // Replace everything with a drawRRect with the paint from the drawRect | |
| 246 // and the AA settings from the clipRRect | |
| 247 static void apply_3(SkDebugCanvas* canvas, int curCommand) { | |
| 248 | |
| 249 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
| 250 | |
| 251 SkClipRRectCommand* crr = | |
| 252 (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 253 SkDrawRectCommand* dr = | |
| 254 (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 255 | |
| 256 // TODO: could skip paint re-creation if the AA settings already match | |
| 257 SkPaint newPaint = dr->paint(); | |
| 258 newPaint.setAntiAlias(crr->doAA()); | |
| 259 SkDrawRRectCommand* drr = new SkDrawRRectCommand(crr->rrect(), newPaint); | |
| 260 canvas->setDrawCommandAt(curCommand+2, drr); | |
| 261 | |
| 262 canvas->deleteDrawCommandAt(curCommand+1); // clipRRect | |
| 263 canvas->deleteDrawCommandAt(curCommand); // save | |
| 264 } | |
| 265 | |
| 266 // Check for: | |
| 267 // SAVE | |
| 268 // CLIP_RECT | |
| 269 // DRAW_BITMAP_RECT_TO_RECT | |
| 270 // RESTORE | |
| 271 // where the rect and drawBitmapRect dst exactly match | |
| 272 static bool check_4(SkDebugCanvas* canvas, int curCommand) { | |
| 273 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
| 274 canvas->getSize() <= curCommand+4 || | |
| 275 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
| 276 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+2)->getType() || | |
| 277 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
| 278 return false; | |
| 279 } | |
| 280 | |
| 281 SkClipRectCommand* cr = | |
| 282 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 283 SkDrawBitmapRectCommand* dbmr = | |
| 284 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 285 | |
| 286 if (SkRegion::kIntersect_Op != cr->op()) { | |
| 287 return false; | |
| 288 } | |
| 289 | |
| 290 return dbmr->dstRect() == cr->rect(); | |
| 291 } | |
| 292 | |
| 293 // Remove everything but the drawBitmapRect | |
| 294 static void apply_4(SkDebugCanvas* canvas, int curCommand) { | |
| 295 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
| 296 // drawBitmapRectToRect | |
| 297 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
| 298 canvas->deleteDrawCommandAt(curCommand); // save | |
| 299 } | |
| 300 | |
| 301 // Check for: | |
| 302 // SAVE | |
| 303 // CLIP_RECT | |
| 304 // SAVE_LAYER | |
| 305 // SAVE | |
| 306 // CLIP_RECT | |
| 307 // SAVE_LAYER | |
| 308 // SAVE | |
| 309 // CLIP_RECT | |
| 310 // DRAWBITMAPRECTTORECT | |
| 311 // RESTORE | |
| 312 // RESTORE | |
| 313 // RESTORE | |
| 314 // RESTORE | |
| 315 // RESTORE | |
| 316 // where: | |
| 317 // all the clipRect's are BW, nested, intersections | |
| 318 // the drawBitmapRectToRect is a 1-1 copy from src to dest | |
| 319 // the last (smallest) clip rect is a subset of the drawBitmapRectToRect's
dest rect | |
| 320 // all the saveLayer's paints can be rolled into the drawBitmapRectToRect's
paint | |
| 321 // This pattern is used by Google spreadsheet when drawing the toolbar buttons | |
| 322 static bool check_7(SkDebugCanvas* canvas, int curCommand) { | |
| 323 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
| 324 canvas->getSize() <= curCommand+13 || | |
| 325 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
| 326 SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand+
2)->getType() || | |
| 327 SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+3)->g
etType() || | |
| 328 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+4
)->getType() || | |
| 329 SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand+
5)->getType() || | |
| 330 SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+6)->g
etType() || | |
| 331 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+7
)->getType() || | |
| 332 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+8)->getType() || | |
| 333 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+9)
->getType() || | |
| 334 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+10
)->getType() || | |
| 335 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+11
)->getType() || | |
| 336 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+12
)->getType() || | |
| 337 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+13
)->getType()) { | |
| 338 return false; | |
| 339 } | |
| 340 | |
| 341 SkClipRectCommand* clip0 = | |
| 342 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 343 SkSaveLayerCommand* saveLayer0 = | |
| 344 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 345 SkClipRectCommand* clip1 = | |
| 346 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+4); | |
| 347 SkSaveLayerCommand* saveLayer1 = | |
| 348 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); | |
| 349 SkClipRectCommand* clip2 = | |
| 350 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); | |
| 351 SkDrawBitmapRectCommand* dbmr = | |
| 352 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); | |
| 353 | |
| 354 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) { | |
| 355 return false; | |
| 356 } | |
| 357 | |
| 358 if (SkRegion::kIntersect_Op != clip0->op() || | |
| 359 SkRegion::kIntersect_Op != clip1->op() || | |
| 360 SkRegion::kIntersect_Op != clip2->op()) { | |
| 361 return false; | |
| 362 } | |
| 363 | |
| 364 if (!clip0->rect().contains(clip1->rect()) || | |
| 365 !clip1->rect().contains(clip2->rect())) { | |
| 366 return false; | |
| 367 } | |
| 368 | |
| 369 // The src->dest mapping needs to be 1-to-1 | |
| 370 if (nullptr == dbmr->srcRect()) { | |
| 371 if (dbmr->bitmap().width() != dbmr->dstRect().width() || | |
| 372 dbmr->bitmap().height() != dbmr->dstRect().height()) { | |
| 373 return false; | |
| 374 } | |
| 375 } else { | |
| 376 if (dbmr->srcRect()->width() != dbmr->dstRect().width() || | |
| 377 dbmr->srcRect()->height() != dbmr->dstRect().height()) { | |
| 378 return false; | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 if (!dbmr->dstRect().contains(clip2->rect())) { | |
| 383 return false; | |
| 384 } | |
| 385 | |
| 386 const SkPaint* saveLayerPaint0 = saveLayer0->paint(); | |
| 387 const SkPaint* saveLayerPaint1 = saveLayer1->paint(); | |
| 388 | |
| 389 if ((saveLayerPaint0 && !is_simple(*saveLayerPaint0)) || | |
| 390 (saveLayerPaint1 && !is_simple(*saveLayerPaint1))) { | |
| 391 return false; | |
| 392 } | |
| 393 | |
| 394 SkPaint* dbmrPaint = dbmr->paint(); | |
| 395 | |
| 396 if (nullptr == dbmrPaint) { | |
| 397 return true; | |
| 398 } | |
| 399 | |
| 400 if (saveLayerPaint0) { | |
| 401 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force
opaque | |
| 402 if (dbmrPaint->getColor() != layerColor0) { | |
| 403 return false; | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 if (saveLayerPaint1) { | |
| 408 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force
opaque | |
| 409 if (dbmrPaint->getColor() != layerColor1) { | |
| 410 return false; | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 return true; | |
| 415 } | |
| 416 | |
| 417 // Reduce to a single drawBitmapRectToRect call by folding the clipRect's into | |
| 418 // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect'
s | |
| 419 // paint. | |
| 420 static void apply_7(SkDebugCanvas* canvas, int curCommand) { | |
| 421 SkSaveLayerCommand* saveLayer0 = | |
| 422 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 423 SkSaveLayerCommand* saveLayer1 = | |
| 424 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); | |
| 425 SkClipRectCommand* clip2 = | |
| 426 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); | |
| 427 SkDrawBitmapRectCommand* dbmr = | |
| 428 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); | |
| 429 | |
| 430 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->d
stRect().fLeft; | |
| 431 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstR
ect().fTop; | |
| 432 | |
| 433 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, | |
| 434 clip2->rect().width(), clip2->rect().height
()); | |
| 435 | |
| 436 dbmr->setSrcRect(newSrc); | |
| 437 dbmr->setDstRect(clip2->rect()); | |
| 438 | |
| 439 SkColor color = 0xFF000000; | |
| 440 int a0, a1; | |
| 441 | |
| 442 const SkPaint* saveLayerPaint0 = saveLayer0->paint(); | |
| 443 if (saveLayerPaint0) { | |
| 444 color = saveLayerPaint0->getColor(); | |
| 445 a0 = SkColorGetA(color); | |
| 446 } else { | |
| 447 a0 = 0xFF; | |
| 448 } | |
| 449 | |
| 450 const SkPaint* saveLayerPaint1 = saveLayer1->paint(); | |
| 451 if (saveLayerPaint1) { | |
| 452 color = saveLayerPaint1->getColor(); | |
| 453 a1 = SkColorGetA(color); | |
| 454 } else { | |
| 455 a1 = 0xFF; | |
| 456 } | |
| 457 | |
| 458 int newA = SkMulDiv255Round(a0, a1); | |
| 459 SkASSERT(newA <= 0xFF); | |
| 460 | |
| 461 SkPaint* dbmrPaint = dbmr->paint(); | |
| 462 | |
| 463 if (dbmrPaint) { | |
| 464 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA); | |
| 465 dbmrPaint->setColor(newColor); | |
| 466 } else { | |
| 467 SkColor newColor = SkColorSetA(color, newA); | |
| 468 | |
| 469 SkPaint newPaint; | |
| 470 newPaint.setColor(newColor); | |
| 471 dbmr->setPaint(newPaint); | |
| 472 } | |
| 473 | |
| 474 // remove everything except the drawbitmaprect | |
| 475 canvas->deleteDrawCommandAt(curCommand+13); // restore | |
| 476 canvas->deleteDrawCommandAt(curCommand+12); // restore | |
| 477 canvas->deleteDrawCommandAt(curCommand+11); // restore | |
| 478 canvas->deleteDrawCommandAt(curCommand+10); // restore | |
| 479 canvas->deleteDrawCommandAt(curCommand+9); // restore | |
| 480 canvas->deleteDrawCommandAt(curCommand+7); // clipRect | |
| 481 canvas->deleteDrawCommandAt(curCommand+6); // save | |
| 482 canvas->deleteDrawCommandAt(curCommand+5); // saveLayer | |
| 483 canvas->deleteDrawCommandAt(curCommand+4); // clipRect | |
| 484 canvas->deleteDrawCommandAt(curCommand+3); // save | |
| 485 canvas->deleteDrawCommandAt(curCommand+2); // saveLayer | |
| 486 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
| 487 canvas->deleteDrawCommandAt(curCommand); // save | |
| 488 } | |
| 489 | |
| 490 // Check for: | |
| 491 // SAVE | |
| 492 // CLIP_RECT | |
| 493 // DRAWBITMAPRECTTORECT | |
| 494 // RESTORE | |
| 495 // where: | |
| 496 // the drawBitmapRectToRect is a 1-1 copy from src to dest | |
| 497 // the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect | |
| 498 static bool check_8(SkDebugCanvas* canvas, int curCommand) { | |
| 499 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
| 500 canvas->getSize() <= curCommand+4 || | |
| 501 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
| 502 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+2)->getType() || | |
| 503 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
| 504 return false; | |
| 505 } | |
| 506 | |
| 507 SkClipRectCommand* clip = | |
| 508 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 509 SkDrawBitmapRectCommand* dbmr = | |
| 510 (SkDrawBitmapRectCommand*) 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 (nullptr == 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 | |
| 537 static void apply_8(SkDebugCanvas* canvas, int curCommand) { | |
| 538 SkClipRectCommand* clip = | |
| 539 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 540 SkDrawBitmapRectCommand* dbmr = | |
| 541 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 542 | |
| 543 SkScalar newSrcLeft, newSrcTop; | |
| 544 | |
| 545 if (dbmr->srcRect()) { | |
| 546 newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect
().fLeft; | |
| 547 newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect()
.fTop; | |
| 548 } else { | |
| 549 newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft; | |
| 550 newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop; | |
| 551 } | |
| 552 | |
| 553 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, | |
| 554 clip->rect().width(), clip->rect().height()
); | |
| 555 | |
| 556 dbmr->setSrcRect(newSrc); | |
| 557 dbmr->setDstRect(clip->rect()); | |
| 558 | |
| 559 // remove everything except the drawbitmaprect | |
| 560 canvas->deleteDrawCommandAt(curCommand+3); | |
| 561 canvas->deleteDrawCommandAt(curCommand+1); | |
| 562 canvas->deleteDrawCommandAt(curCommand); | |
| 563 } | |
| 564 | |
| 565 // Check for: | |
| 566 // SAVE | |
| 567 // CLIP_RECT | |
| 568 // DRAWBITMAPRECTTORECT | |
| 569 // RESTORE | |
| 570 // where: | |
| 571 // clipRect is BW and encloses the DBMR2R's dest rect | |
| 572 static bool check_9(SkDebugCanvas* canvas, int curCommand) { | |
| 573 if (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->get
Type() || | |
| 574 canvas->getSize() <= curCommand+4 || | |
| 575 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1
)->getType() || | |
| 576 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCom
mand+2)->getType() || | |
| 577 SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+3)
->getType()) { | |
| 578 return false; | |
| 579 } | |
| 580 | |
| 581 SkClipRectCommand* clip = | |
| 582 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); | |
| 583 SkDrawBitmapRectCommand* dbmr = | |
| 584 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); | |
| 585 | |
| 586 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { | |
| 587 return false; | |
| 588 } | |
| 589 | |
| 590 if (!clip->rect().contains(dbmr->dstRect())) { | |
| 591 return false; | |
| 592 } | |
| 593 | |
| 594 return true; | |
| 595 } | |
| 596 | |
| 597 // remove everything except the drawbitmaprect | |
| 598 static void apply_9(SkDebugCanvas* canvas, int curCommand) { | |
| 599 canvas->deleteDrawCommandAt(curCommand+3); // restore | |
| 600 // drawBitmapRectToRect | |
| 601 canvas->deleteDrawCommandAt(curCommand+1); // clipRect | |
| 602 canvas->deleteDrawCommandAt(curCommand); // save | |
| 603 } | |
| 604 | |
| 605 typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand); | |
| 606 typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand); | |
| 607 | |
| 608 struct OptTableEntry { | |
| 609 PFCheck fCheck; | |
| 610 PFApply fApply; | |
| 611 int fNumTimesApplied; | |
| 612 } gOptTable[] = { | |
| 613 { check_0, apply_0, 0 }, | |
| 614 { check_1, apply_1, 0 }, | |
| 615 { check_2, apply_2, 0 }, | |
| 616 { check_3, apply_3, 0 }, | |
| 617 { check_4, apply_4, 0 }, | |
| 618 { check_7, apply_7, 0 }, | |
| 619 { check_8, apply_8, 0 }, | |
| 620 { check_9, apply_9, 0 }, | |
| 621 }; | |
| 622 | |
| 623 | |
| 624 static int filter_picture(const SkString& inFile, const SkString& outFile) { | |
| 625 SkAutoTUnref<SkPicture> inPicture; | |
| 626 | |
| 627 SkFILEStream inStream(inFile.c_str()); | |
| 628 if (inStream.isValid()) { | |
| 629 inPicture.reset(SkPicture::CreateFromStream(&inStream)); | |
| 630 } | |
| 631 | |
| 632 if (nullptr == inPicture.get()) { | |
| 633 SkDebugf("Could not read file %s\n", inFile.c_str()); | |
| 634 return -1; | |
| 635 } | |
| 636 | |
| 637 int localCount[SK_ARRAY_COUNT(gOptTable)]; | |
| 638 | |
| 639 memset(localCount, 0, sizeof(localCount)); | |
| 640 | |
| 641 SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), | |
| 642 SkScalarCeilToInt(inPicture->cullRect().height()))
; | |
| 643 inPicture->playback(&debugCanvas); | |
| 644 | |
| 645 // delete the initial save and restore since replaying the commands will | |
| 646 // re-add them | |
| 647 if (debugCanvas.getSize() > 1) { | |
| 648 debugCanvas.deleteDrawCommandAt(0); | |
| 649 debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1); | |
| 650 } | |
| 651 | |
| 652 bool changed = true; | |
| 653 int numBefore = debugCanvas.getSize(); | |
| 654 | |
| 655 while (changed) { | |
| 656 changed = false; | |
| 657 for (int i = 0; i < debugCanvas.getSize(); ++i) { | |
| 658 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { | |
| 659 if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) { | |
| 660 (*gOptTable[opt].fApply)(&debugCanvas, i); | |
| 661 | |
| 662 ++gOptTable[opt].fNumTimesApplied; | |
| 663 ++localCount[opt]; | |
| 664 | |
| 665 if (debugCanvas.getSize() == i) { | |
| 666 // the optimization removed all the remaining operations | |
| 667 break; | |
| 668 } | |
| 669 | |
| 670 opt = 0; // try all the opts all over again | |
| 671 changed = true; | |
| 672 } | |
| 673 } | |
| 674 } | |
| 675 } | |
| 676 | |
| 677 int numAfter = debugCanvas.getSize(); | |
| 678 | |
| 679 if (!outFile.isEmpty()) { | |
| 680 SkPictureRecorder recorder; | |
| 681 SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width()
, | |
| 682 inPicture->cullRect().height(
), | |
| 683 nullptr, 0); | |
| 684 debugCanvas.draw(canvas); | |
| 685 SkAutoTUnref<SkPicture> outPicture(recorder.endRecording()); | |
| 686 | |
| 687 SkFILEWStream outStream(outFile.c_str()); | |
| 688 | |
| 689 outPicture->serialize(&outStream); | |
| 690 } | |
| 691 | |
| 692 bool someOptFired = false; | |
| 693 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { | |
| 694 if (0 != localCount[opt]) { | |
| 695 SkDebugf("%d: %d ", opt, localCount[opt]); | |
| 696 someOptFired = true; | |
| 697 } | |
| 698 } | |
| 699 | |
| 700 if (!someOptFired) { | |
| 701 SkDebugf("No opts fired\n"); | |
| 702 } else { | |
| 703 SkDebugf("\t before: %d after: %d delta: %d\n", | |
| 704 numBefore, numAfter, numBefore-numAfter); | |
| 705 } | |
| 706 | |
| 707 return 0; | |
| 708 } | |
| 709 | |
| 710 // This function is not marked as 'static' so it can be referenced externally | |
| 711 // in the iOS build. | |
| 712 int tool_main(int argc, char** argv); // suppress a warning on mac | |
| 713 | |
| 714 int tool_main(int argc, char** argv) { | |
| 715 SkGraphics::Init(); | |
| 716 | |
| 717 if (argc < 3) { | |
| 718 usage(); | |
| 719 return -1; | |
| 720 } | |
| 721 | |
| 722 SkString inFile, outFile, inDir, outDir; | |
| 723 | |
| 724 char* const* stop = argv + argc; | |
| 725 for (++argv; argv < stop; ++argv) { | |
| 726 if (strcmp(*argv, "-i") == 0) { | |
| 727 argv++; | |
| 728 if (argv < stop && **argv) { | |
| 729 inFile.set(*argv); | |
| 730 } else { | |
| 731 SkDebugf("missing arg for -i\n"); | |
| 732 usage(); | |
| 733 return -1; | |
| 734 } | |
| 735 } else if (strcmp(*argv, "--input-dir") == 0) { | |
| 736 argv++; | |
| 737 if (argv < stop && **argv) { | |
| 738 inDir.set(*argv); | |
| 739 } else { | |
| 740 SkDebugf("missing arg for --input-dir\n"); | |
| 741 usage(); | |
| 742 return -1; | |
| 743 } | |
| 744 } else if (strcmp(*argv, "--output-dir") == 0) { | |
| 745 argv++; | |
| 746 if (argv < stop && **argv) { | |
| 747 outDir.set(*argv); | |
| 748 } else { | |
| 749 SkDebugf("missing arg for --output-dir\n"); | |
| 750 usage(); | |
| 751 return -1; | |
| 752 } | |
| 753 } else if (strcmp(*argv, "-o") == 0) { | |
| 754 argv++; | |
| 755 if (argv < stop && **argv) { | |
| 756 outFile.set(*argv); | |
| 757 } else { | |
| 758 SkDebugf("missing arg for -o\n"); | |
| 759 usage(); | |
| 760 return -1; | |
| 761 } | |
| 762 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { | |
| 763 usage(); | |
| 764 return 0; | |
| 765 } else { | |
| 766 SkDebugf("unknown arg %s\n", *argv); | |
| 767 usage(); | |
| 768 return -1; | |
| 769 } | |
| 770 } | |
| 771 | |
| 772 SkOSFile::Iter iter(inDir.c_str(), "skp"); | |
| 773 | |
| 774 SkString inputFilename, outputFilename; | |
| 775 if (iter.next(&inputFilename)) { | |
| 776 | |
| 777 do { | |
| 778 inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str()); | |
| 779 if (!outDir.isEmpty()) { | |
| 780 outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str()); | |
| 781 } | |
| 782 SkDebugf("Executing %s\n", inputFilename.c_str()); | |
| 783 filter_picture(inFile, outFile); | |
| 784 } while(iter.next(&inputFilename)); | |
| 785 | |
| 786 } else if (!inFile.isEmpty()) { | |
| 787 filter_picture(inFile, outFile); | |
| 788 } else { | |
| 789 usage(); | |
| 790 return -1; | |
| 791 } | |
| 792 | |
| 793 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { | |
| 794 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied); | |
| 795 } | |
| 796 | |
| 797 return 0; | |
| 798 } | |
| 799 | |
| 800 #if !defined SK_BUILD_FOR_IOS | |
| 801 int main(int argc, char * const argv[]) { | |
| 802 return tool_main(argc, (char**) argv); | |
| 803 } | |
| 804 #endif | |
| OLD | NEW |