1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * This file defines SkpDebugPlayer, a class which loads a SKP or MSKP file and draws it
3*c8dee2aaSAndroid Build Coastguard Worker * to an SkSurface with annotation, and detailed playback controls. It holds as many DebugCanvases
4*c8dee2aaSAndroid Build Coastguard Worker * as there are frames in the file.
5*c8dee2aaSAndroid Build Coastguard Worker *
6*c8dee2aaSAndroid Build Coastguard Worker * It also defines emscripten bindings for SkpDebugPlayer and other classes necessary to us it.
7*c8dee2aaSAndroid Build Coastguard Worker *
8*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google LLC
9*c8dee2aaSAndroid Build Coastguard Worker *
10*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
11*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
12*c8dee2aaSAndroid Build Coastguard Worker */
13*c8dee2aaSAndroid Build Coastguard Worker
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkCodec.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/docs/SkMultiPictureDocument.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkPngEncoder.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkBase64.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPicturePriv.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkJSONWriter.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "tools/SkSharingProc.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "tools/UrlDataManager.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "tools/debugger/DebugCanvas.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "tools/debugger/DebugLayerManager.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "tools/debugger/DrawCommand.h"
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
31*c8dee2aaSAndroid Build Coastguard Worker #include <string>
32*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
33*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
34*c8dee2aaSAndroid Build Coastguard Worker #include <map>
35*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten.h>
36*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/bind.h>
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker #ifdef CK_ENABLE_WEBGL
39*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrBackendSurface.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLInterface.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLTypes.h"
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker #include <GL/gl.h>
46*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/html5.h>
47*c8dee2aaSAndroid Build Coastguard Worker #endif
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker #include "modules/canvaskit/WasmCommon.h"
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker // file signature for SkMultiPictureDocument
52*c8dee2aaSAndroid Build Coastguard Worker // TODO(nifong): make public and include from SkMultiPictureDocument.h
53*c8dee2aaSAndroid Build Coastguard Worker static constexpr char kMultiMagic[] = "Skia Multi-Picture Doc\n\n";
54*c8dee2aaSAndroid Build Coastguard Worker
MinVersion()55*c8dee2aaSAndroid Build Coastguard Worker uint32_t MinVersion() { return SkPicturePriv::kMin_Version; }
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker struct ImageInfoNoColorspace {
58*c8dee2aaSAndroid Build Coastguard Worker int width;
59*c8dee2aaSAndroid Build Coastguard Worker int height;
60*c8dee2aaSAndroid Build Coastguard Worker SkColorType colorType;
61*c8dee2aaSAndroid Build Coastguard Worker SkAlphaType alphaType;
62*c8dee2aaSAndroid Build Coastguard Worker };
63*c8dee2aaSAndroid Build Coastguard Worker
64*c8dee2aaSAndroid Build Coastguard Worker // TODO(kjlubick) Should this handle colorspace
toImageInfoNoColorspace(const SkImageInfo & ii)65*c8dee2aaSAndroid Build Coastguard Worker ImageInfoNoColorspace toImageInfoNoColorspace(const SkImageInfo& ii) {
66*c8dee2aaSAndroid Build Coastguard Worker return (ImageInfoNoColorspace){ii.width(), ii.height(), ii.colorType(), ii.alphaType()};
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker
deserializeImage(sk_sp<SkData> data,std::optional<SkAlphaType>,void *)69*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> deserializeImage(sk_sp<SkData> data, std::optional<SkAlphaType>, void*) {
70*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkCodec> codec = DecodeImageData(std::move(data));
71*c8dee2aaSAndroid Build Coastguard Worker if (!codec) {
72*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Could not decode an image\n");
73*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> img = std::get<0>(codec->getImage());
76*c8dee2aaSAndroid Build Coastguard Worker if (!img) {
77*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Could not make an image from a codec\n");
78*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker return img;
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker class SkpDebugPlayer {
85*c8dee2aaSAndroid Build Coastguard Worker public:
SkpDebugPlayer()86*c8dee2aaSAndroid Build Coastguard Worker SkpDebugPlayer() :
87*c8dee2aaSAndroid Build Coastguard Worker udm(UrlDataManager(SkString("/data"))){}
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker /* loadSkp deserializes a skp file that has been copied into the shared WASM memory.
90*c8dee2aaSAndroid Build Coastguard Worker * cptr - a pointer to the data to deserialize.
91*c8dee2aaSAndroid Build Coastguard Worker * length - length of the data in bytes.
92*c8dee2aaSAndroid Build Coastguard Worker * The caller must allocate the memory with M._malloc where M is the wasm module in javascript
93*c8dee2aaSAndroid Build Coastguard Worker * and copy the data into M.buffer at the pointer returned by malloc.
94*c8dee2aaSAndroid Build Coastguard Worker *
95*c8dee2aaSAndroid Build Coastguard Worker * uintptr_t is used here because emscripten will not allow binding of functions with pointers
96*c8dee2aaSAndroid Build Coastguard Worker * to primitive types. We can instead pass a number and cast it to whatever kind of
97*c8dee2aaSAndroid Build Coastguard Worker * pointer we're expecting.
98*c8dee2aaSAndroid Build Coastguard Worker *
99*c8dee2aaSAndroid Build Coastguard Worker * Returns an error string which is populated in the case that the file cannot be read.
100*c8dee2aaSAndroid Build Coastguard Worker */
loadSkp(uintptr_t cptr,int length)101*c8dee2aaSAndroid Build Coastguard Worker std::string loadSkp(uintptr_t cptr, int length) {
102*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* data = reinterpret_cast<const uint8_t*>(cptr);
103*c8dee2aaSAndroid Build Coastguard Worker // Both traditional and multi-frame skp files have a magic word
104*c8dee2aaSAndroid Build Coastguard Worker SkMemoryStream stream(data, length);
105*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("make stream at %p, with %d bytes\n",data, length);
106*c8dee2aaSAndroid Build Coastguard Worker const bool isMulti = memcmp(data, kMultiMagic, sizeof(kMultiMagic) - 1) == 0;
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker
109*c8dee2aaSAndroid Build Coastguard Worker if (isMulti) {
110*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Try reading as a multi-frame skp\n");
111*c8dee2aaSAndroid Build Coastguard Worker const auto& error = loadMultiFrame(&stream);
112*c8dee2aaSAndroid Build Coastguard Worker if (!error.empty()) { return error; }
113*c8dee2aaSAndroid Build Coastguard Worker } else {
114*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Try reading as single-frame skp\n");
115*c8dee2aaSAndroid Build Coastguard Worker // TODO(nifong): Rely on SkPicture's return errors once it provides some.
116*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DebugCanvas> canvas = loadSingleFrame(&stream);
117*c8dee2aaSAndroid Build Coastguard Worker if (!canvas) {
118*c8dee2aaSAndroid Build Coastguard Worker return "Error loading single frame";
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker frames.push_back(std::move(canvas));
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker return "";
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker /* drawTo asks the debug canvas to draw from the beginning of the picture
126*c8dee2aaSAndroid Build Coastguard Worker * to the given command and flush the canvas.
127*c8dee2aaSAndroid Build Coastguard Worker */
drawTo(SkSurface * surface,int32_t index)128*c8dee2aaSAndroid Build Coastguard Worker void drawTo(SkSurface* surface, int32_t index) {
129*c8dee2aaSAndroid Build Coastguard Worker // Set the command within the frame or layer event being drawn.
130*c8dee2aaSAndroid Build Coastguard Worker if (fInspectedLayer >= 0) {
131*c8dee2aaSAndroid Build Coastguard Worker fLayerManager->setCommand(fInspectedLayer, fp, index);
132*c8dee2aaSAndroid Build Coastguard Worker } else {
133*c8dee2aaSAndroid Build Coastguard Worker index = constrainFrameCommand(index);
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker
136*c8dee2aaSAndroid Build Coastguard Worker auto* canvas = surface->getCanvas();
137*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorTRANSPARENT);
138*c8dee2aaSAndroid Build Coastguard Worker if (fInspectedLayer >= 0) {
139*c8dee2aaSAndroid Build Coastguard Worker // when it's a layer event we're viewing, we use the layer manager to render it.
140*c8dee2aaSAndroid Build Coastguard Worker fLayerManager->drawLayerEventTo(surface, fInspectedLayer, fp);
141*c8dee2aaSAndroid Build Coastguard Worker } else {
142*c8dee2aaSAndroid Build Coastguard Worker // otherwise, its a frame at the top level.
143*c8dee2aaSAndroid Build Coastguard Worker frames[fp]->drawTo(surface->getCanvas(), index);
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker #ifdef CK_ENABLE_WEBGL
146*c8dee2aaSAndroid Build Coastguard Worker skgpu::ganesh::Flush(surface);
147*c8dee2aaSAndroid Build Coastguard Worker #endif
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker // Draws to the end of the current frame.
draw(SkSurface * surface)151*c8dee2aaSAndroid Build Coastguard Worker void draw(SkSurface* surface) {
152*c8dee2aaSAndroid Build Coastguard Worker auto* canvas = surface->getCanvas();
153*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorTRANSPARENT);
154*c8dee2aaSAndroid Build Coastguard Worker frames[fp]->draw(surface->getCanvas());
155*c8dee2aaSAndroid Build Coastguard Worker #ifdef CK_ENABLE_WEBGL
156*c8dee2aaSAndroid Build Coastguard Worker skgpu::ganesh::Flush(surface);
157*c8dee2aaSAndroid Build Coastguard Worker #endif
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker // Gets the bounds for the given frame
161*c8dee2aaSAndroid Build Coastguard Worker // (or layer update, assuming there is one at that frame for fInspectedLayer)
getBoundsForFrame(int32_t frame)162*c8dee2aaSAndroid Build Coastguard Worker const SkIRect getBoundsForFrame(int32_t frame) {
163*c8dee2aaSAndroid Build Coastguard Worker if (fInspectedLayer < 0) {
164*c8dee2aaSAndroid Build Coastguard Worker return fBoundsArray[frame];
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker auto summary = fLayerManager->event(fInspectedLayer, fp);
167*c8dee2aaSAndroid Build Coastguard Worker return SkIRect::MakeWH(summary.layerWidth, summary.layerHeight);
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker // Gets the bounds for the current frame
getBounds()171*c8dee2aaSAndroid Build Coastguard Worker const SkIRect getBounds() {
172*c8dee2aaSAndroid Build Coastguard Worker return getBoundsForFrame(fp);
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker // returns the debugcanvas of the current frame, or the current draw event when inspecting
176*c8dee2aaSAndroid Build Coastguard Worker // a layer.
visibleCanvas()177*c8dee2aaSAndroid Build Coastguard Worker DebugCanvas* visibleCanvas() {
178*c8dee2aaSAndroid Build Coastguard Worker if (fInspectedLayer >=0) {
179*c8dee2aaSAndroid Build Coastguard Worker return fLayerManager->getEventDebugCanvas(fInspectedLayer, fp);
180*c8dee2aaSAndroid Build Coastguard Worker } else {
181*c8dee2aaSAndroid Build Coastguard Worker return frames[fp].get();
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker
185*c8dee2aaSAndroid Build Coastguard Worker // The following three operations apply to every debugcanvas because they are overdraw features.
186*c8dee2aaSAndroid Build Coastguard Worker // There is only one toggle for them on the app, they are global settings.
187*c8dee2aaSAndroid Build Coastguard Worker // However, there's not a simple way to make the debugcanvases pull settings from a central
188*c8dee2aaSAndroid Build Coastguard Worker // location so we set it on all of them at once.
setOverdrawVis(bool on)189*c8dee2aaSAndroid Build Coastguard Worker void setOverdrawVis(bool on) {
190*c8dee2aaSAndroid Build Coastguard Worker for (size_t i=0; i < frames.size(); i++) {
191*c8dee2aaSAndroid Build Coastguard Worker frames[i]->setOverdrawViz(on);
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker fLayerManager->setOverdrawViz(on);
194*c8dee2aaSAndroid Build Coastguard Worker }
setGpuOpBounds(bool on)195*c8dee2aaSAndroid Build Coastguard Worker void setGpuOpBounds(bool on) {
196*c8dee2aaSAndroid Build Coastguard Worker for (size_t i=0; i < frames.size(); i++) {
197*c8dee2aaSAndroid Build Coastguard Worker frames[i]->setDrawGpuOpBounds(on);
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker fLayerManager->setDrawGpuOpBounds(on);
200*c8dee2aaSAndroid Build Coastguard Worker }
setClipVizColor(JSColor color)201*c8dee2aaSAndroid Build Coastguard Worker void setClipVizColor(JSColor color) {
202*c8dee2aaSAndroid Build Coastguard Worker for (size_t i=0; i < frames.size(); i++) {
203*c8dee2aaSAndroid Build Coastguard Worker frames[i]->setClipVizColor(SkColor(color));
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker fLayerManager->setClipVizColor(SkColor(color));
206*c8dee2aaSAndroid Build Coastguard Worker }
setAndroidClipViz(bool on)207*c8dee2aaSAndroid Build Coastguard Worker void setAndroidClipViz(bool on) {
208*c8dee2aaSAndroid Build Coastguard Worker for (size_t i=0; i < frames.size(); i++) {
209*c8dee2aaSAndroid Build Coastguard Worker frames[i]->setAndroidClipViz(on);
210*c8dee2aaSAndroid Build Coastguard Worker }
211*c8dee2aaSAndroid Build Coastguard Worker // doesn't matter in layers
212*c8dee2aaSAndroid Build Coastguard Worker }
setOriginVisible(bool on)213*c8dee2aaSAndroid Build Coastguard Worker void setOriginVisible(bool on) {
214*c8dee2aaSAndroid Build Coastguard Worker for (size_t i=0; i < frames.size(); i++) {
215*c8dee2aaSAndroid Build Coastguard Worker frames[i]->setOriginVisible(on);
216*c8dee2aaSAndroid Build Coastguard Worker }
217*c8dee2aaSAndroid Build Coastguard Worker }
218*c8dee2aaSAndroid Build Coastguard Worker // The two operations below only apply to the current frame, because they concern the command
219*c8dee2aaSAndroid Build Coastguard Worker // list, which is unique to each frame.
deleteCommand(int index)220*c8dee2aaSAndroid Build Coastguard Worker void deleteCommand(int index) {
221*c8dee2aaSAndroid Build Coastguard Worker visibleCanvas()->deleteDrawCommandAt(index);
222*c8dee2aaSAndroid Build Coastguard Worker }
setCommandVisibility(int index,bool visible)223*c8dee2aaSAndroid Build Coastguard Worker void setCommandVisibility(int index, bool visible) {
224*c8dee2aaSAndroid Build Coastguard Worker visibleCanvas()->toggleCommand(index, visible);
225*c8dee2aaSAndroid Build Coastguard Worker }
getSize() const226*c8dee2aaSAndroid Build Coastguard Worker int getSize() const {
227*c8dee2aaSAndroid Build Coastguard Worker if (fInspectedLayer >=0) {
228*c8dee2aaSAndroid Build Coastguard Worker return fLayerManager->event(fInspectedLayer, fp).commandCount;
229*c8dee2aaSAndroid Build Coastguard Worker } else {
230*c8dee2aaSAndroid Build Coastguard Worker return frames[fp]->getSize();
231*c8dee2aaSAndroid Build Coastguard Worker }
232*c8dee2aaSAndroid Build Coastguard Worker }
getFrameCount() const233*c8dee2aaSAndroid Build Coastguard Worker int getFrameCount() const {
234*c8dee2aaSAndroid Build Coastguard Worker return frames.size();
235*c8dee2aaSAndroid Build Coastguard Worker }
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker // Return the command list in JSON representation as a string
jsonCommandList(sk_sp<SkSurface> surface)238*c8dee2aaSAndroid Build Coastguard Worker std::string jsonCommandList(sk_sp<SkSurface> surface) {
239*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream stream;
240*c8dee2aaSAndroid Build Coastguard Worker SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
241*c8dee2aaSAndroid Build Coastguard Worker writer.beginObject(); // root
242*c8dee2aaSAndroid Build Coastguard Worker visibleCanvas()->toJSON(writer, udm, surface->getCanvas());
243*c8dee2aaSAndroid Build Coastguard Worker writer.endObject(); // root
244*c8dee2aaSAndroid Build Coastguard Worker writer.flush();
245*c8dee2aaSAndroid Build Coastguard Worker auto skdata = stream.detachAsData();
246*c8dee2aaSAndroid Build Coastguard Worker // Convert skdata to string_view, which accepts a length
247*c8dee2aaSAndroid Build Coastguard Worker std::string_view data_view(reinterpret_cast<const char*>(skdata->data()), skdata->size());
248*c8dee2aaSAndroid Build Coastguard Worker // and string_view to string, which emscripten understands.
249*c8dee2aaSAndroid Build Coastguard Worker return std::string(data_view);
250*c8dee2aaSAndroid Build Coastguard Worker }
251*c8dee2aaSAndroid Build Coastguard Worker
252*c8dee2aaSAndroid Build Coastguard Worker // Gets the clip and matrix of the last command drawn
lastCommandInfo()253*c8dee2aaSAndroid Build Coastguard Worker std::string lastCommandInfo() {
254*c8dee2aaSAndroid Build Coastguard Worker SkM44 vm = visibleCanvas()->getCurrentMatrix();
255*c8dee2aaSAndroid Build Coastguard Worker SkIRect clip = visibleCanvas()->getCurrentClip();
256*c8dee2aaSAndroid Build Coastguard Worker
257*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream stream;
258*c8dee2aaSAndroid Build Coastguard Worker SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
259*c8dee2aaSAndroid Build Coastguard Worker writer.beginObject(); // root
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker writer.appendName("ViewMatrix");
262*c8dee2aaSAndroid Build Coastguard Worker DrawCommand::MakeJsonMatrix44(writer, vm);
263*c8dee2aaSAndroid Build Coastguard Worker writer.appendName("ClipRect");
264*c8dee2aaSAndroid Build Coastguard Worker DrawCommand::MakeJsonIRect(writer, clip);
265*c8dee2aaSAndroid Build Coastguard Worker
266*c8dee2aaSAndroid Build Coastguard Worker writer.endObject(); // root
267*c8dee2aaSAndroid Build Coastguard Worker writer.flush();
268*c8dee2aaSAndroid Build Coastguard Worker auto skdata = stream.detachAsData();
269*c8dee2aaSAndroid Build Coastguard Worker // Convert skdata to string_view, which accepts a length
270*c8dee2aaSAndroid Build Coastguard Worker std::string_view data_view(reinterpret_cast<const char*>(skdata->data()), skdata->size());
271*c8dee2aaSAndroid Build Coastguard Worker // and string_view to string, which emscripten understands.
272*c8dee2aaSAndroid Build Coastguard Worker return std::string(data_view);
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker
changeFrame(int index)275*c8dee2aaSAndroid Build Coastguard Worker void changeFrame(int index) {
276*c8dee2aaSAndroid Build Coastguard Worker fp = index;
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker
279*c8dee2aaSAndroid Build Coastguard Worker // Return the png file at the requested index in
280*c8dee2aaSAndroid Build Coastguard Worker // the skp file's vector of shared images. this is the set of images referred to by the
281*c8dee2aaSAndroid Build Coastguard Worker // filenames like "\\1" in DrawImage commands.
282*c8dee2aaSAndroid Build Coastguard Worker // Return type is the PNG data as a base64 encoded string with prepended URI.
getImageResource(int index)283*c8dee2aaSAndroid Build Coastguard Worker std::string getImageResource(int index) {
284*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> pngData = SkPngEncoder::Encode(nullptr, fImages[index].get(), {});
285*c8dee2aaSAndroid Build Coastguard Worker size_t len = SkBase64::EncodedSize(pngData->size());
286*c8dee2aaSAndroid Build Coastguard Worker SkString dst;
287*c8dee2aaSAndroid Build Coastguard Worker dst.resize(len);
288*c8dee2aaSAndroid Build Coastguard Worker SkBase64::Encode(pngData->data(), pngData->size(), dst.data());
289*c8dee2aaSAndroid Build Coastguard Worker dst.prepend("data:image/png;base64,");
290*c8dee2aaSAndroid Build Coastguard Worker return std::string(dst.c_str());
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker
getImageCount()293*c8dee2aaSAndroid Build Coastguard Worker int getImageCount() {
294*c8dee2aaSAndroid Build Coastguard Worker return fImages.size();
295*c8dee2aaSAndroid Build Coastguard Worker }
296*c8dee2aaSAndroid Build Coastguard Worker
297*c8dee2aaSAndroid Build Coastguard Worker // Get the image info of one of the resource images.
getImageInfo(int index)298*c8dee2aaSAndroid Build Coastguard Worker ImageInfoNoColorspace getImageInfo(int index) {
299*c8dee2aaSAndroid Build Coastguard Worker return toImageInfoNoColorspace(fImages[index]->imageInfo());
300*c8dee2aaSAndroid Build Coastguard Worker }
301*c8dee2aaSAndroid Build Coastguard Worker
302*c8dee2aaSAndroid Build Coastguard Worker // return data on which commands each image is used in.
303*c8dee2aaSAndroid Build Coastguard Worker // (frame, -1) returns info for the given frame,
304*c8dee2aaSAndroid Build Coastguard Worker // (frame, nodeid) return info for a layer update
305*c8dee2aaSAndroid Build Coastguard Worker // { imageid: [commandid, commandid, ...], ... }
imageUseInfo(int framenumber,int nodeid)306*c8dee2aaSAndroid Build Coastguard Worker JSObject imageUseInfo(int framenumber, int nodeid) {
307*c8dee2aaSAndroid Build Coastguard Worker JSObject result = emscripten::val::object();
308*c8dee2aaSAndroid Build Coastguard Worker DebugCanvas* debugCanvas = frames[framenumber].get();
309*c8dee2aaSAndroid Build Coastguard Worker if (nodeid >= 0) {
310*c8dee2aaSAndroid Build Coastguard Worker debugCanvas = fLayerManager->getEventDebugCanvas(nodeid, framenumber);
311*c8dee2aaSAndroid Build Coastguard Worker }
312*c8dee2aaSAndroid Build Coastguard Worker const auto& map = debugCanvas->getImageIdToCommandMap(udm);
313*c8dee2aaSAndroid Build Coastguard Worker for (auto it = map.begin(); it != map.end(); ++it) {
314*c8dee2aaSAndroid Build Coastguard Worker JSArray list = emscripten::val::array();
315*c8dee2aaSAndroid Build Coastguard Worker for (const int commandId : it->second) {
316*c8dee2aaSAndroid Build Coastguard Worker list.call<void>("push", commandId);
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker result.set(std::to_string(it->first), list);
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker return result;
321*c8dee2aaSAndroid Build Coastguard Worker }
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker // Return information on every layer (offscreeen buffer) that is available for drawing at
324*c8dee2aaSAndroid Build Coastguard Worker // the current frame.
getLayerSummariesJs()325*c8dee2aaSAndroid Build Coastguard Worker JSArray getLayerSummariesJs() {
326*c8dee2aaSAndroid Build Coastguard Worker JSArray result = emscripten::val::array();
327*c8dee2aaSAndroid Build Coastguard Worker for (auto summary : fLayerManager->summarizeLayers(fp)) {
328*c8dee2aaSAndroid Build Coastguard Worker result.call<void>("push", summary);
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker return result;
331*c8dee2aaSAndroid Build Coastguard Worker }
332*c8dee2aaSAndroid Build Coastguard Worker
getLayerKeys()333*c8dee2aaSAndroid Build Coastguard Worker JSArray getLayerKeys() {
334*c8dee2aaSAndroid Build Coastguard Worker JSArray result = emscripten::val::array();
335*c8dee2aaSAndroid Build Coastguard Worker for (auto key : fLayerManager->getKeys()) {
336*c8dee2aaSAndroid Build Coastguard Worker JSObject item = emscripten::val::object();
337*c8dee2aaSAndroid Build Coastguard Worker item.set("frame", key.frame);
338*c8dee2aaSAndroid Build Coastguard Worker item.set("nodeId", key.nodeId);
339*c8dee2aaSAndroid Build Coastguard Worker result.call<void>("push", item);
340*c8dee2aaSAndroid Build Coastguard Worker }
341*c8dee2aaSAndroid Build Coastguard Worker return result;
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker // When set to a valid layer index, causes this class to playback the layer draw event at nodeId
345*c8dee2aaSAndroid Build Coastguard Worker // on frame fp. No validation of nodeId or fp is performed, this must be valid values obtained
346*c8dee2aaSAndroid Build Coastguard Worker // from either fLayerManager.listNodesForFrame or fLayerManager.summarizeEvents
347*c8dee2aaSAndroid Build Coastguard Worker // Set to -1 to return to viewing the top level animation
setInspectedLayer(int nodeId)348*c8dee2aaSAndroid Build Coastguard Worker void setInspectedLayer(int nodeId) {
349*c8dee2aaSAndroid Build Coastguard Worker fInspectedLayer = nodeId;
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker
352*c8dee2aaSAndroid Build Coastguard Worker // Finds a command that left the given pixel in it's current state.
353*c8dee2aaSAndroid Build Coastguard Worker // Note that this method may fail to find the absolute last command that leaves a pixel
354*c8dee2aaSAndroid Build Coastguard Worker // the given color, but there is probably only one candidate in most cases, and the log(n)
355*c8dee2aaSAndroid Build Coastguard Worker // makes it worth it.
findCommandByPixel(SkSurface * surface,int x,int y,int commandIndex)356*c8dee2aaSAndroid Build Coastguard Worker int findCommandByPixel(SkSurface* surface, int x, int y, int commandIndex) {
357*c8dee2aaSAndroid Build Coastguard Worker // What color is the pixel now?
358*c8dee2aaSAndroid Build Coastguard Worker SkColor finalColor = evaluateCommandColor(surface, commandIndex, x, y);
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker int lowerBound = 0;
361*c8dee2aaSAndroid Build Coastguard Worker int upperBound = commandIndex;
362*c8dee2aaSAndroid Build Coastguard Worker
363*c8dee2aaSAndroid Build Coastguard Worker while (upperBound - lowerBound > 1) {
364*c8dee2aaSAndroid Build Coastguard Worker int command = (upperBound - lowerBound) / 2 + lowerBound;
365*c8dee2aaSAndroid Build Coastguard Worker auto c = evaluateCommandColor(surface, command, x, y);
366*c8dee2aaSAndroid Build Coastguard Worker if (c == finalColor) {
367*c8dee2aaSAndroid Build Coastguard Worker upperBound = command;
368*c8dee2aaSAndroid Build Coastguard Worker } else {
369*c8dee2aaSAndroid Build Coastguard Worker lowerBound = command;
370*c8dee2aaSAndroid Build Coastguard Worker }
371*c8dee2aaSAndroid Build Coastguard Worker }
372*c8dee2aaSAndroid Build Coastguard Worker // clean up after side effects
373*c8dee2aaSAndroid Build Coastguard Worker drawTo(surface, commandIndex);
374*c8dee2aaSAndroid Build Coastguard Worker return upperBound;
375*c8dee2aaSAndroid Build Coastguard Worker }
376*c8dee2aaSAndroid Build Coastguard Worker
377*c8dee2aaSAndroid Build Coastguard Worker private:
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker // Helper for findCommandByPixel.
380*c8dee2aaSAndroid Build Coastguard Worker // Has side effect of flushing to surface.
381*c8dee2aaSAndroid Build Coastguard Worker // TODO(nifong) eliminate side effect.
evaluateCommandColor(SkSurface * surface,int command,int x,int y)382*c8dee2aaSAndroid Build Coastguard Worker SkColor evaluateCommandColor(SkSurface* surface, int command, int x, int y) {
383*c8dee2aaSAndroid Build Coastguard Worker drawTo(surface, command);
384*c8dee2aaSAndroid Build Coastguard Worker
385*c8dee2aaSAndroid Build Coastguard Worker SkColor c;
386*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
387*c8dee2aaSAndroid Build Coastguard Worker SkPixmap pixmap(info, &c, 4);
388*c8dee2aaSAndroid Build Coastguard Worker surface->readPixels(pixmap, x, y);
389*c8dee2aaSAndroid Build Coastguard Worker return c;
390*c8dee2aaSAndroid Build Coastguard Worker }
391*c8dee2aaSAndroid Build Coastguard Worker
392*c8dee2aaSAndroid Build Coastguard Worker // Loads a single frame (traditional) skp file from the provided data stream and returns
393*c8dee2aaSAndroid Build Coastguard Worker // a newly allocated DebugCanvas initialized with the SkPicture that was in the file.
loadSingleFrame(SkMemoryStream * stream)394*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DebugCanvas> loadSingleFrame(SkMemoryStream* stream) {
395*c8dee2aaSAndroid Build Coastguard Worker SkDeserialProcs procs;
396*c8dee2aaSAndroid Build Coastguard Worker procs.fImageDataProc = deserializeImage;
397*c8dee2aaSAndroid Build Coastguard Worker // note overloaded = operator that actually does a move
398*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPicture> picture = SkPicture::MakeFromStream(stream, &procs);
399*c8dee2aaSAndroid Build Coastguard Worker if (!picture) {
400*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Unable to deserialze frame.\n");
401*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
402*c8dee2aaSAndroid Build Coastguard Worker }
403*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Parsed SKP file.\n");
404*c8dee2aaSAndroid Build Coastguard Worker // Make debug canvas using bounds from SkPicture
405*c8dee2aaSAndroid Build Coastguard Worker fBoundsArray.push_back(picture->cullRect().roundOut());
406*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DebugCanvas> debugCanvas = std::make_unique<DebugCanvas>(fBoundsArray.back());
407*c8dee2aaSAndroid Build Coastguard Worker
408*c8dee2aaSAndroid Build Coastguard Worker // Only draw picture to the debug canvas once.
409*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->drawPicture(picture);
410*c8dee2aaSAndroid Build Coastguard Worker return debugCanvas;
411*c8dee2aaSAndroid Build Coastguard Worker }
412*c8dee2aaSAndroid Build Coastguard Worker
loadMultiFrame(SkMemoryStream * stream)413*c8dee2aaSAndroid Build Coastguard Worker std::string loadMultiFrame(SkMemoryStream* stream) {
414*c8dee2aaSAndroid Build Coastguard Worker // Attempt to deserialize with an image sharing serial proc.
415*c8dee2aaSAndroid Build Coastguard Worker auto deserialContext = std::make_unique<SkSharingDeserialContext>();
416*c8dee2aaSAndroid Build Coastguard Worker SkDeserialProcs procs;
417*c8dee2aaSAndroid Build Coastguard Worker procs.fImageProc = SkSharingDeserialContext::deserializeImage;
418*c8dee2aaSAndroid Build Coastguard Worker procs.fImageCtx = deserialContext.get();
419*c8dee2aaSAndroid Build Coastguard Worker
420*c8dee2aaSAndroid Build Coastguard Worker int page_count = SkMultiPictureDocument::ReadPageCount(stream);
421*c8dee2aaSAndroid Build Coastguard Worker if (!page_count) {
422*c8dee2aaSAndroid Build Coastguard Worker // MSKP's have a version separate from the SKP subpictures they contain.
423*c8dee2aaSAndroid Build Coastguard Worker return "Not a MultiPictureDocument, MultiPictureDocument file version too old, or MultiPictureDocument contained 0 frames.";
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Expecting %d frames\n", page_count);
426*c8dee2aaSAndroid Build Coastguard Worker
427*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkDocumentPage> pages(page_count);
428*c8dee2aaSAndroid Build Coastguard Worker if (!SkMultiPictureDocument::Read(stream, pages.data(), page_count, &procs)) {
429*c8dee2aaSAndroid Build Coastguard Worker return "Reading frames from MultiPictureDocument failed";
430*c8dee2aaSAndroid Build Coastguard Worker }
431*c8dee2aaSAndroid Build Coastguard Worker
432*c8dee2aaSAndroid Build Coastguard Worker fLayerManager = std::make_unique<DebugLayerManager>();
433*c8dee2aaSAndroid Build Coastguard Worker
434*c8dee2aaSAndroid Build Coastguard Worker int i = 0;
435*c8dee2aaSAndroid Build Coastguard Worker for (const auto& page : pages) {
436*c8dee2aaSAndroid Build Coastguard Worker // Make debug canvas using bounds from SkPicture
437*c8dee2aaSAndroid Build Coastguard Worker fBoundsArray.push_back(page.fPicture->cullRect().roundOut());
438*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DebugCanvas> debugCanvas = std::make_unique<DebugCanvas>(fBoundsArray.back());
439*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->setLayerManagerAndFrame(fLayerManager.get(), i);
440*c8dee2aaSAndroid Build Coastguard Worker
441*c8dee2aaSAndroid Build Coastguard Worker // Only draw picture to the debug canvas once.
442*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->drawPicture(page.fPicture);
443*c8dee2aaSAndroid Build Coastguard Worker
444*c8dee2aaSAndroid Build Coastguard Worker if (debugCanvas->getSize() <=0 ){
445*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Skipped corrupted frame, had %d commands \n", debugCanvas->getSize());
446*c8dee2aaSAndroid Build Coastguard Worker continue;
447*c8dee2aaSAndroid Build Coastguard Worker }
448*c8dee2aaSAndroid Build Coastguard Worker // If you don't set these, they're undefined.
449*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->setOverdrawViz(false);
450*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->setDrawGpuOpBounds(false);
451*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->setClipVizColor(SK_ColorTRANSPARENT);
452*c8dee2aaSAndroid Build Coastguard Worker debugCanvas->setAndroidClipViz(false);
453*c8dee2aaSAndroid Build Coastguard Worker frames.push_back(std::move(debugCanvas));
454*c8dee2aaSAndroid Build Coastguard Worker i++;
455*c8dee2aaSAndroid Build Coastguard Worker }
456*c8dee2aaSAndroid Build Coastguard Worker fImages = deserialContext->fImages;
457*c8dee2aaSAndroid Build Coastguard Worker
458*c8dee2aaSAndroid Build Coastguard Worker udm.indexImages(fImages);
459*c8dee2aaSAndroid Build Coastguard Worker return "";
460*c8dee2aaSAndroid Build Coastguard Worker }
461*c8dee2aaSAndroid Build Coastguard Worker
462*c8dee2aaSAndroid Build Coastguard Worker // constrains the draw command index to the frame's command list length.
constrainFrameCommand(int index)463*c8dee2aaSAndroid Build Coastguard Worker int constrainFrameCommand(int index) {
464*c8dee2aaSAndroid Build Coastguard Worker int cmdlen = frames[fp]->getSize();
465*c8dee2aaSAndroid Build Coastguard Worker if (index >= cmdlen) {
466*c8dee2aaSAndroid Build Coastguard Worker return cmdlen-1;
467*c8dee2aaSAndroid Build Coastguard Worker }
468*c8dee2aaSAndroid Build Coastguard Worker return index;
469*c8dee2aaSAndroid Build Coastguard Worker }
470*c8dee2aaSAndroid Build Coastguard Worker
471*c8dee2aaSAndroid Build Coastguard Worker // A vector of DebugCanvas, each one initialized to a frame of the animation.
472*c8dee2aaSAndroid Build Coastguard Worker std::vector<std::unique_ptr<DebugCanvas>> frames;
473*c8dee2aaSAndroid Build Coastguard Worker // The index of the current frame (into the vector above)
474*c8dee2aaSAndroid Build Coastguard Worker int fp = 0;
475*c8dee2aaSAndroid Build Coastguard Worker // The width and height of every frame.
476*c8dee2aaSAndroid Build Coastguard Worker // frame sizes are known to change in Android Skia RenderEngine because it interleves pictures from different applications.
477*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkIRect> fBoundsArray;
478*c8dee2aaSAndroid Build Coastguard Worker // image resources from a loaded file
479*c8dee2aaSAndroid Build Coastguard Worker std::vector<sk_sp<SkImage>> fImages;
480*c8dee2aaSAndroid Build Coastguard Worker
481*c8dee2aaSAndroid Build Coastguard Worker // The URLDataManager here is a cache that accepts encoded data (pngs) and puts
482*c8dee2aaSAndroid Build Coastguard Worker // numbers on them. We have our own collection of images (fImages) that was populated by the
483*c8dee2aaSAndroid Build Coastguard Worker // SkSharingDeserialContext when mskp files are loaded which it can use for IDing images
484*c8dee2aaSAndroid Build Coastguard Worker // without having to serialize them.
485*c8dee2aaSAndroid Build Coastguard Worker UrlDataManager udm;
486*c8dee2aaSAndroid Build Coastguard Worker
487*c8dee2aaSAndroid Build Coastguard Worker // A structure holding the picture information needed to draw any layers used in an mskp file
488*c8dee2aaSAndroid Build Coastguard Worker // individual frames hold a pointer to it, store draw events, and request images from it.
489*c8dee2aaSAndroid Build Coastguard Worker // it is stateful and is set to the current frame at all times.
490*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<DebugLayerManager> fLayerManager;
491*c8dee2aaSAndroid Build Coastguard Worker
492*c8dee2aaSAndroid Build Coastguard Worker // The node id of a layer being inspected, if any.
493*c8dee2aaSAndroid Build Coastguard Worker // -1 means we are viewing the top level animation, not a layer.
494*c8dee2aaSAndroid Build Coastguard Worker // the exact draw event being inspected depends also on the selected frame `fp`.
495*c8dee2aaSAndroid Build Coastguard Worker int fInspectedLayer = -1;
496*c8dee2aaSAndroid Build Coastguard Worker };
497*c8dee2aaSAndroid Build Coastguard Worker
498*c8dee2aaSAndroid Build Coastguard Worker using namespace emscripten;
EMSCRIPTEN_BINDINGS(my_module)499*c8dee2aaSAndroid Build Coastguard Worker EMSCRIPTEN_BINDINGS(my_module) {
500*c8dee2aaSAndroid Build Coastguard Worker
501*c8dee2aaSAndroid Build Coastguard Worker function("MinVersion", &MinVersion);
502*c8dee2aaSAndroid Build Coastguard Worker
503*c8dee2aaSAndroid Build Coastguard Worker // The main class that the JavaScript in index.html uses
504*c8dee2aaSAndroid Build Coastguard Worker class_<SkpDebugPlayer>("SkpDebugPlayer")
505*c8dee2aaSAndroid Build Coastguard Worker .constructor<>()
506*c8dee2aaSAndroid Build Coastguard Worker .function("changeFrame", &SkpDebugPlayer::changeFrame)
507*c8dee2aaSAndroid Build Coastguard Worker .function("deleteCommand", &SkpDebugPlayer::deleteCommand)
508*c8dee2aaSAndroid Build Coastguard Worker .function("draw", &SkpDebugPlayer::draw, allow_raw_pointers())
509*c8dee2aaSAndroid Build Coastguard Worker .function("drawTo", &SkpDebugPlayer::drawTo, allow_raw_pointers())
510*c8dee2aaSAndroid Build Coastguard Worker .function("findCommandByPixel", &SkpDebugPlayer::findCommandByPixel, allow_raw_pointers())
511*c8dee2aaSAndroid Build Coastguard Worker .function("getBounds", &SkpDebugPlayer::getBounds)
512*c8dee2aaSAndroid Build Coastguard Worker .function("getBoundsForFrame", &SkpDebugPlayer::getBoundsForFrame)
513*c8dee2aaSAndroid Build Coastguard Worker .function("getFrameCount", &SkpDebugPlayer::getFrameCount)
514*c8dee2aaSAndroid Build Coastguard Worker .function("getImageResource", &SkpDebugPlayer::getImageResource)
515*c8dee2aaSAndroid Build Coastguard Worker .function("getImageCount", &SkpDebugPlayer::getImageCount)
516*c8dee2aaSAndroid Build Coastguard Worker .function("getImageInfo", &SkpDebugPlayer::getImageInfo)
517*c8dee2aaSAndroid Build Coastguard Worker .function("getLayerKeys", &SkpDebugPlayer::getLayerKeys)
518*c8dee2aaSAndroid Build Coastguard Worker .function("getLayerSummariesJs", &SkpDebugPlayer::getLayerSummariesJs)
519*c8dee2aaSAndroid Build Coastguard Worker .function("getSize", &SkpDebugPlayer::getSize)
520*c8dee2aaSAndroid Build Coastguard Worker .function("imageUseInfo", &SkpDebugPlayer::imageUseInfo)
521*c8dee2aaSAndroid Build Coastguard Worker .function("imageUseInfoForFrameJs", optional_override([](SkpDebugPlayer& self, const int frame)->JSObject {
522*c8dee2aaSAndroid Build Coastguard Worker // -1 as a node id is used throughout the application to mean no layer inspected.
523*c8dee2aaSAndroid Build Coastguard Worker return self.imageUseInfo(frame, -1);
524*c8dee2aaSAndroid Build Coastguard Worker }))
525*c8dee2aaSAndroid Build Coastguard Worker .function("jsonCommandList", &SkpDebugPlayer::jsonCommandList, allow_raw_pointers())
526*c8dee2aaSAndroid Build Coastguard Worker .function("lastCommandInfo", &SkpDebugPlayer::lastCommandInfo)
527*c8dee2aaSAndroid Build Coastguard Worker .function("loadSkp", &SkpDebugPlayer::loadSkp, allow_raw_pointers())
528*c8dee2aaSAndroid Build Coastguard Worker .function("setClipVizColor", &SkpDebugPlayer::setClipVizColor)
529*c8dee2aaSAndroid Build Coastguard Worker .function("setCommandVisibility", &SkpDebugPlayer::setCommandVisibility)
530*c8dee2aaSAndroid Build Coastguard Worker .function("setGpuOpBounds", &SkpDebugPlayer::setGpuOpBounds)
531*c8dee2aaSAndroid Build Coastguard Worker .function("setInspectedLayer", &SkpDebugPlayer::setInspectedLayer)
532*c8dee2aaSAndroid Build Coastguard Worker .function("setOriginVisible", &SkpDebugPlayer::setOriginVisible)
533*c8dee2aaSAndroid Build Coastguard Worker .function("setOverdrawVis", &SkpDebugPlayer::setOverdrawVis)
534*c8dee2aaSAndroid Build Coastguard Worker .function("setAndroidClipViz", &SkpDebugPlayer::setAndroidClipViz);
535*c8dee2aaSAndroid Build Coastguard Worker
536*c8dee2aaSAndroid Build Coastguard Worker // Structs used as arguments or returns to the functions above
537*c8dee2aaSAndroid Build Coastguard Worker // TODO(kjlubick) handle this rect like the ones in CanvasKit
538*c8dee2aaSAndroid Build Coastguard Worker value_object<SkIRect>("SkIRect")
539*c8dee2aaSAndroid Build Coastguard Worker .field("fLeft", &SkIRect::fLeft)
540*c8dee2aaSAndroid Build Coastguard Worker .field("fTop", &SkIRect::fTop)
541*c8dee2aaSAndroid Build Coastguard Worker .field("fRight", &SkIRect::fRight)
542*c8dee2aaSAndroid Build Coastguard Worker .field("fBottom", &SkIRect::fBottom);
543*c8dee2aaSAndroid Build Coastguard Worker // emscripten provided the following convenience function for binding vector<T>
544*c8dee2aaSAndroid Build Coastguard Worker // https://emscripten.org/docs/api_reference/bind.h.html#_CPPv415register_vectorPKc
545*c8dee2aaSAndroid Build Coastguard Worker register_vector<DebugLayerManager::LayerSummary>("VectorLayerSummary");
546*c8dee2aaSAndroid Build Coastguard Worker value_object<DebugLayerManager::LayerSummary>("LayerSummary")
547*c8dee2aaSAndroid Build Coastguard Worker .field("nodeId", &DebugLayerManager::LayerSummary::nodeId)
548*c8dee2aaSAndroid Build Coastguard Worker .field("frameOfLastUpdate", &DebugLayerManager::LayerSummary::frameOfLastUpdate)
549*c8dee2aaSAndroid Build Coastguard Worker .field("fullRedraw", &DebugLayerManager::LayerSummary::fullRedraw)
550*c8dee2aaSAndroid Build Coastguard Worker .field("layerWidth", &DebugLayerManager::LayerSummary::layerWidth)
551*c8dee2aaSAndroid Build Coastguard Worker .field("layerHeight", &DebugLayerManager::LayerSummary::layerHeight);
552*c8dee2aaSAndroid Build Coastguard Worker
553*c8dee2aaSAndroid Build Coastguard Worker value_object<ImageInfoNoColorspace>("ImageInfoNoColorspace")
554*c8dee2aaSAndroid Build Coastguard Worker .field("width", &ImageInfoNoColorspace::width)
555*c8dee2aaSAndroid Build Coastguard Worker .field("height", &ImageInfoNoColorspace::height)
556*c8dee2aaSAndroid Build Coastguard Worker .field("colorType", &ImageInfoNoColorspace::colorType)
557*c8dee2aaSAndroid Build Coastguard Worker .field("alphaType", &ImageInfoNoColorspace::alphaType);
558*c8dee2aaSAndroid Build Coastguard Worker }
559