• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkDebugCanvas.h"
9 #include "SkPicture.h"
10 #include "SkSurface.h"
11 #include <emscripten.h>
12 #include <emscripten/bind.h>
13 
14 using JSColor = int32_t;
15 
16 struct SimpleImageInfo {
17   int width;
18   int height;
19   SkColorType colorType;
20   SkAlphaType alphaType;
21 };
22 
toSkImageInfo(const SimpleImageInfo & sii)23 SkImageInfo toSkImageInfo(const SimpleImageInfo& sii) {
24   return SkImageInfo::Make(sii.width, sii.height, sii.colorType, sii.alphaType);
25 }
26 
27 class SkpDebugPlayer {
28   public:
SkpDebugPlayer()29     SkpDebugPlayer() {}
30 
31 
32     /* loadSkp deserializes a skp file that has been copied into the shared WASM memory.
33      * cptr - a pointer to the data to deserialize.
34      * length - length of the data in bytes.
35      * The caller must allocate the memory with M._malloc where M is the wasm module in javascript
36      * and copy the data into M.buffer at the pointer returned by malloc.
37      *
38      * uintptr_t is used here because emscripten will not allow binding of functions with pointers
39      * to primitive types. We can instead pass a number and cast it to whatever kind of
40      * pointer we're expecting.
41      */
loadSkp(uintptr_t cptr,int length)42     void loadSkp(uintptr_t cptr, int length) {
43       const auto* data = reinterpret_cast<const uint8_t*>(cptr);
44       // todo: pass in bounds
45       fDebugCanvas.reset(new SkDebugCanvas(720, 1280));
46       SkDebugf("SkDebugCanvas created.\n");
47       // note overloaded = operator that actually does a move
48       fPicture = SkPicture::MakeFromData(data, length);
49       if (!fPicture) {
50         SkDebugf("Unable to parse SKP file.\n");
51         return;
52       }
53       SkDebugf("Parsed SKP file.\n");
54       // Only draw picture to the debug canvas once.
55       fDebugCanvas->drawPicture(fPicture);
56       SkDebugf("Added picture with %d commands.\n", fDebugCanvas->getSize());
57     }
58 
59     /* drawTo asks the debug canvas to draw from the beginning of the picture
60      * to the given command and flush the canvas.
61      */
drawTo(SkSurface * surface,int32_t index)62     void drawTo(SkSurface* surface, int32_t index) {
63       fDebugCanvas->drawTo(surface->getCanvas(), index);
64       surface->getCanvas()->flush();
65     }
66 
67   private:
68     // admission of ignorance - don't know when to use unique pointer or sk_sp
69     std::unique_ptr<SkDebugCanvas> fDebugCanvas;
70     sk_sp<SkPicture> fPicture;
71 };
72 
73 using namespace emscripten;
EMSCRIPTEN_BINDINGS(my_module)74 EMSCRIPTEN_BINDINGS(my_module) {
75 
76   // The main class that the JavaScript in index.html uses
77   class_<SkpDebugPlayer>("SkpDebugPlayer")
78     .constructor<>()
79     .function("loadSkp", &SkpDebugPlayer::loadSkp, allow_raw_pointers())
80     .function("drawTo", &SkpDebugPlayer::drawTo, allow_raw_pointers());
81 
82   // Symbols needed by cpu.js to perform surface creation and flushing.
83   enum_<SkColorType>("ColorType")
84     .value("RGBA_8888", SkColorType::kRGBA_8888_SkColorType);
85   enum_<SkAlphaType>("AlphaType")
86     .value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType);
87   value_object<SimpleImageInfo>("SkImageInfo")
88     .field("width",     &SimpleImageInfo::width)
89     .field("height",    &SimpleImageInfo::height)
90     .field("colorType", &SimpleImageInfo::colorType)
91     .field("alphaType", &SimpleImageInfo::alphaType);
92   constant("TRANSPARENT", (JSColor) SK_ColorTRANSPARENT);
93   function("_getRasterDirectSurface", optional_override([](const SimpleImageInfo ii,
94                                                            uintptr_t /* uint8_t*  */ pPtr,
95                                                            size_t rowBytes)->sk_sp<SkSurface> {
96     uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
97     SkImageInfo imageInfo = toSkImageInfo(ii);
98     return SkSurface::MakeRasterDirect(imageInfo, pixels, rowBytes, nullptr);
99   }), allow_raw_pointers());
100   class_<SkSurface>("SkSurface")
101     .smart_ptr<sk_sp<SkSurface>>("sk_sp<SkSurface>")
102     .function("width", &SkSurface::width)
103     .function("height", &SkSurface::height)
104     .function("_flush", select_overload<void()>(&SkSurface::flush))
105     .function("getCanvas", &SkSurface::getCanvas, allow_raw_pointers());
106   class_<SkCanvas>("SkCanvas")
107     .function("clear", optional_override([](SkCanvas& self, JSColor color)->void {
108       // JS side gives us a signed int instead of an unsigned int for color
109       // Add a optional_override to change it out.
110       self.clear(SkColor(color));
111     }));
112 }
113