Update filter tool to allow more flexible filtering

https://codereview.appspot.com/7227055/



git-svn-id: http://skia.googlecode.com/svn/trunk@7492 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/debugger/SkDebugCanvas.cpp b/debugger/SkDebugCanvas.cpp
index e4cfec8..7be729c 100644
--- a/debugger/SkDebugCanvas.cpp
+++ b/debugger/SkDebugCanvas.cpp
@@ -10,7 +10,6 @@
 #include "SkDebugCanvas.h"
 #include "SkDrawCommand.h"
 #include "SkDevice.h"
-#include "SkImageWidget.h"
 
 #ifdef SK_BUILD_FOR_WIN
     // iostream includes xlocale which generates warning 4530 because we're compiling without
@@ -179,8 +178,8 @@
 static SkBitmap createBitmap(const SkPath& path) {
     SkBitmap bitmap;
     bitmap.setConfig(SkBitmap::kARGB_8888_Config,
-                     SkImageWidget::kImageWidgetWidth,
-                     SkImageWidget::kImageWidgetHeight);
+                     SkDebugCanvas::kVizImageWidth,
+                     SkDebugCanvas::kVizImageHeight);
     bitmap.allocPixels();
     bitmap.eraseColor(SK_ColorWHITE);
     SkDevice* device = new SkDevice(bitmap);
@@ -191,11 +190,11 @@
     const SkRect& bounds = path.getBounds();
 
     if (bounds.width() > bounds.height()) {
-        canvas.scale(SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetWidth)/bounds.width()),
-                     SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetHeight)/bounds.width()));
+        canvas.scale(SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageWidth)/bounds.width()),
+                     SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageHeight)/bounds.width()));
     } else {
-        canvas.scale(SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetWidth)/bounds.height()),
-                     SkDoubleToScalar((0.9*SkImageWidget::kImageWidgetHeight)/bounds.height()));
+        canvas.scale(SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageWidth)/bounds.height()),
+                     SkDoubleToScalar((0.9*SkDebugCanvas::kVizImageHeight)/bounds.height()));
     }
     canvas.translate(-bounds.fLeft+2, -bounds.fTop+2);
 
@@ -211,8 +210,8 @@
 static SkBitmap createBitmap(const SkBitmap& input, const SkRect* srcRect) {
     SkBitmap bitmap;
     bitmap.setConfig(SkBitmap::kARGB_8888_Config,
-                     SkImageWidget::kImageWidgetWidth,
-                     SkImageWidget::kImageWidgetHeight);
+                     SkDebugCanvas::kVizImageWidth,
+                     SkDebugCanvas::kVizImageHeight);
     bitmap.allocPixels();
     bitmap.eraseColor(SK_ColorLTGRAY);
     SkDevice* device = new SkDevice(bitmap);
@@ -220,8 +219,8 @@
     SkCanvas canvas(device);
     device->unref();
 
-    SkScalar xScale = (SkImageWidget::kImageWidgetWidth-2.0) / input.width();
-    SkScalar yScale = (SkImageWidget::kImageWidgetHeight-2.0) / input.height();
+    SkScalar xScale = SkIntToScalar(SkDebugCanvas::kVizImageWidth-2) / input.width();
+    SkScalar yScale = SkIntToScalar(SkDebugCanvas::kVizImageHeight-2) / input.height();
 
     if (input.width() > input.height()) {
         yScale *= input.height() / (float) input.width();
diff --git a/debugger/SkDebugCanvas.h b/debugger/SkDebugCanvas.h
index aafa802..238c5c0 100644
--- a/debugger/SkDebugCanvas.h
+++ b/debugger/SkDebugCanvas.h
@@ -200,8 +200,10 @@
 
     virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
 
+    static const int kVizImageHeight = 256;
+    static const int kVizImageWidth = 256;
+
 private:
-    typedef SkCanvas INHERITED;
     SkTDArray<SkDrawCommand*> fCommandVector;
     int fHeight;
     int fWidth;
@@ -231,6 +233,8 @@
         drawing anything else into the canvas.
      */
     void applyUserTransform(SkCanvas* canvas);
+
+    typedef SkCanvas INHERITED;
 };
 
 #endif
diff --git a/debugger/SkDrawCommand.cpp b/debugger/SkDrawCommand.cpp
index a2459b3..dce0af6 100644
--- a/debugger/SkDrawCommand.cpp
+++ b/debugger/SkDrawCommand.cpp
@@ -230,7 +230,12 @@
     this->fBitmap = &bitmap;
     this->fSrc = src;
     this->fDst = &dst;
-    this->fPaint = paint;
+    if (NULL != paint) {
+        this->fPaint = *paint;
+        this->fPaintPtr = &this->fPaint;
+    } else {
+        this->fPaintPtr = NULL;
+    }
     this->fDrawType = DRAW_BITMAP_RECT_TO_RECT;
     this->fResizedBitmap = resizedBitmap;
 
@@ -245,7 +250,7 @@
 }
 
 void DrawBitmapRect::execute(SkCanvas* canvas) {
-    canvas->drawBitmapRectToRect(*this->fBitmap, this->fSrc, *this->fDst, this->fPaint);
+    canvas->drawBitmapRectToRect(*this->fBitmap, this->fSrc, *this->fDst, this->fPaintPtr);
 }
 
 const SkBitmap* DrawBitmapRect::getBitmap() const {
diff --git a/debugger/SkDrawCommand.h b/debugger/SkDrawCommand.h
index 98cfbc9..fba5a01 100644
--- a/debugger/SkDrawCommand.h
+++ b/debugger/SkDrawCommand.h
@@ -163,9 +163,20 @@
             const SkRect& dst, const SkPaint* paint, SkBitmap& resizedBitmap);
     virtual void execute(SkCanvas* canvas) SK_OVERRIDE;
     virtual const SkBitmap* getBitmap() const SK_OVERRIDE;
+
+    // The non-const 'paint' method allows modification of this object's
+    // SkPaint. For this reason the ctor and setPaint method make a local copy.
+    // The 'fPaintPtr' member acts a signal that the local SkPaint is valid
+    // (since only an SkPaint* is passed into the ctor).
+    const SkPaint* paint() const { return fPaintPtr; }
+    SkPaint* paint() { return fPaintPtr; }
+
+    void setPaint(const SkPaint& paint) { fPaint = paint; fPaintPtr = &fPaint; }
+
 private:
     const SkRect* fSrc;
-    const SkPaint* fPaint;
+    SkPaint fPaint;
+    SkPaint* fPaintPtr;
     const SkBitmap* fBitmap;
     const SkRect* fDst;
     SkBitmap fResizedBitmap;
@@ -357,6 +368,9 @@
             SkCanvas::SaveFlags flags);
     virtual void execute(SkCanvas* canvas) SK_OVERRIDE;
     virtual void trackSaveState(int* state) SK_OVERRIDE;
+
+    const SkPaint* paint() const { return fPaint; }
+
 private:
     const SkRect* fBounds;
     const SkPaint* fPaint;
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 8c75c1f..d5f76a3 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -85,6 +85,8 @@
         '<(skia_src_path)/core/SkFloat.h',
         '<(skia_src_path)/core/SkFloatBits.cpp',
         '<(skia_src_path)/core/SkFontHost.cpp',
+        '<(skia_src_path)/core/SkFontDescriptor.cpp',
+        '<(skia_src_path)/core/SkFontDescriptor.h',
         '<(skia_src_path)/core/SkGeometry.cpp',
         '<(skia_src_path)/core/SkGlyphCache.cpp',
         '<(skia_src_path)/core/SkGlyphCache.h',
diff --git a/gyp/ports.gyp b/gyp/ports.gyp
index a84f788..0b298d1 100644
--- a/gyp/ports.gyp
+++ b/gyp/ports.gyp
@@ -23,8 +23,6 @@
         '../src/ports/SkDebug_nacl.cpp',
         '../src/ports/SkDebug_stdio.cpp',
         '../src/ports/SkDebug_win.cpp',
-        '../src/ports/SkFontDescriptor.h',
-        '../src/ports/SkFontDescriptor.cpp',
         '../src/ports/SkFontHost_sandbox_none.cpp',
         '../src/ports/SkFontHost_win.cpp',
         '../src/ports/SkFontHost_win_dw.cpp',
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index 259ae67..8148358 100644
--- a/gyp/tools.gyp
+++ b/gyp/tools.gyp
@@ -197,11 +197,18 @@
       'type': 'executable',
       'include_dirs' : [
         '../src/core',
+        '../debugger',
       ],
       'sources': [
         '../tools/filtermain.cpp',
-        '../tools/path_utils.cpp',
         '../tools/path_utils.h',
+        '../tools/path_utils.cpp',
+        '../debugger/SkDrawCommand.h',
+        '../debugger/SkDrawCommand.cpp',
+        '../debugger/SkDebugCanvas.h',
+        '../debugger/SkDebugCanvas.cpp',
+        '../debugger/SkObjectParser.h',
+        '../debugger/SkObjectParser.cpp',
       ],
       'dependencies': [
         'skia_base_libs.gyp:skia_base_libs',
diff --git a/src/ports/SkFontDescriptor.cpp b/src/core/SkFontDescriptor.cpp
similarity index 100%
rename from src/ports/SkFontDescriptor.cpp
rename to src/core/SkFontDescriptor.cpp
diff --git a/src/ports/SkFontDescriptor.h b/src/core/SkFontDescriptor.h
similarity index 100%
rename from src/ports/SkFontDescriptor.h
rename to src/core/SkFontDescriptor.h
diff --git a/tools/filtermain.cpp b/tools/filtermain.cpp
index ab20e3f..ecaf3b2 100644
--- a/tools/filtermain.cpp
+++ b/tools/filtermain.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkDebugCanvas.h"
 #include "SkDevice.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
@@ -19,125 +20,27 @@
 
 static void usage() {
     SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
-    SkDebugf("                        [-p pathFile] [-t textureDir] [-h|--help]\n\n");
+    SkDebugf("                        [-h|--help]\n\n");
     SkDebugf("    -i inFile  : file to file.\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("    -p pathFile : file in which to place compileable path data.\n");
-    SkDebugf("    -t textureDir : directory in which to place textures. (only available w/ single file)\n");
     SkDebugf("    -h|--help  : Show this help message.\n");
 }
 
-// SkFilterRecord allows the filter to manipulate the read in SkPicture
-class SkFilterRecord : public SkPictureRecord {
-public:
-    SkFilterRecord(uint32_t recordFlags, SkDevice* device, SkFILEWStream* pathStream)
-        : INHERITED(recordFlags, device)
-        , fTransSkipped(0)
-        , fTransTot(0)
-        , fScalesSkipped(0)
-        , fScalesTot(0)
-        , fPathStream(pathStream) {
-    }
+// 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();
+}
 
-    virtual ~SkFilterRecord() {
-    }
-
-    virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAntiAlias) SK_OVERRIDE {
-        if (!path.isRect(NULL) && 4 < path.countPoints()) {
-            sk_tools::dump_path(fPathStream, path);
-        }
-        return INHERITED::clipPath(path, op, doAntiAlias);
-    }
-
-    virtual void drawPath(const SkPath& path, const SkPaint& p) SK_OVERRIDE {
-        if (!path.isRect(NULL) && 4 < path.countPoints()) {
-            sk_tools::dump_path(fPathStream, path);
-        }
-        INHERITED::drawPath(path, p);
-    }
-
-    virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE {
-        ++fTransTot;
-
-#if 0
-        if (0 == dx && 0 == dy) {
-            ++fTransSkipped;
-            return true;
-        }
-#endif
-
-        return INHERITED::translate(dx, dy);
-    }
-
-    virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE {
-        ++fScalesTot;
-
-#if 0
-        if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
-            ++fScalesSkipped;
-            return true;
-        }
-#endif
-
-        return INHERITED::scale(sx, sy);
-    }
-
-    void saveImages(const SkString& path) {
-        SkTRefArray<SkBitmap>* bitmaps = fBitmapHeap->extractBitmaps();
-
-        if (NULL != bitmaps) {
-            for (int i = 0; i < bitmaps->count(); ++i) {
-                SkString filename(path);
-                if (!path.endsWith("\\")) {
-                    filename.append("\\");
-                }
-                filename.append("image");
-                filename.appendS32(i);
-                filename.append(".png");
-
-                SkImageEncoder::EncodeFile(filename.c_str(), (*bitmaps)[i],
-                                           SkImageEncoder::kPNG_Type, 0);
-            }
-        }
-
-        bitmaps->unref();
-    }
-
-    void report() {
-        SkDebugf("%d Trans skipped (out of %d)\n", fTransSkipped, fTransTot);
-        SkDebugf("%d Scales skipped (out of %d)\n", fScalesSkipped, fScalesTot);
-    }
-
-protected:
-    int fTransSkipped;
-    int fTransTot;
-
-    int fScalesSkipped;
-    int fScalesTot;
-
-    SkFILEWStream* fPathStream;
-private:
-    typedef SkPictureRecord INHERITED;
-};
-
-// Wrap SkPicture to allow installation of a SkFilterRecord object
-class SkFilterPicture : public SkPicture {
-public:
-    SkFilterPicture(int width, int height, SkPictureRecord* record) {
-        fWidth = width;
-        fHeight = height;
-        fRecord = record;
-        SkSafeRef(fRecord);
-    }
-
-private:
-    typedef SkPicture INHERITED;
-};
-
-static int filter_picture(const SkString& inFile, const SkString& outFile,
-                   const SkString& textureDir, SkFILEWStream *pathStream) {
+static int filter_picture(const SkString& inFile, const SkString& outFile) {
     SkPicture* inPicture = NULL;
 
     SkFILEStream inStream(inFile.c_str());
@@ -150,30 +53,60 @@
         return -1;
     }
 
-    SkBitmap bm;
-    bm.setConfig(SkBitmap::kNo_Config, inPicture->width(), inPicture->height());
-    SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm)));
+    SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
+    debugCanvas.setBounds(inPicture->width(), inPicture->height());
+    inPicture->draw(&debugCanvas);
 
-    SkAutoTUnref<SkFilterRecord> filterRecord(SkNEW_ARGS(SkFilterRecord, (0, dev, pathStream)));
+    const SkTDArray<SkDrawCommand*>& commands = debugCanvas.getDrawCommands();
 
-    // Playback the read in picture to the SkFilterRecorder to allow filtering
-    filterRecord->beginRecording();
-    inPicture->draw(filterRecord);
-    filterRecord->endRecording();
+    for (int i = 0; i < commands.count(); ++i) {
+        // Check for:
+        //    SAVE_LAYER
+        //      DRAW_BITMAP_RECT_TO_RECT
+        //    RESTORE
+        // where the saveLayer's color can be moved into the drawBitmapRect
+        if (SAVE_LAYER == commands[i]->getType() && commands.count() > i+2) {
+            if (DRAW_BITMAP_RECT_TO_RECT == commands[i+1]->getType() &&
+                RESTORE == commands[i+2]->getType()) {
+                SaveLayer* sl = (SaveLayer*) commands[i];
+                DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[i+1];
 
-    filterRecord->report();
+                const SkPaint* p0 = sl->paint();
+                SkPaint* p1 = dbmr->paint();
+
+                if (NULL == p0) {
+                    commands[i]->setVisible(false);
+                    commands[i+2]->setVisible(false);
+                } else if (NULL == p1) {
+                    commands[i]->setVisible(false);
+                    dbmr->setPaint(*p0);
+                    commands[i+2]->setVisible(false);
+                } else if (is_simple(*p0) &&
+                           (SkColorGetR(p0->getColor()) == SkColorGetR(p1->getColor())) &&
+                           (SkColorGetG(p0->getColor()) == SkColorGetG(p1->getColor())) &&
+                           (SkColorGetB(p0->getColor()) == SkColorGetB(p1->getColor()))) {
+                    commands[i]->setVisible(false);
+                    SkColor newColor = SkColorSetA(p1->getColor(), 
+                                                   SkColorGetA(p0->getColor()));
+                    p1->setColor(newColor);
+                    commands[i+2]->setVisible(false);
+                }
+            }
+        }
+    }
 
     if (!outFile.isEmpty()) {
-        SkFilterPicture outPicture(inPicture->width(), inPicture->height(), filterRecord);
+        SkPicture outPicture;
+
+        SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
+        debugCanvas.draw(canvas);
+        outPicture.endRecording();
+
         SkFILEWStream outStream(outFile.c_str());
 
         outPicture.serialize(&outStream);
     }
 
-    if (!textureDir.isEmpty()) {
-        filterRecord->saveImages(textureDir);
-    }
-
     return 0;
 }
 
@@ -189,7 +122,7 @@
         return -1;
     }
 
-    SkString inFile, outFile, inDir, outDir, textureDir, pathFile;
+    SkString inFile, outFile, inDir, outDir;
 
     char* const* stop = argv + argc;
     for (++argv; argv < stop; ++argv) {
@@ -229,24 +162,6 @@
                 usage();
                 return -1;
             }
-        } else if (strcmp(*argv, "-p") == 0) {
-            argv++;
-            if (argv < stop && **argv) {
-                pathFile.set(*argv);
-            } else {
-                SkDebugf("missing arg for -p\n");
-                usage();
-                return -1;
-            }
-        } else if (strcmp(*argv, "-t") == 0) {
-            argv++;
-            if (argv < stop && **argv) {
-                textureDir.set(*argv);
-            } else {
-                SkDebugf("missing arg for -t\n");
-                usage();
-                return -1;
-            }
         } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
             usage();
             return 0;
@@ -257,25 +172,6 @@
         }
     }
 
-    if(!inDir.isEmpty() && !textureDir.isEmpty()) {
-        SkDebugf("ERROR: The textureDir option is not permitted when passing an input directory.\n");
-        usage();
-        return -1;
-    }
-
-    SkFILEWStream *pathStream = NULL;
-
-    if (!pathFile.isEmpty()) {
-        pathStream = new SkFILEWStream(pathFile.c_str());
-        if (!pathStream->isValid()) {
-            SkDebugf("Could open path file %s\n", pathFile.c_str());
-            delete pathStream;
-            return -1;
-        }
-
-        sk_tools::dump_path_prefix(pathStream);
-    }
-
     SkOSFile::Iter iter(inDir.c_str(), "skp");
 
     SkString inputFilename, outputFilename;
@@ -287,26 +183,16 @@
                 sk_tools::make_filepath(&outFile, outDir, inputFilename);
             }
             SkDebugf("Executing %s\n", inputFilename.c_str());
-            filter_picture(inFile, outFile, textureDir, pathStream);
+            filter_picture(inFile, outFile);
         } while(iter.next(&inputFilename));
 
     } else if (!inFile.isEmpty()) {
-        filter_picture(inFile, outFile, textureDir, pathStream);
+        filter_picture(inFile, outFile);
     } else {
         usage();
-        if (NULL != pathStream) {
-            delete pathStream;
-            pathStream = NULL;
-        }
         return -1;
     }
 
-    if (NULL != pathStream) {
-        sk_tools::dump_path_suffix(pathStream);
-        delete pathStream;
-        pathStream = NULL;
-    }
-
     SkGraphics::Term();
     return 0;
 }