add SkRecordOptimize2 and an experimental API for more aggressive opts

BUG=skia:

Review URL: https://codereview.chromium.org/1462973002
diff --git a/src/core/SkRecordOpts.cpp b/src/core/SkRecordOpts.cpp
index d363712..d1520ad 100644
--- a/src/core/SkRecordOpts.cpp
+++ b/src/core/SkRecordOpts.cpp
@@ -13,19 +13,6 @@
 
 using namespace SkRecords;
 
-void SkRecordOptimize(SkRecord* record) {
-    // This might be useful  as a first pass in the future if we want to weed
-    // out junk for other optimization passes.  Right now, nothing needs it,
-    // and the bounding box hierarchy will do the work of skipping no-op
-    // Save-NoDraw-Restore sequences better than we can here.
-    //SkRecordNoopSaveRestores(record);
-
-    SkRecordNoopSaveLayerDrawRestores(record);
-    SkRecordMergeSvgOpacityAndFilterLayers(record);
-
-    record->defrag();
-}
-
 // Most of the optimizations in this file are pattern-based.  These are all defined as structs with:
 //   - a Match typedef
 //   - a bool onMatch(SkRceord*, Match*, int begin, int end) method,
@@ -46,6 +33,45 @@
     return changed;
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static void multiple_set_matrices(SkRecord* record) {
+    struct {
+        typedef Pattern<Is<SetMatrix>,
+                        Greedy<Is<NoOp>>,
+                        Is<SetMatrix> >
+            Match;
+
+        bool onMatch(SkRecord* record, Match* pattern, int begin, int end) {
+            record->replace<NoOp>(begin);  // first SetMatrix
+            return true;
+        }
+    } pass;
+    while (apply(&pass, record));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0   // experimental, but needs knowledge of previous matrix to operate correctly
+static void apply_matrix_to_draw_params(SkRecord* record) {
+    struct {
+        typedef Pattern<Is<SetMatrix>,
+                        Greedy<Is<NoOp>>,
+                        Is<SetMatrix> >
+            Pattern;
+
+        bool onMatch(SkRecord* record, Pattern* pattern, int begin, int end) {
+            record->replace<NoOp>(begin);  // first SetMatrix
+            return true;
+        }
+    } pass;
+    // No need to loop, as we never "open up" opportunities for more of this type of optimization.
+    apply(&pass, record);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 // Turns the logical NoOp Save and Restore in Save-Draw*-Restore patterns into actual NoOps.
 struct SaveOnlyDrawsRestoreNooper {
     typedef Pattern<Is<Save>,
@@ -232,3 +258,28 @@
     SvgOpacityAndFilterLayerMergePass pass;
     apply(&pass, record);
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SkRecordOptimize(SkRecord* record) {
+    // This might be useful  as a first pass in the future if we want to weed
+    // out junk for other optimization passes.  Right now, nothing needs it,
+    // and the bounding box hierarchy will do the work of skipping no-op
+    // Save-NoDraw-Restore sequences better than we can here.
+    //SkRecordNoopSaveRestores(record);
+
+    SkRecordNoopSaveLayerDrawRestores(record);
+    SkRecordMergeSvgOpacityAndFilterLayers(record);
+
+    record->defrag();
+}
+
+void SkRecordOptimize2(SkRecord* record) {
+    multiple_set_matrices(record);
+    SkRecordNoopSaveRestores(record);
+    SkRecordNoopSaveLayerDrawRestores(record);
+    SkRecordMergeSvgOpacityAndFilterLayers(record);
+
+    record->defrag();
+}
+
diff --git a/src/core/SkRecordOpts.h b/src/core/SkRecordOpts.h
index a560d006..d6531b5 100644
--- a/src/core/SkRecordOpts.h
+++ b/src/core/SkRecordOpts.h
@@ -24,4 +24,7 @@
 // the alpha of the first SaveLayer to the second SaveLayer.
 void SkRecordMergeSvgOpacityAndFilterLayers(SkRecord*);
 
+// Experimental optimizers
+void SkRecordOptimize2(SkRecord*);
+
 #endif//SkRecordOpts_DEFINED
diff --git a/tools/dump_record.cpp b/tools/dump_record.cpp
index 1b5f1dc..029638e 100644
--- a/tools/dump_record.cpp
+++ b/tools/dump_record.cpp
@@ -19,6 +19,7 @@
 DEFINE_string2(skps, r, "", ".SKPs to dump.");
 DEFINE_string(match, "", "The usual filters on file names to dump.");
 DEFINE_bool2(optimize, O, false, "Run SkRecordOptimize before dumping.");
+DEFINE_bool(optimize2, false, "Run SkRecordOptimize2 before dumping.");
 DEFINE_int32(tile, 1000000000, "Simulated tile size.");
 DEFINE_bool(timeWithCommand, false, "If true, print time next to command, else in first column.");
 DEFINE_string2(write, w, "", "Write the (optimized) picture to the named file.");
@@ -65,6 +66,9 @@
         if (FLAGS_optimize) {
             SkRecordOptimize(&record);
         }
+        if (FLAGS_optimize2) {
+            SkRecordOptimize2(&record);
+        }
 
         dump(FLAGS_skps[i], w, h, record);