Add a method of returning the list of commands that use an image

Change-Id: I3c94f7b6faa71ab0cbeccddd2032b657e350c9b3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/316843
Commit-Queue: Nathaniel Nifong <nifong@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
diff --git a/experimental/wasm-skp-debugger/debugger_bindings.cpp b/experimental/wasm-skp-debugger/debugger_bindings.cpp
index be92d3d..2f751c6 100644
--- a/experimental/wasm-skp-debugger/debugger_bindings.cpp
+++ b/experimental/wasm-skp-debugger/debugger_bindings.cpp
@@ -27,6 +27,7 @@
 #include <string>
 #include <string_view>
 #include <vector>
+#include <map>
 #include <emscripten.h>
 #include <emscripten/bind.h>
 
@@ -275,6 +276,29 @@
       return toSimpleImageInfo(fImages[index]->imageInfo());
     }
 
+    // returns a JSON string representing commands where each image is referenced.
+    std::string imageUseInfoForFrame(int framenumber) {
+      std::map<int, std::vector<int>> m = frames[framenumber]->getImageIdToCommandMap(udm);
+
+      SkDynamicMemoryWStream stream;
+      SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
+      writer.beginObject(); // root
+
+      for (auto it = m.begin(); it != m.end(); ++it) {
+        writer.beginArray(std::to_string(it->first).c_str());
+        for (const int commandId : it->second) {
+          writer.appendU64((uint64_t)commandId);
+        }
+        writer.endArray();
+      }
+
+      writer.endObject(); // root
+      writer.flush();
+      auto skdata = stream.detachAsData();
+      std::string_view data_view(reinterpret_cast<const char*>(skdata->data()), skdata->size());
+      return std::string(data_view);
+    }
+
     // return a list of layer draw events that happened at the beginning of this frame.
     std::vector<DebugLayerManager::LayerSummary> getLayerSummaries() {
       return fLayerManager->summarizeLayers(fp);
@@ -480,6 +504,7 @@
     .function("getImageInfo",         &SkpDebugPlayer::getImageInfo)
     .function("getLayerSummaries",    &SkpDebugPlayer::getLayerSummaries)
     .function("getSize",              &SkpDebugPlayer::getSize)
+    .function("imageUseInfoForFrame", &SkpDebugPlayer::imageUseInfoForFrame)
     .function("jsonCommandList",      &SkpDebugPlayer::jsonCommandList, allow_raw_pointers())
     .function("lastCommandInfo",      &SkpDebugPlayer::lastCommandInfo)
     .function("loadSkp",              &SkpDebugPlayer::loadSkp, allow_raw_pointers())
diff --git a/experimental/wasm-skp-debugger/externs.js b/experimental/wasm-skp-debugger/externs.js
index 0446d15..c417c52 100644
--- a/experimental/wasm-skp-debugger/externs.js
+++ b/experimental/wasm-skp-debugger/externs.js
@@ -45,6 +45,7 @@
 		setCommandVisibility: function() {},
 		jsonCommandList: function() {},
 		lastCommandInfo: function() {},
+		imageUseInfoForFrame: function() {},
 	},
 
 	/**
diff --git a/tools/debugger/DebugCanvas.cpp b/tools/debugger/DebugCanvas.cpp
index 5335e0f..68b373e 100644
--- a/tools/debugger/DebugCanvas.cpp
+++ b/tools/debugger/DebugCanvas.cpp
@@ -251,7 +251,7 @@
     fCommandVector.remove(index);
 }
 
-DrawCommand* DebugCanvas::getDrawCommandAt(int index) {
+DrawCommand* DebugCanvas::getDrawCommandAt(int index) const {
     SkASSERT(index < fCommandVector.count());
     return fCommandVector[index];
 }
@@ -596,3 +596,37 @@
     SkASSERT(index < fCommandVector.count());
     fCommandVector[index]->setVisible(toggle);
 }
+
+std::map<int, std::vector<int>> DebugCanvas::getImageIdToCommandMap(UrlDataManager& udm) const {
+    // map from image ids to list of commands that reference them.
+    std::map<int, std::vector<int>> m;
+
+    for (int i = 0; i < this->getSize(); i++) {
+        const DrawCommand* command = this->getDrawCommandAt(i);
+        int imageIndex = -1;
+        // this is not an exaustive list of where images can be used, they show up in paints too.
+        switch (command->getOpType()) {
+            case DrawCommand::OpType::kDrawImage_OpType: {
+                imageIndex = static_cast<const DrawImageCommand*>(command)->imageId(udm);
+                break;
+            }
+            case DrawCommand::OpType::kDrawImageRect_OpType: {
+                imageIndex = static_cast<const DrawImageRectCommand*>(command)->imageId(udm);
+                break;
+            }
+            case DrawCommand::OpType::kDrawImageNine_OpType: {
+                imageIndex = static_cast<const DrawImageNineCommand*>(command)->imageId(udm);
+                break;
+            }
+            case DrawCommand::OpType::kDrawImageLattice_OpType: {
+                imageIndex = static_cast<const DrawImageLatticeCommand*>(command)->imageId(udm);
+                break;
+            }
+            default: break;
+        }
+        if (imageIndex >= 0) {
+            m[imageIndex].push_back(i);
+        }
+    }
+    return m;
+}
diff --git a/tools/debugger/DebugCanvas.h b/tools/debugger/DebugCanvas.h
index fe1d32d..d966bf8 100644
--- a/tools/debugger/DebugCanvas.h
+++ b/tools/debugger/DebugCanvas.h
@@ -19,6 +19,9 @@
 #include "tools/debugger/DebugLayerManager.h"
 #include "tools/debugger/DrawCommand.h"
 
+#include <map>
+#include <vector>
+
 class GrAuditTrail;
 class SkNWayCanvas;
 class SkPicture;
@@ -103,7 +106,7 @@
         Returns the draw command at the given index.
         @param index  The index of the command
      */
-    DrawCommand* getDrawCommandAt(int index);
+    DrawCommand* getDrawCommandAt(int index) const;
 
     /**
         Returns length of draw command vector.
@@ -127,6 +130,11 @@
 
     void detachCommands(SkTDArray<DrawCommand*>* dst) { fCommandVector.swap(*dst); }
 
+    /**
+        Returns a map from image IDs to command indices where they are used.
+     */
+    std::map<int, std::vector<int>> getImageIdToCommandMap(UrlDataManager& udm) const;
+
 protected:
     void              willSave() override;
     SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
diff --git a/tools/debugger/DrawCommand.cpp b/tools/debugger/DrawCommand.cpp
index 6811d43..6dbcc5c 100644
--- a/tools/debugger/DrawCommand.cpp
+++ b/tools/debugger/DrawCommand.cpp
@@ -1198,13 +1198,15 @@
     return true;
 }
 
+uint64_t DrawImageCommand::imageId(UrlDataManager& udm) const {
+    return udm.lookupImage(fImage.get());
+}
+
 void DrawImageCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
     INHERITED::toJSON(writer, urlDataManager);
-
-
     if (urlDataManager.hasImageIndex()) {
         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
-        writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
+        writer.appendU64(imageId(urlDataManager));
     } else {
         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
         flatten(*fImage, writer, urlDataManager);
@@ -1261,11 +1263,15 @@
     return true;
 }
 
+uint64_t DrawImageLatticeCommand::imageId(UrlDataManager& udm) const {
+    return udm.lookupImage(fImage.get());
+}
+
 void DrawImageLatticeCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
     INHERITED::toJSON(writer, urlDataManager);
     if (urlDataManager.hasImageIndex()) {
         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
-        writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
+        writer.appendU64(imageId(urlDataManager));
     } else {
         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
         flatten(*fImage, writer, urlDataManager);
@@ -1312,11 +1318,15 @@
     return true;
 }
 
+uint64_t DrawImageRectCommand::imageId(UrlDataManager& udm) const {
+    return udm.lookupImage(fImage.get());
+}
+
 void DrawImageRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
     INHERITED::toJSON(writer, urlDataManager);
     if (urlDataManager.hasImageIndex()) {
         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
-        writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
+        writer.appendU64(imageId(urlDataManager));
     } else {
         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
         flatten(*fImage, writer, urlDataManager);
@@ -1424,11 +1434,15 @@
     return true;
 }
 
+uint64_t DrawImageNineCommand::imageId(UrlDataManager& udm) const {
+    return udm.lookupImage(fImage.get());
+}
+
 void DrawImageNineCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
     INHERITED::toJSON(writer, urlDataManager);
     if (urlDataManager.hasImageIndex()) {
         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
-        writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
+        writer.appendU64(imageId(urlDataManager));
     } else {
         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
         flatten(*fImage, writer, urlDataManager);
diff --git a/tools/debugger/DrawCommand.h b/tools/debugger/DrawCommand.h
index 4171ea3..e15d02f 100644
--- a/tools/debugger/DrawCommand.h
+++ b/tools/debugger/DrawCommand.h
@@ -113,6 +113,7 @@
     static bool flatten(const SkBitmap& bitmap,
                         SkJSONWriter&   writer,
                         UrlDataManager& urlDataManager);
+    OpType getOpType() const { return fOpType; }
 
 private:
     OpType fOpType;
@@ -255,6 +256,7 @@
     void execute(SkCanvas* canvas) const override;
     bool render(SkCanvas* canvas) const override;
     void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+    uint64_t imageId(UrlDataManager& udb) const;
 
 private:
     sk_sp<const SkImage> fImage;
@@ -274,6 +276,7 @@
     void execute(SkCanvas* canvas) const override;
     bool render(SkCanvas* canvas) const override;
     void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+    uint64_t imageId(UrlDataManager& udb) const;
 
 private:
     sk_sp<const SkImage> fImage;
@@ -293,6 +296,7 @@
     void execute(SkCanvas* canvas) const override;
     bool render(SkCanvas* canvas) const override;
     void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+    uint64_t imageId(UrlDataManager& udb) const;
 
 private:
     sk_sp<const SkImage> fImage;
@@ -313,6 +317,7 @@
     void execute(SkCanvas* canvas) const override;
     bool render(SkCanvas* canvas) const override;
     void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+    uint64_t imageId(UrlDataManager& udm) const;
 
 private:
     sk_sp<const SkImage>        fImage;