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