diff options
Diffstat (limited to 'chromium/third_party/skia/tools/filtermain.cpp')
-rw-r--r-- | chromium/third_party/skia/tools/filtermain.cpp | 847 |
1 files changed, 847 insertions, 0 deletions
diff --git a/chromium/third_party/skia/tools/filtermain.cpp b/chromium/third_party/skia/tools/filtermain.cpp new file mode 100644 index 00000000000..2a404f92cf1 --- /dev/null +++ b/chromium/third_party/skia/tools/filtermain.cpp @@ -0,0 +1,847 @@ +/* + * 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 "SkPicturePlayback.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 (NULL != 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 (NULL != 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 (NULL != 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 ((NULL != saveLayerPaint0 && !is_simple(*saveLayerPaint0)) || + (NULL != saveLayerPaint1 && !is_simple(*saveLayerPaint1))) { + return false; + } + + SkPaint* dbmrPaint = dbmr->paint(); + + if (NULL == dbmrPaint) { + return true; + } + + if (NULL != saveLayerPaint0) { + SkColor layerColor0 = saveLayerPaint0->getColor() | 0xFF000000; // force opaque + if (dbmrPaint->getColor() != layerColor0) { + return false; + } + } + + if (NULL != 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 (NULL != saveLayerPaint0) { + color = saveLayerPaint0->getColor(); + a0 = SkColorGetA(color); + } else { + a0 = 0xFF; + } + + const SkPaint* saveLayerPaint1 = saveLayer1->paint(); + if (NULL != saveLayerPaint1) { + color = saveLayerPaint1->getColor(); + a1 = SkColorGetA(color); + } else { + a1 = 0xFF; + } + + int newA = SkMulDiv255Round(a0, a1); + SkASSERT(newA <= 0xFF); + + SkPaint* dbmrPaint = dbmr->paint(); + + if (NULL != 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 (NULL != 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) { + SkAutoTDelete<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(inPicture->width(), inPicture->height()); + debugCanvas.setBounds(inPicture->width(), inPicture->height()); + inPicture->draw(&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->width(), inPicture->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::SkPathJoin(inDir.c_str(), inputFilename.c_str()); + if (!outDir.isEmpty()) { + outFile = SkOSPath::SkPathJoin(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 |