| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkDebugCanvas.h" |
| #include "SkDevice.h" |
| #include "SkForceLinking.h" |
| #include "SkGraphics.h" |
| #include "SkImageDecoder.h" |
| #include "SkImageEncoder.h" |
| #include "SkOSFile.h" |
| #include "SkPicture.h" |
| #include "SkPictureRecord.h" |
| #include "SkPictureRecorder.h" |
| #include "SkStream.h" |
| #include "picture_utils.h" |
| |
| __SK_FORCE_IMAGE_DECODER_LINKING; |
| |
| static void usage() { |
| SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n"); |
| SkDebugf(" [-h|--help]\n\n"); |
| SkDebugf(" -i inFile : file to filter.\n"); |
| SkDebugf(" -o outFile : result of filtering.\n"); |
| SkDebugf(" --input-dir : process all files in dir with .skp extension.\n"); |
| SkDebugf(" --output-dir : results of filtering the input dir.\n"); |
| SkDebugf(" -h|--help : Show this help message.\n"); |
| } |
| |
| // Is the supplied paint simply a color? |
| static bool is_simple(const SkPaint& p) { |
| return NULL == p.getPathEffect() && |
| NULL == p.getShader() && |
| NULL == p.getXfermode() && |
| NULL == p.getMaskFilter() && |
| NULL == p.getColorFilter() && |
| NULL == p.getRasterizer() && |
| NULL == p.getLooper() && |
| NULL == p.getImageFilter(); |
| } |
| |
| |
| // Check for: |
| // SAVE_LAYER |
| // DRAW_BITMAP_RECT_TO_RECT |
| // RESTORE |
| // where the saveLayer's color can be moved into the drawBitmapRect |
| static bool check_0(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+2 || |
| DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+2)->getType()) { |
| return false; |
| } |
| |
| SkSaveLayerCommand* saveLayer = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| |
| const SkPaint* saveLayerPaint = saveLayer->paint(); |
| SkPaint* dbmrPaint = dbmr->paint(); |
| |
| // For this optimization we only fold the saveLayer and drawBitmapRect |
| // together if the saveLayer's draw is simple (i.e., no fancy effects) |
| // and the only difference in the colors is their alpha value |
| SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque |
| SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000; // force opaque |
| |
| // If either operation lacks a paint then the collapse is trivial |
| return NULL == saveLayerPaint || |
| NULL == dbmrPaint || |
| (is_simple(*saveLayerPaint) && dbmrColor == layerColor); |
| } |
| |
| // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer |
| // and restore |
| static void apply_0(SkDebugCanvas* canvas, int curCommand) { |
| SkSaveLayerCommand* saveLayer = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); |
| const SkPaint* saveLayerPaint = saveLayer->paint(); |
| |
| // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed |
| if (saveLayerPaint) { |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkPaint* dbmrPaint = dbmr->paint(); |
| |
| if (NULL == dbmrPaint) { |
| // if the DBMR doesn't have a paint just use the saveLayer's |
| dbmr->setPaint(*saveLayerPaint); |
| } else if (saveLayerPaint) { |
| // Both paints are present so their alphas need to be combined |
| SkColor color = saveLayerPaint->getColor(); |
| int a0 = SkColorGetA(color); |
| |
| color = dbmrPaint->getColor(); |
| int a1 = SkColorGetA(color); |
| |
| int newA = SkMulDiv255Round(a0, a1); |
| SkASSERT(newA <= 0xFF); |
| |
| SkColor newColor = SkColorSetA(color, newA); |
| dbmrPaint->setColor(newColor); |
| } |
| } |
| |
| canvas->deleteDrawCommandAt(curCommand+2); // restore |
| canvas->deleteDrawCommandAt(curCommand); // saveLayer |
| } |
| |
| // Check for: |
| // SAVE_LAYER |
| // SAVE |
| // CLIP_RECT |
| // DRAW_BITMAP_RECT_TO_RECT |
| // RESTORE |
| // RESTORE |
| // where the saveLayer's color can be moved into the drawBitmapRect |
| static bool check_1(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+5 || |
| SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+5)->getType()) { |
| return false; |
| } |
| |
| SkSaveLayerCommand* saveLayer = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); |
| |
| const SkPaint* saveLayerPaint = saveLayer->paint(); |
| SkPaint* dbmrPaint = dbmr->paint(); |
| |
| // For this optimization we only fold the saveLayer and drawBitmapRect |
| // together if the saveLayer's draw is simple (i.e., no fancy effects) and |
| // and the only difference in the colors is that the saveLayer's can have |
| // an alpha while the drawBitmapRect's is opaque. |
| // TODO: it should be possible to fold them together even if they both |
| // have different non-255 alphas but this is low priority since we have |
| // never seen that case |
| // If either operation lacks a paint then the collapse is trivial |
| SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque |
| |
| return NULL == saveLayerPaint || |
| NULL == dbmrPaint || |
| (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor); |
| } |
| |
| // Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer |
| // and restore |
| static void apply_1(SkDebugCanvas* canvas, int curCommand) { |
| SkSaveLayerCommand* saveLayer = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); |
| const SkPaint* saveLayerPaint = saveLayer->paint(); |
| |
| // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed |
| if (saveLayerPaint) { |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); |
| SkPaint* dbmrPaint = dbmr->paint(); |
| |
| if (NULL == dbmrPaint) { |
| dbmr->setPaint(*saveLayerPaint); |
| } else { |
| SkColor newColor = SkColorSetA(dbmrPaint->getColor(), |
| SkColorGetA(saveLayerPaint->getColor())); |
| dbmrPaint->setColor(newColor); |
| } |
| } |
| |
| canvas->deleteDrawCommandAt(curCommand+5); // restore |
| canvas->deleteDrawCommandAt(curCommand); // saveLayer |
| } |
| |
| // Check for: |
| // SAVE |
| // CLIP_RECT |
| // DRAW_RECT |
| // RESTORE |
| // where the rect is entirely within the clip and the clip is an intersect |
| static bool check_2(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+4 || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { |
| return false; |
| } |
| |
| SkClipRectCommand* cr = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawRectCommand* dr = |
| (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| if (SkRegion::kIntersect_Op != cr->op()) { |
| return false; |
| } |
| |
| return cr->rect().contains(dr->rect()); |
| } |
| |
| // Remove everything but the drawRect |
| static void apply_2(SkDebugCanvas* canvas, int curCommand) { |
| canvas->deleteDrawCommandAt(curCommand+3); // restore |
| // drawRect |
| canvas->deleteDrawCommandAt(curCommand+1); // clipRect |
| canvas->deleteDrawCommandAt(curCommand); // save |
| } |
| |
| // Check for: |
| // SAVE |
| // CLIP_RRECT |
| // DRAW_RECT |
| // RESTORE |
| // where the rect entirely encloses the clip |
| static bool check_3(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+4 || |
| CLIP_RRECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| DRAW_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { |
| return false; |
| } |
| |
| SkClipRRectCommand* crr = |
| (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawRectCommand* dr = |
| (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| if (SkRegion::kIntersect_Op != crr->op()) { |
| return false; |
| } |
| |
| return dr->rect().contains(crr->rrect().rect()); |
| } |
| |
| // Replace everything with a drawRRect with the paint from the drawRect |
| // and the AA settings from the clipRRect |
| static void apply_3(SkDebugCanvas* canvas, int curCommand) { |
| |
| canvas->deleteDrawCommandAt(curCommand+3); // restore |
| |
| SkClipRRectCommand* crr = |
| (SkClipRRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawRectCommand* dr = |
| (SkDrawRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| // TODO: could skip paint re-creation if the AA settings already match |
| SkPaint newPaint = dr->paint(); |
| newPaint.setAntiAlias(crr->doAA()); |
| SkDrawRRectCommand* drr = new SkDrawRRectCommand(crr->rrect(), newPaint); |
| canvas->setDrawCommandAt(curCommand+2, drr); |
| |
| canvas->deleteDrawCommandAt(curCommand+1); // clipRRect |
| canvas->deleteDrawCommandAt(curCommand); // save |
| } |
| |
| // Check for: |
| // SAVE |
| // CLIP_RECT |
| // DRAW_BITMAP_RECT_TO_RECT |
| // RESTORE |
| // where the rect and drawBitmapRect dst exactly match |
| static bool check_4(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+4 || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { |
| return false; |
| } |
| |
| SkClipRectCommand* cr = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| if (SkRegion::kIntersect_Op != cr->op()) { |
| return false; |
| } |
| |
| return dbmr->dstRect() == cr->rect(); |
| } |
| |
| // Remove everything but the drawBitmapRect |
| static void apply_4(SkDebugCanvas* canvas, int curCommand) { |
| canvas->deleteDrawCommandAt(curCommand+3); // restore |
| // drawBitmapRectToRect |
| canvas->deleteDrawCommandAt(curCommand+1); // clipRect |
| canvas->deleteDrawCommandAt(curCommand); // save |
| } |
| |
| // Check for: |
| // TRANSLATE |
| // where the translate is zero |
| static bool check_5(SkDebugCanvas* canvas, int curCommand) { |
| if (TRANSLATE != canvas->getDrawCommandAt(curCommand)->getType()) { |
| return false; |
| } |
| |
| SkTranslateCommand* t = |
| (SkTranslateCommand*) canvas->getDrawCommandAt(curCommand); |
| |
| return 0 == t->x() && 0 == t->y(); |
| } |
| |
| // Just remove the translate |
| static void apply_5(SkDebugCanvas* canvas, int curCommand) { |
| canvas->deleteDrawCommandAt(curCommand); // translate |
| } |
| |
| // Check for: |
| // SCALE |
| // where the scale is 1,1 |
| static bool check_6(SkDebugCanvas* canvas, int curCommand) { |
| if (SCALE != canvas->getDrawCommandAt(curCommand)->getType()) { |
| return false; |
| } |
| |
| SkScaleCommand* s = (SkScaleCommand*) canvas->getDrawCommandAt(curCommand); |
| |
| return SK_Scalar1 == s->x() && SK_Scalar1 == s->y(); |
| } |
| |
| // Just remove the scale |
| static void apply_6(SkDebugCanvas* canvas, int curCommand) { |
| canvas->deleteDrawCommandAt(curCommand); // scale |
| } |
| |
| // Check for: |
| // SAVE |
| // CLIP_RECT |
| // SAVE_LAYER |
| // SAVE |
| // CLIP_RECT |
| // SAVE_LAYER |
| // SAVE |
| // CLIP_RECT |
| // DRAWBITMAPRECTTORECT |
| // RESTORE |
| // RESTORE |
| // RESTORE |
| // RESTORE |
| // RESTORE |
| // where: |
| // all the clipRect's are BW, nested, intersections |
| // the drawBitmapRectToRect is a 1-1 copy from src to dest |
| // the last (smallest) clip rect is a subset of the drawBitmapRectToRect's dest rect |
| // all the saveLayer's paints can be rolled into the drawBitmapRectToRect's paint |
| // This pattern is used by Google spreadsheet when drawing the toolbar buttons |
| static bool check_7(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+13 || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| SAVE_LAYER != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| SAVE != canvas->getDrawCommandAt(curCommand+3)->getType() || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+4)->getType() || |
| SAVE_LAYER != canvas->getDrawCommandAt(curCommand+5)->getType() || |
| SAVE != canvas->getDrawCommandAt(curCommand+6)->getType() || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+7)->getType() || |
| DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+8)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+9)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+10)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+11)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+12)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+13)->getType()) { |
| return false; |
| } |
| |
| SkClipRectCommand* clip0 = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkSaveLayerCommand* saveLayer0 = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); |
| SkClipRectCommand* clip1 = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+4); |
| SkSaveLayerCommand* saveLayer1 = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); |
| SkClipRectCommand* clip2 = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); |
| |
| if (clip0->doAA() || clip1->doAA() || clip2->doAA()) { |
| return false; |
| } |
| |
| if (SkRegion::kIntersect_Op != clip0->op() || |
| SkRegion::kIntersect_Op != clip1->op() || |
| SkRegion::kIntersect_Op != clip2->op()) { |
| return false; |
| } |
| |
| if (!clip0->rect().contains(clip1->rect()) || |
| !clip1->rect().contains(clip2->rect())) { |
| return false; |
| } |
| |
| // The src->dest mapping needs to be 1-to-1 |
| if (NULL == dbmr->srcRect()) { |
| if (dbmr->bitmap().width() != dbmr->dstRect().width() || |
| dbmr->bitmap().height() != dbmr->dstRect().height()) { |
| return false; |
| } |
| } else { |
| if (dbmr->srcRect()->width() != dbmr->dstRect().width() || |
| dbmr->srcRect()->height() != dbmr->dstRect().height()) { |
| return false; |
| } |
| } |
| |
| if (!dbmr->dstRect().contains(clip2->rect())) { |
| return false; |
| } |
| |
| const SkPaint* saveLayerPaint0 = saveLayer0->paint(); |
| const SkPaint* saveLayerPaint1 = saveLayer1->paint(); |
| |
| if ((saveLayerPaint0 && !is_simple(*saveLayerPaint0)) || |
| (saveLayerPaint1 && !is_simple(*saveLayerPaint1))) { |
| return false; |
| } |
| |
| SkPaint* dbmrPaint = dbmr->paint(); |
| |
| if (NULL == dbmrPaint) { |
| return true; |
| } |
| |
| if (saveLayerPaint0) { |
| SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque |
| if (dbmrPaint->getColor() != layerColor0) { |
| return false; |
| } |
| } |
| |
| if (saveLayerPaint1) { |
| SkColor layerColor1 = saveLayerPaint1->getColor() | 0xFF000000; // force opaque |
| if (dbmrPaint->getColor() != layerColor1) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| // Reduce to a single drawBitmapRectToRect call by folding the clipRect's into |
| // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's |
| // paint. |
| static void apply_7(SkDebugCanvas* canvas, int curCommand) { |
| SkSaveLayerCommand* saveLayer0 = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); |
| SkSaveLayerCommand* saveLayer1 = |
| (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); |
| SkClipRectCommand* clip2 = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); |
| |
| SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft; |
| SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop; |
| |
| SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, |
| clip2->rect().width(), clip2->rect().height()); |
| |
| dbmr->setSrcRect(newSrc); |
| dbmr->setDstRect(clip2->rect()); |
| |
| SkColor color = 0xFF000000; |
| int a0, a1; |
| |
| const SkPaint* saveLayerPaint0 = saveLayer0->paint(); |
| if (saveLayerPaint0) { |
| color = saveLayerPaint0->getColor(); |
| a0 = SkColorGetA(color); |
| } else { |
| a0 = 0xFF; |
| } |
| |
| const SkPaint* saveLayerPaint1 = saveLayer1->paint(); |
| if (saveLayerPaint1) { |
| color = saveLayerPaint1->getColor(); |
| a1 = SkColorGetA(color); |
| } else { |
| a1 = 0xFF; |
| } |
| |
| int newA = SkMulDiv255Round(a0, a1); |
| SkASSERT(newA <= 0xFF); |
| |
| SkPaint* dbmrPaint = dbmr->paint(); |
| |
| if (dbmrPaint) { |
| SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA); |
| dbmrPaint->setColor(newColor); |
| } else { |
| SkColor newColor = SkColorSetA(color, newA); |
| |
| SkPaint newPaint; |
| newPaint.setColor(newColor); |
| dbmr->setPaint(newPaint); |
| } |
| |
| // remove everything except the drawbitmaprect |
| canvas->deleteDrawCommandAt(curCommand+13); // restore |
| canvas->deleteDrawCommandAt(curCommand+12); // restore |
| canvas->deleteDrawCommandAt(curCommand+11); // restore |
| canvas->deleteDrawCommandAt(curCommand+10); // restore |
| canvas->deleteDrawCommandAt(curCommand+9); // restore |
| canvas->deleteDrawCommandAt(curCommand+7); // clipRect |
| canvas->deleteDrawCommandAt(curCommand+6); // save |
| canvas->deleteDrawCommandAt(curCommand+5); // saveLayer |
| canvas->deleteDrawCommandAt(curCommand+4); // clipRect |
| canvas->deleteDrawCommandAt(curCommand+3); // save |
| canvas->deleteDrawCommandAt(curCommand+2); // saveLayer |
| canvas->deleteDrawCommandAt(curCommand+1); // clipRect |
| canvas->deleteDrawCommandAt(curCommand); // save |
| } |
| |
| // Check for: |
| // SAVE |
| // CLIP_RECT |
| // DRAWBITMAPRECTTORECT |
| // RESTORE |
| // where: |
| // the drawBitmapRectToRect is a 1-1 copy from src to dest |
| // the clip rect is BW and a subset of the drawBitmapRectToRect's dest rect |
| static bool check_8(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+4 || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { |
| return false; |
| } |
| |
| SkClipRectCommand* clip = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { |
| return false; |
| } |
| |
| // The src->dest mapping needs to be 1-to-1 |
| if (NULL == dbmr->srcRect()) { |
| if (dbmr->bitmap().width() != dbmr->dstRect().width() || |
| dbmr->bitmap().height() != dbmr->dstRect().height()) { |
| return false; |
| } |
| } else { |
| if (dbmr->srcRect()->width() != dbmr->dstRect().width() || |
| dbmr->srcRect()->height() != dbmr->dstRect().height()) { |
| return false; |
| } |
| } |
| |
| if (!dbmr->dstRect().contains(clip->rect())) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // Fold the clipRect into the drawBitmapRectToRect's src and dest rects |
| static void apply_8(SkDebugCanvas* canvas, int curCommand) { |
| SkClipRectCommand* clip = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| SkScalar newSrcLeft, newSrcTop; |
| |
| if (dbmr->srcRect()) { |
| newSrcLeft = dbmr->srcRect()->fLeft + clip->rect().fLeft - dbmr->dstRect().fLeft; |
| newSrcTop = dbmr->srcRect()->fTop + clip->rect().fTop - dbmr->dstRect().fTop; |
| } else { |
| newSrcLeft = clip->rect().fLeft - dbmr->dstRect().fLeft; |
| newSrcTop = clip->rect().fTop - dbmr->dstRect().fTop; |
| } |
| |
| SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, |
| clip->rect().width(), clip->rect().height()); |
| |
| dbmr->setSrcRect(newSrc); |
| dbmr->setDstRect(clip->rect()); |
| |
| // remove everything except the drawbitmaprect |
| canvas->deleteDrawCommandAt(curCommand+3); |
| canvas->deleteDrawCommandAt(curCommand+1); |
| canvas->deleteDrawCommandAt(curCommand); |
| } |
| |
| // Check for: |
| // SAVE |
| // CLIP_RECT |
| // DRAWBITMAPRECTTORECT |
| // RESTORE |
| // where: |
| // clipRect is BW and encloses the DBMR2R's dest rect |
| static bool check_9(SkDebugCanvas* canvas, int curCommand) { |
| if (SAVE != canvas->getDrawCommandAt(curCommand)->getType() || |
| canvas->getSize() <= curCommand+4 || |
| CLIP_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() || |
| DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() || |
| RESTORE != canvas->getDrawCommandAt(curCommand+3)->getType()) { |
| return false; |
| } |
| |
| SkClipRectCommand* clip = |
| (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+1); |
| SkDrawBitmapRectCommand* dbmr = |
| (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+2); |
| |
| if (clip->doAA() || SkRegion::kIntersect_Op != clip->op()) { |
| return false; |
| } |
| |
| if (!clip->rect().contains(dbmr->dstRect())) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // remove everything except the drawbitmaprect |
| static void apply_9(SkDebugCanvas* canvas, int curCommand) { |
| canvas->deleteDrawCommandAt(curCommand+3); // restore |
| // drawBitmapRectToRect |
| canvas->deleteDrawCommandAt(curCommand+1); // clipRect |
| canvas->deleteDrawCommandAt(curCommand); // save |
| } |
| |
| typedef bool (*PFCheck)(SkDebugCanvas* canvas, int curCommand); |
| typedef void (*PFApply)(SkDebugCanvas* canvas, int curCommand); |
| |
| struct OptTableEntry { |
| PFCheck fCheck; |
| PFApply fApply; |
| int fNumTimesApplied; |
| } gOptTable[] = { |
| { check_0, apply_0, 0 }, |
| { check_1, apply_1, 0 }, |
| { check_2, apply_2, 0 }, |
| { check_3, apply_3, 0 }, |
| { check_4, apply_4, 0 }, |
| { check_5, apply_5, 0 }, |
| { check_6, apply_6, 0 }, |
| { check_7, apply_7, 0 }, |
| { check_8, apply_8, 0 }, |
| { check_9, apply_9, 0 }, |
| }; |
| |
| |
| static int filter_picture(const SkString& inFile, const SkString& outFile) { |
| SkAutoTUnref<SkPicture> inPicture; |
| |
| SkFILEStream inStream(inFile.c_str()); |
| if (inStream.isValid()) { |
| inPicture.reset(SkPicture::CreateFromStream(&inStream)); |
| } |
| |
| if (NULL == inPicture.get()) { |
| SkDebugf("Could not read file %s\n", inFile.c_str()); |
| return -1; |
| } |
| |
| int localCount[SK_ARRAY_COUNT(gOptTable)]; |
| |
| memset(localCount, 0, sizeof(localCount)); |
| |
| SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), |
| SkScalarCeilToInt(inPicture->cullRect().height())); |
| inPicture->playback(&debugCanvas); |
| |
| // delete the initial save and restore since replaying the commands will |
| // re-add them |
| if (debugCanvas.getSize() > 1) { |
| debugCanvas.deleteDrawCommandAt(0); |
| debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1); |
| } |
| |
| bool changed = true; |
| int numBefore = debugCanvas.getSize(); |
| |
| while (changed) { |
| changed = false; |
| for (int i = 0; i < debugCanvas.getSize(); ++i) { |
| for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { |
| if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) { |
| (*gOptTable[opt].fApply)(&debugCanvas, i); |
| |
| ++gOptTable[opt].fNumTimesApplied; |
| ++localCount[opt]; |
| |
| if (debugCanvas.getSize() == i) { |
| // the optimization removed all the remaining operations |
| break; |
| } |
| |
| opt = 0; // try all the opts all over again |
| changed = true; |
| } |
| } |
| } |
| } |
| |
| int numAfter = debugCanvas.getSize(); |
| |
| if (!outFile.isEmpty()) { |
| SkPictureRecorder recorder; |
| SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width(), |
| inPicture->cullRect().height(), |
| NULL, 0); |
| debugCanvas.draw(canvas); |
| SkAutoTUnref<SkPicture> outPicture(recorder.endRecording()); |
| |
| SkFILEWStream outStream(outFile.c_str()); |
| |
| outPicture->serialize(&outStream); |
| } |
| |
| bool someOptFired = false; |
| for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { |
| if (0 != localCount[opt]) { |
| SkDebugf("%d: %d ", opt, localCount[opt]); |
| someOptFired = true; |
| } |
| } |
| |
| if (!someOptFired) { |
| SkDebugf("No opts fired\n"); |
| } else { |
| SkDebugf("\t before: %d after: %d delta: %d\n", |
| numBefore, numAfter, numBefore-numAfter); |
| } |
| |
| return 0; |
| } |
| |
| // This function is not marked as 'static' so it can be referenced externally |
| // in the iOS build. |
| int tool_main(int argc, char** argv); // suppress a warning on mac |
| |
| int tool_main(int argc, char** argv) { |
| #if SK_ENABLE_INST_COUNT |
| gPrintInstCount = true; |
| #endif |
| |
| SkGraphics::Init(); |
| |
| if (argc < 3) { |
| usage(); |
| return -1; |
| } |
| |
| SkString inFile, outFile, inDir, outDir; |
| |
| char* const* stop = argv + argc; |
| for (++argv; argv < stop; ++argv) { |
| if (strcmp(*argv, "-i") == 0) { |
| argv++; |
| if (argv < stop && **argv) { |
| inFile.set(*argv); |
| } else { |
| SkDebugf("missing arg for -i\n"); |
| usage(); |
| return -1; |
| } |
| } else if (strcmp(*argv, "--input-dir") == 0) { |
| argv++; |
| if (argv < stop && **argv) { |
| inDir.set(*argv); |
| } else { |
| SkDebugf("missing arg for --input-dir\n"); |
| usage(); |
| return -1; |
| } |
| } else if (strcmp(*argv, "--output-dir") == 0) { |
| argv++; |
| if (argv < stop && **argv) { |
| outDir.set(*argv); |
| } else { |
| SkDebugf("missing arg for --output-dir\n"); |
| usage(); |
| return -1; |
| } |
| } else if (strcmp(*argv, "-o") == 0) { |
| argv++; |
| if (argv < stop && **argv) { |
| outFile.set(*argv); |
| } else { |
| SkDebugf("missing arg for -o\n"); |
| usage(); |
| return -1; |
| } |
| } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { |
| usage(); |
| return 0; |
| } else { |
| SkDebugf("unknown arg %s\n", *argv); |
| usage(); |
| return -1; |
| } |
| } |
| |
| SkOSFile::Iter iter(inDir.c_str(), "skp"); |
| |
| SkString inputFilename, outputFilename; |
| if (iter.next(&inputFilename)) { |
| |
| do { |
| inFile = SkOSPath::Join(inDir.c_str(), inputFilename.c_str()); |
| if (!outDir.isEmpty()) { |
| outFile = SkOSPath::Join(outDir.c_str(), inputFilename.c_str()); |
| } |
| SkDebugf("Executing %s\n", inputFilename.c_str()); |
| filter_picture(inFile, outFile); |
| } while(iter.next(&inputFilename)); |
| |
| } else if (!inFile.isEmpty()) { |
| filter_picture(inFile, outFile); |
| } else { |
| usage(); |
| return -1; |
| } |
| |
| for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { |
| SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied); |
| } |
| |
| SkGraphics::Term(); |
| return 0; |
| } |
| |
| #if !defined SK_BUILD_FOR_IOS |
| int main(int argc, char * const argv[]) { |
| return tool_main(argc, (char**) argv); |
| } |
| #endif |