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 NULL == p.getPathEffect() && 36 NULL == p.getShader() && 37 NULL == p.getXfermode() && 38 NULL == p.getMaskFilter() && 39 NULL == p.getColorFilter() && 40 NULL == p.getRasterizer() && 41 NULL == p.getLooper() && 42 NULL == 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(curCommand+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 opaque 71 SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaque 72 73 // If either operation lacks a paint then the collapse is trivial 74 return NULL == saveLayerPaint || 75 NULL == 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 (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed 87 if (saveLayerPaint) { 88 SkDrawBitmapRectCommand* dbmr = 89 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); 90 SkPaint* dbmrPaint = dbmr->paint(); 91 92 if (NULL == 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)->getType() || 127 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() || 128 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+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 opaque 151 152 return NULL == saveLayerPaint || 153 NULL == 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 (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed 165 if (saveLayerPaint) { 166 SkDrawBitmapRectCommand* dbmr = 167 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); 168 SkPaint* dbmrPaint = dbmr->paint(); 169 170 if (NULL == 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)->getType() || 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)->getType() || 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)->getType() || 274 canvas->getSize() <= curCommand+4 || 275 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() || 276 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+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)->getType() || 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)->getType() || 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)->getType() || 331 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+7)->getType() || 332 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+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 (NULL == 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 (NULL == 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->dstRect().fLeft; 431 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().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)->getType() || 500 canvas->getSize() <= curCommand+4 || 501 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() || 502 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+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 (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 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)->getType() || 574 canvas->getSize() <= curCommand+4 || 575 SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() || 576 SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+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 (NULL == 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 NULL, 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 #if SK_ENABLE_INST_COUNT 716 gPrintInstCount = true; 717 #endif 718 719 SkGraphics::Init(); 720 721 if (argc < 3) { 722 usage(); 723 return -1; 724 } 725 726 SkString inFile, outFile, inDir, outDir; 727 728 char* const* stop = argv + argc; 729 for (++argv; argv < stop; ++argv) { 730 if (strcmp(*argv, "-i") == 0) { 731 argv++; 732 if (argv < stop && **argv) { 733 inFile.set(*argv); 734 } else { 735 SkDebugf("missing arg for -i\n"); 736 usage(); 737 return -1; 738 } 739 } else if (strcmp(*argv, "--input-dir") == 0) { 740 argv++; 741 if (argv < stop && **argv) { 742 inDir.set(*argv); 743 } else { 744 SkDebugf("missing arg for --input-dir\n"); 745 usage(); 746 return -1; 747 } 748 } else if (strcmp(*argv, "--output-dir") == 0) { 749 argv++; 750 if (argv < stop && **argv) { 751 outDir.set(*argv); 752 } else { 753 SkDebugf("missing arg for --output-dir\n"); 754 usage(); 755 return -1; 756 } 757 } else if (strcmp(*argv, "-o") == 0) { 758 argv++; 759 if (argv < stop && **argv) { 760 outFile.set(*argv); 761 } else { 762 SkDebugf("missing arg for -o\n"); 763 usage(); 764 return -1; 765 } 766 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { 767 usage(); 768 return 0; 769 } else { 770 SkDebugf("unknown arg %s\n", *argv); 771 usage(); 772 return -1; 773 } 774 } 775 776 SkOSFile::Iter iter(inDir.c_str(), "skp"); 777 778 SkString inputFilename, outputFilename; 779 if (iter.next(&inputFilename)) { 780 781 do { 782 inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str()); 783 if (!outDir.isEmpty()) { 784 outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str()); 785 } 786 SkDebugf("Executing %s\n", inputFilename.c_str()); 787 filter_picture(inFile, outFile); 788 } while(iter.next(&inputFilename)); 789 790 } else if (!inFile.isEmpty()) { 791 filter_picture(inFile, outFile); 792 } else { 793 usage(); 794 return -1; 795 } 796 797 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { 798 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied); 799 } 800 801 SkGraphics::Term(); 802 return 0; 803 } 804 805 #if !defined SK_BUILD_FOR_IOS 806 int main(int argc, char * const argv[]) { 807 return tool_main(argc, (char**) argv); 808 } 809 #endif 810