skia2/tools/filtermain.cpp
mtklein 2766c00fc0 remove SkInstCnt
It's been outclassed by Valgrind and leak sanitizer,
and it seems to be causing problems for external folks building Skia.

I'm not sure why our own builds seem unaffected.

Latest thread:
https://groups.google.com/forum/#!topic/skia-discuss/oj9FsQwwSF0

BUG=skia:

Review URL: https://codereview.chromium.org/1217573002
2015-06-26 11:45:03 -07:00

806 lines
28 KiB
C++

/*
* 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 (SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+2 ||
SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kRestore_OpType != 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 (SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+5 ||
SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+3)->getType() ||
SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+4)->getType() ||
SkDrawCommand::kRestore_OpType != 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 (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+4 ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kDrawRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kRestore_OpType != 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 (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+4 ||
SkDrawCommand::kClipRRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kDrawRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kRestore_OpType != 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 (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+4 ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kRestore_OpType != 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:
// 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 (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+13 ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+3)->getType() ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+4)->getType() ||
SkDrawCommand::kSaveLayer_OpType != canvas->getDrawCommandAt(curCommand+5)->getType() ||
SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand+6)->getType() ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+7)->getType() ||
SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+8)->getType() ||
SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+9)->getType() ||
SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+10)->getType() ||
SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+11)->getType() ||
SkDrawCommand::kRestore_OpType != canvas->getDrawCommandAt(curCommand+12)->getType() ||
SkDrawCommand::kRestore_OpType != 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 (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+4 ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kRestore_OpType != 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 (SkDrawCommand::kSave_OpType != canvas->getDrawCommandAt(curCommand)->getType() ||
canvas->getSize() <= curCommand+4 ||
SkDrawCommand::kClipRect_OpType != canvas->getDrawCommandAt(curCommand+1)->getType() ||
SkDrawCommand::kDrawBitmapRect_OpType != canvas->getDrawCommandAt(curCommand+2)->getType() ||
SkDrawCommand::kRestore_OpType != 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_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) {
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