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 (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() || 53 canvas->getSize() <= curCommand+2 || 54 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 55 RESTORE != 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 (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() || 125 canvas->getSize() <= curCommand+5 || 126 SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() || 127 CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || 128 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() || 129 RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() || 130 RESTORE != 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 (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || 191 canvas->getSize() <= curCommand+4 || 192 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 193 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || 194 RESTORE != 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 (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || 226 canvas->getSize() <= curCommand+4 || 227 CLIP_RRECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 228 DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || 229 RESTORE != 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 (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || 274 canvas->getSize() <= curCommand+4 || 275 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 276 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || 277 RESTORE != 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 // TRANSLATE 303 // where the translate is zero 304 static bool check_5(SkDebugCanvas* canvas, int curCommand) { 305 if (TRANSLATE != canvas->getDrawCommandAt(curCommand)->getType()) { 306 return false; 307 } 308 309 SkTranslateCommand* t = 310 (SkTranslateCommand*) canvas->getDrawCommandAt(curCommand); 311 312 return 0 == t->x() && 0 == t->y(); 313 } 314 315 // Just remove the translate 316 static void apply_5(SkDebugCanvas* canvas, int curCommand) { 317 canvas->deleteDrawCommandAt(curCommand); // translate 318 } 319 320 // Check for: 321 // SCALE 322 // where the scale is 1,1 323 static bool check_6(SkDebugCanvas* canvas, int curCommand) { 324 if (SCALE != canvas->getDrawCommandAt(curCommand)->getType()) { 325 return false; 326 } 327 328 SkScaleCommand* s = (SkScaleCommand*) canvas->getDrawCommandAt(curCommand); 329 330 return SK_Scalar1 == s->x() && SK_Scalar1 == s->y(); 331 } 332 333 // Just remove the scale 334 static void apply_6(SkDebugCanvas* canvas, int curCommand) { 335 canvas->deleteDrawCommandAt(curCommand); // scale 336 } 337 338 // Check for: 339 // SAVE 340 // CLIP_RECT 341 // SAVE_LAYER 342 // SAVE 343 // CLIP_RECT 344 // SAVE_LAYER 345 // SAVE 346 // CLIP_RECT 347 // DRAWBITMAPRECTTORECT 348 // RESTORE 349 // RESTORE 350 // RESTORE 351 // RESTORE 352 // RESTORE 353 // where: 354 // all the clipRect's are BW, nested, intersections 355 // the drawBitmapRectToRect is a 1-1 copy from src to dest 356 // the last (smallest) clip rect is a subset of the drawBitmapRectToRect's dest rect 357 // all the saveLayer's paints can be rolled into the drawBitmapRectToRect's paint 358 // This pattern is used by Google spreadsheet when drawing the toolbar buttons 359 static bool check_7(SkDebugCanvas* canvas, int curCommand) { 360 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || 361 canvas->getSize() <= curCommand+13 || 362 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 363 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+2)->getType() || 364 SAVE != canvas->getDrawCommandAt(curCommand+3)->getType() || 365 CLIP_RECT != canvas->getDrawCommandAt(curCommand+4)->getType() || 366 SAVE_LAYER != canvas->getDrawCommandAt(curCommand+5)->getType() || 367 SAVE != canvas->getDrawCommandAt(curCommand+6)->getType() || 368 CLIP_RECT != canvas->getDrawCommandAt(curCommand+7)->getType() || 369 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+8)->getType() || 370 RESTORE != canvas->getDrawCommandAt(curCommand+9)->getType() || 371 RESTORE != canvas->getDrawCommandAt(curCommand+10)->getType() || 372 RESTORE != canvas->getDrawCommandAt(curCommand+11)->getType() || 373 RESTORE != canvas->getDrawCommandAt(curCommand+12)->getType() || 374 RESTORE != canvas->getDrawCommandAt(curCommand+13)->getType()) { 375 return false; 376 } 377 378 SkClipRectCommand* clip0 = 379 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); 380 SkSaveLayerCommand* saveLayer0 = 381 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); 382 SkClipRectCommand* clip1 = 383 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+4); 384 SkSaveLayerCommand* saveLayer1 = 385 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); 386 SkClipRectCommand* clip2 = 387 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); 388 SkDrawBitmapRectCommand* dbmr = 389 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); 390 391 if (clip0->doAA() || clip1->doAA() || clip2->doAA()) { 392 return false; 393 } 394 395 if (SkRegion::kIntersect_Op != clip0->op() || 396 SkRegion::kIntersect_Op != clip1->op() || 397 SkRegion::kIntersect_Op != clip2->op()) { 398 return false; 399 } 400 401 if (!clip0->rect().contains(clip1->rect()) || 402 !clip1->rect().contains(clip2->rect())) { 403 return false; 404 } 405 406 // The src->dest mapping needs to be 1-to-1 407 if (NULL == dbmr->srcRect()) { 408 if (dbmr->bitmap().width() != dbmr->dstRect().width() || 409 dbmr->bitmap().height() != dbmr->dstRect().height()) { 410 return false; 411 } 412 } else { 413 if (dbmr->srcRect()->width() != dbmr->dstRect().width() || 414 dbmr->srcRect()->height() != dbmr->dstRect().height()) { 415 return false; 416 } 417 } 418 419 if (!dbmr->dstRect().contains(clip2->rect())) { 420 return false; 421 } 422 423 const SkPaint* saveLayerPaint0 = saveLayer0->paint(); 424 const SkPaint* saveLayerPaint1 = saveLayer1->paint(); 425 426 if ((saveLayerPaint0 && !is_simple(*saveLayerPaint0)) || 427 (saveLayerPaint1 && !is_simple(*saveLayerPaint1))) { 428 return false; 429 } 430 431 SkPaint* dbmrPaint = dbmr->paint(); 432 433 if (NULL == dbmrPaint) { 434 return true; 435 } 436 437 if (saveLayerPaint0) { 438 SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque 439 if (dbmrPaint->getColor() != layerColor0) { 440 return false; 441 } 442 } 443 444 if (saveLayerPaint1) { 445 SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque 446 if (dbmrPaint->getColor() != layerColor1) { 447 return false; 448 } 449 } 450 451 return true; 452 } 453 454 // Reduce to a single drawBitmapRectToRect call by folding the clipRect's into 455 // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's 456 // paint. 457 static void apply_7(SkDebugCanvas* canvas, int curCommand) { 458 SkSaveLayerCommand* saveLayer0 = 459 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); 460 SkSaveLayerCommand* saveLayer1 = 461 (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); 462 SkClipRectCommand* clip2 = 463 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); 464 SkDrawBitmapRectCommand* dbmr = 465 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); 466 467 SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft; 468 SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop; 469 470 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, 471 clip2->rect().width(), clip2->rect().height()); 472 473 dbmr->setSrcRect(newSrc); 474 dbmr->setDstRect(clip2->rect()); 475 476 SkColor color = 0xFF000000; 477 int a0, a1; 478 479 const SkPaint* saveLayerPaint0 = saveLayer0->paint(); 480 if (saveLayerPaint0) { 481 color = saveLayerPaint0->getColor(); 482 a0 = SkColorGetA(color); 483 } else { 484 a0 = 0xFF; 485 } 486 487 const SkPaint* saveLayerPaint1 = saveLayer1->paint(); 488 if (saveLayerPaint1) { 489 color = saveLayerPaint1->getColor(); 490 a1 = SkColorGetA(color); 491 } else { 492 a1 = 0xFF; 493 } 494 495 int newA = SkMulDiv255Round(a0, a1); 496 SkASSERT(newA <= 0xFF); 497 498 SkPaint* dbmrPaint = dbmr->paint(); 499 500 if (dbmrPaint) { 501 SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA); 502 dbmrPaint->setColor(newColor); 503 } else { 504 SkColor newColor = SkColorSetA(color, newA); 505 506 SkPaint newPaint; 507 newPaint.setColor(newColor); 508 dbmr->setPaint(newPaint); 509 } 510 511 // remove everything except the drawbitmaprect 512 canvas->deleteDrawCommandAt(curCommand+13); // restore 513 canvas->deleteDrawCommandAt(curCommand+12); // restore 514 canvas->deleteDrawCommandAt(curCommand+11); // restore 515 canvas->deleteDrawCommandAt(curCommand+10); // restore 516 canvas->deleteDrawCommandAt(curCommand+9); // restore 517 canvas->deleteDrawCommandAt(curCommand+7); // clipRect 518 canvas->deleteDrawCommandAt(curCommand+6); // save 519 canvas->deleteDrawCommandAt(curCommand+5); // saveLayer 520 canvas->deleteDrawCommandAt(curCommand+4); // clipRect 521 canvas->deleteDrawCommandAt(curCommand+3); // save 522 canvas->deleteDrawCommandAt(curCommand+2); // saveLayer 523 canvas->deleteDrawCommandAt(curCommand+1); // clipRect 524 canvas->deleteDrawCommandAt(curCommand); // save 525 } 526 527 // Check for: 528 // SAVE 529 // CLIP_RECT 530 // DRAWBITMAPRECTTORECT 531 // RESTORE 532 // where: 533 // the drawBitmapRectToRect is a 1-1 copy from src to dest 534 // the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect 535 static bool check_8(SkDebugCanvas* canvas, int curCommand) { 536 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || 537 canvas->getSize() <= curCommand+4 || 538 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 539 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || 540 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { 541 return false; 542 } 543 544 SkClipRectCommand* clip = 545 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); 546 SkDrawBitmapRectCommand* dbmr = 547 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); 548 549 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { 550 return false; 551 } 552 553 // The src->dest mapping needs to be 1-to-1 554 if (NULL == dbmr->srcRect()) { 555 if (dbmr->bitmap().width() != dbmr->dstRect().width() || 556 dbmr->bitmap().height() != dbmr->dstRect().height()) { 557 return false; 558 } 559 } else { 560 if (dbmr->srcRect()->width() != dbmr->dstRect().width() || 561 dbmr->srcRect()->height() != dbmr->dstRect().height()) { 562 return false; 563 } 564 } 565 566 if (!dbmr->dstRect().contains(clip->rect())) { 567 return false; 568 } 569 570 return true; 571 } 572 573 // Fold the clipRect into the drawBitmapRectToRect's src and dest rects 574 static void apply_8(SkDebugCanvas* canvas, int curCommand) { 575 SkClipRectCommand* clip = 576 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); 577 SkDrawBitmapRectCommand* dbmr = 578 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); 579 580 SkScalar newSrcLeft, newSrcTop; 581 582 if (dbmr->srcRect()) { 583 newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect().fLeft; 584 newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect().fTop; 585 } else { 586 newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft; 587 newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop; 588 } 589 590 SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, 591 clip->rect().width(), clip->rect().height()); 592 593 dbmr->setSrcRect(newSrc); 594 dbmr->setDstRect(clip->rect()); 595 596 // remove everything except the drawbitmaprect 597 canvas->deleteDrawCommandAt(curCommand+3); 598 canvas->deleteDrawCommandAt(curCommand+1); 599 canvas->deleteDrawCommandAt(curCommand); 600 } 601 602 // Check for: 603 // SAVE 604 // CLIP_RECT 605 // DRAWBITMAPRECTTORECT 606 // RESTORE 607 // where: 608 // clipRect is BW and encloses the DBMR2R's dest rect 609 static bool check_9(SkDebugCanvas* canvas, int curCommand) { 610 if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || 611 canvas->getSize() <= curCommand+4 || 612 CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || 613 DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || 614 RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { 615 return false; 616 } 617 618 SkClipRectCommand* clip = 619 (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); 620 SkDrawBitmapRectCommand* dbmr = 621 (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); 622 623 if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { 624 return false; 625 } 626 627 if (!clip->rect().contains(dbmr->dstRect())) { 628 return false; 629 } 630 631 return true; 632 } 633 634 // remove everything except the drawbitmaprect 635 static void apply_9(SkDebugCanvas* canvas, int curCommand) { 636 canvas->deleteDrawCommandAt(curCommand+3); // restore 637 // drawBitmapRectToRect 638 canvas->deleteDrawCommandAt(curCommand+1); // clipRect 639 canvas->deleteDrawCommandAt(curCommand); // save 640 } 641 642 typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand); 643 typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand); 644 645 struct OptTableEntry { 646 PFCheck fCheck; 647 PFApply fApply; 648 int fNumTimesApplied; 649 } gOptTable[] = { 650 { check_0, apply_0, 0 }, 651 { check_1, apply_1, 0 }, 652 { check_2, apply_2, 0 }, 653 { check_3, apply_3, 0 }, 654 { check_4, apply_4, 0 }, 655 { check_5, apply_5, 0 }, 656 { check_6, apply_6, 0 }, 657 { check_7, apply_7, 0 }, 658 { check_8, apply_8, 0 }, 659 { check_9, apply_9, 0 }, 660 }; 661 662 663 static int filter_picture(const SkString& inFile, const SkString& outFile) { 664 SkAutoTDelete<SkPicture> inPicture; 665 666 SkFILEStream inStream(inFile.c_str()); 667 if (inStream.isValid()) { 668 inPicture.reset(SkPicture::CreateFromStream(&inStream)); 669 } 670 671 if (NULL == inPicture.get()) { 672 SkDebugf("Could not read file %s\n", inFile.c_str()); 673 return -1; 674 } 675 676 int localCount[SK_ARRAY_COUNT(gOptTable)]; 677 678 memset(localCount, 0, sizeof(localCount)); 679 680 SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), 681 SkScalarCeilToInt(inPicture->cullRect().height())); 682 inPicture->playback(&debugCanvas); 683 684 // delete the initial save and restore since replaying the commands will 685 // re-add them 686 if (debugCanvas.getSize() > 1) { 687 debugCanvas.deleteDrawCommandAt(0); 688 debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1); 689 } 690 691 bool changed = true; 692 int numBefore = debugCanvas.getSize(); 693 694 while (changed) { 695 changed = false; 696 for (int i = 0; i < debugCanvas.getSize(); ++i) { 697 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { 698 if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) { 699 (*gOptTable[opt].fApply)(&debugCanvas, i); 700 701 ++gOptTable[opt].fNumTimesApplied; 702 ++localCount[opt]; 703 704 if (debugCanvas.getSize() == i) { 705 // the optimization removed all the remaining operations 706 break; 707 } 708 709 opt = 0; // try all the opts all over again 710 changed = true; 711 } 712 } 713 } 714 } 715 716 int numAfter = debugCanvas.getSize(); 717 718 if (!outFile.isEmpty()) { 719 SkPictureRecorder recorder; 720 SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width(), 721 inPicture->cullRect().height(), 722 NULL, 0); 723 debugCanvas.draw(canvas); 724 SkAutoTUnref<SkPicture> outPicture(recorder.endRecording()); 725 726 SkFILEWStream outStream(outFile.c_str()); 727 728 outPicture->serialize(&outStream); 729 } 730 731 bool someOptFired = false; 732 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { 733 if (0 != localCount[opt]) { 734 SkDebugf("%d: %d ", opt, localCount[opt]); 735 someOptFired = true; 736 } 737 } 738 739 if (!someOptFired) { 740 SkDebugf("No opts fired\n"); 741 } else { 742 SkDebugf("\t before: %d after: %d delta: %d\n", 743 numBefore, numAfter, numBefore-numAfter); 744 } 745 746 return 0; 747 } 748 749 // This function is not marked as 'static' so it can be referenced externally 750 // in the iOS build. 751 int tool_main(int argc, char** argv); // suppress a warning on mac 752 753 int tool_main(int argc, char** argv) { 754 #if SK_ENABLE_INST_COUNT 755 gPrintInstCount = true; 756 #endif 757 758 SkGraphics::Init(); 759 760 if (argc < 3) { 761 usage(); 762 return -1; 763 } 764 765 SkString inFile, outFile, inDir, outDir; 766 767 char* const* stop = argv + argc; 768 for (++argv; argv < stop; ++argv) { 769 if (strcmp(*argv, "-i") == 0) { 770 argv++; 771 if (argv < stop && **argv) { 772 inFile.set(*argv); 773 } else { 774 SkDebugf("missing arg for -i\n"); 775 usage(); 776 return -1; 777 } 778 } else if (strcmp(*argv, "--input-dir") == 0) { 779 argv++; 780 if (argv < stop && **argv) { 781 inDir.set(*argv); 782 } else { 783 SkDebugf("missing arg for --input-dir\n"); 784 usage(); 785 return -1; 786 } 787 } else if (strcmp(*argv, "--output-dir") == 0) { 788 argv++; 789 if (argv < stop && **argv) { 790 outDir.set(*argv); 791 } else { 792 SkDebugf("missing arg for --output-dir\n"); 793 usage(); 794 return -1; 795 } 796 } else if (strcmp(*argv, "-o") == 0) { 797 argv++; 798 if (argv < stop && **argv) { 799 outFile.set(*argv); 800 } else { 801 SkDebugf("missing arg for -o\n"); 802 usage(); 803 return -1; 804 } 805 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { 806 usage(); 807 return 0; 808 } else { 809 SkDebugf("unknown arg %s\n", *argv); 810 usage(); 811 return -1; 812 } 813 } 814 815 SkOSFile::Iter iter(inDir.c_str(), "skp"); 816 817 SkString inputFilename, outputFilename; 818 if (iter.next(&inputFilename)) { 819 820 do { 821 inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str()); 822 if (!outDir.isEmpty()) { 823 outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str()); 824 } 825 SkDebugf("Executing %s\n", inputFilename.c_str()); 826 filter_picture(inFile, outFile); 827 } while(iter.next(&inputFilename)); 828 829 } else if (!inFile.isEmpty()) { 830 filter_picture(inFile, outFile); 831 } else { 832 usage(); 833 return -1; 834 } 835 836 for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { 837 SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied); 838 } 839 840 SkGraphics::Term(); 841 return 0; 842 } 843 844 #if !defined SK_BUILD_FOR_IOS 845 int main(int argc, char * const argv[]) { 846 return tool_main(argc, (char**) argv); 847 } 848 #endif 849