summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/skia/tools/filtermain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/skia/tools/filtermain.cpp')
-rw-r--r--chromium/third_party/skia/tools/filtermain.cpp847
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