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