diff --git a/frontend/render_v2/cpp/js/preamble.js b/frontend/render_v2/cpp/js/preamble.js index 0f4d605a8..4f89a7176 100644 --- a/frontend/render_v2/cpp/js/preamble.js +++ b/frontend/render_v2/cpp/js/preamble.js @@ -2,12 +2,8 @@ (function (Renderer) { console.log("preamble", Renderer); - // - let gr; - let surface; - + // Sets canvas. Renderer.setCanvas = function setCanvas(canvas, attrs) { - console.log("GL", GL); const context = GL.createContext(canvas, attrs); if (!context) { throw new Error('Could not create a new WebGL context') @@ -18,78 +14,24 @@ // to handle certain GPU corner cases. GL.currentContext.GLctx.getExtension('WEBGL_debug_renderer_info'); - console.log("setCanvas", canvas, attrs); - gr = this._MakeGrContext(); - console.log("gr", gr); - - surface = this._MakeOnScreenGLSurface(gr, canvas.width, canvas.height); - console.log("surface", surface); - if (!surface) { - throw new Error('Cannot initialize surface') - } + // Initializes everything needed. + this._InitCanvas(canvas.width, canvas.height); }; - function wasMalloced(obj) { - return obj && obj['_ck']; - } - - function copy1dArray(arr, dest, ptr) { - if (!arr || !arr.length) return null; - if (wasMalloced(arr)) { - return arr.byteOffset; + Renderer.setObjects = function setObjects(vbox, zoom, objects) { + this._SetObjects(objects.cnt); + for (let index = 0; index < objects.cnt; index++) { + const object = objects.arr[index * 2 + 1]; + this._SetObject( + index, + object.selrect.x, + object.selrect.y, + object.selrect.width, + object.selrect.height, + ); } - const bytesPerElement = Renderer[dest].BYTES_PER_ELEMENT; - if (!ptr) { - ptr = Renderer._malloc(arr.length * bytesPerElement); - } - Renderer[dest].set(arr, ptr / bytesPerElement); - return ptr; - } - - function copyRectToWasm(fourFloats, ptr) { - return copy1dArray(fourFloats, 'HEAPF32', ptr || null); - } - - function copyColorToWasm(color4f, ptr) { - return copy1dArray(color4f, 'HEAPF32', ptr || null); - } + }; Renderer.drawCanvas = function drawCanvas(vbox, zoom, objects) { - console.log("vbox", vbox); - console.log("zoom", zoom); - if (!surface) { - throw new Error('Surface uninitialized'); - } - - console.log("renderer", Renderer); - console.log("surface", surface); - - // Esto es una ÑAPA terrible, no me gusta. - if (!Renderer.Paint.prototype.setColor) { - Renderer.Paint.prototype.setColor = function(color4f, colorSpace = null) { - const cPtr = copyColorToWasm(color4f); - this._setColor(cPtr, colorSpace); - } - } - - const paint = new Renderer.Paint(); - paint.setColor(Float32Array.of(1.0, 0, 0, 1.0)); - paint.setStyle(Renderer.PaintStyle.Fill); - paint.setAntiAlias(true); - console.log("paint", paint); - - const canvas = surface._getCanvas(); - console.log("canvas", canvas); - - const cPtr = copyColorToWasm(Float32Array.of(0.0, 0.0, 0.0, 1.0)) - canvas._clear(cPtr); - console.log("canvas cleared"); - - for (const { val: object } of objects) { - console.log("object", object); - const rr = Float32Array.of(object.selrect.x, object.selrect.y, object.selrect.width, object.selrect.height); - - const rPtr = copyRectToWasm(rr); - canvas._drawRect(rPtr, paint); - } + this._DrawCanvas(vbox.x, vbox.y, zoom); }; diff --git a/frontend/render_v2/cpp/src/main.cpp b/frontend/render_v2/cpp/src/main.cpp index a58ba9a1e..4a3a19bb1 100644 --- a/frontend/render_v2/cpp/src/main.cpp +++ b/frontend/render_v2/cpp/src/main.cpp @@ -1,10 +1,3 @@ -/* - * Copyright 2018 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - #include "include/android/SkAnimatedImage.h" #include "include/codec/SkAndroidCodec.h" #include "include/codec/SkEncodedImageFormat.h" @@ -67,6 +60,7 @@ #include "src/sksl/SkSLCompiler.h" #include "modules/canvaskit/WasmCommon.h" + #include #include #include @@ -126,2485 +120,121 @@ #include "include/ports/SkFontMgr_data.h" #endif -struct OptionalMatrix : SkMatrix -{ - OptionalMatrix(WASMPointerF32 mPtr) - { - if (mPtr) - { - const SkScalar *nineMatrixValues = reinterpret_cast(mPtr); - this->set9(nineMatrixValues); - } - } +// Global data needed to keep everything in place. +sk_sp context = nullptr; +sk_sp surface = nullptr; +SkCanvas *canvas = nullptr; + +struct PenpotRect { + float x, y, width, height; }; -SkColor4f ptrToSkColor4f(WASMPointerF32 cPtr) -{ - float *fourFloats = reinterpret_cast(cPtr); - SkColor4f color; - memcpy(&color, fourFloats, 4 * sizeof(float)); - return color; -} - -SkRRect ptrToSkRRect(WASMPointerF32 fPtr) -{ - // In order, these floats should be 4 floats for the rectangle - // (left, top, right, bottom) and then 8 floats for the radii - // (upper left, upper right, lower right, lower left). - const SkScalar *twelveFloats = reinterpret_cast(fPtr); - const SkRect rect = reinterpret_cast(twelveFloats)[0]; - const SkVector *radiiValues = reinterpret_cast(twelveFloats + 4); - - SkRRect rr; - rr.setRectRadii(rect, radiiValues); - return rr; -} - -// Surface creation structs and helpers -struct SimpleImageInfo -{ - int width; - int height; - SkColorType colorType; - SkAlphaType alphaType; - sk_sp colorSpace; +struct PenpotColor { + float r, g, b, a; }; -SkImageInfo toSkImageInfo(const SimpleImageInfo &sii) -{ - return SkImageInfo::Make(sii.width, sii.height, sii.colorType, sii.alphaType, - sii.colorSpace ? sii.colorSpace : SkColorSpace::MakeSRGB()); -} - -#ifdef CK_ENABLE_WEBGL - -// Set the pixel format based on the colortype. -// These degrees of freedom are removed from canvaskit only to keep the interface simpler. -struct ColorSettings -{ - ColorSettings(sk_sp colorSpace) - { - if (colorSpace == nullptr || colorSpace->isSRGB()) - { - colorType = kRGBA_8888_SkColorType; - pixFormat = GR_GL_RGBA8; - } - else - { - colorType = kRGBA_F16_SkColorType; - pixFormat = GR_GL_RGBA16F; - } - } - SkColorType colorType; - GrGLenum pixFormat; +struct PenpotObject { + PenpotRect selRect; }; -sk_sp MakeGrContext() +std::vector objects(0); + +// Initializes all the structures and elements needed to start rendering things. +void InitCanvas(int width, int height) { + emscripten_log(EM_LOG_CONSOLE, "Initializing canvas %d %d", width, height); + // We assume that any calls we make to GL for the remainder of this function will go to the // desired WebGL Context. // setup interface. auto interface = GrGLMakeNativeInterface(); - // setup context - return GrDirectContext::MakeGL(interface); -} + // setup context. + context = GrDirectContext::MakeGL(interface); + + emscripten_log(EM_LOG_CONSOLE, "GL context initialized"); + + GrGLint sampleCnt = 0; + GrGLint stencil = 16; -sk_sp MakeOnScreenGLSurface(sk_sp dContext, int width, int height, - sk_sp colorSpace, int sampleCnt, int stencil) -{ // WebGL should already be clearing the color and stencil buffers, but do it again here to // ensure Skia receives them in the expected state. emscripten_glBindFramebuffer(GL_FRAMEBUFFER, 0); emscripten_glClearColor(0, 0, 0, 0); emscripten_glClearStencil(0); emscripten_glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - dContext->resetContext(kRenderTarget_GrGLBackendState | kMisc_GrGLBackendState); + context->resetContext(kRenderTarget_GrGLBackendState | kMisc_GrGLBackendState); // The on-screen canvas is FBO 0. Wrap it in a Skia render target so Skia can render to it. GrGLFramebufferInfo info; info.fFBOID = 0; - if (!colorSpace) - { - colorSpace = SkColorSpace::MakeSRGB(); + // Create the colorspace needed to represent graphics. + sk_sp colorSpace = SkColorSpace::MakeSRGB(); + + info.fFormat = GR_GL_RGBA8; // kRGBA_8888_SkColorType; + auto target = GrBackendRenderTargets::MakeGL( + width, + height, + sampleCnt, + stencil, + info + ); + + emscripten_log(EM_LOG_CONSOLE, "Creating new surface"); + sk_sp new_surface( + SkSurfaces::WrapBackendRenderTarget( + context.get(), + target, + kBottomLeft_GrSurfaceOrigin, + kRGBA_8888_SkColorType, + colorSpace, + nullptr)); + + surface = new_surface; + canvas = surface->getCanvas(); + emscripten_log(EM_LOG_CONSOLE, "Everything's ready!"); +} + +void DrawCanvas(float x, float y, float zoom) +{ + canvas->clear(SK_ColorTRANSPARENT); + canvas->save(); + canvas->scale(zoom, zoom); + canvas->translate(-x, -y); + emscripten_log(EM_LOG_CONSOLE, "Clearing canvas"); + for (auto object : objects) { + emscripten_log(EM_LOG_CONSOLE, "Drawing object"); + + SkPaint paint; + paint.setARGB(255, 255, 0, 0); + paint.setStyle(SkPaint::Style::kFill_Style); + + SkRect rect = SkRect::MakeXYWH(object.selRect.x, object.selRect.y, object.selRect.width, object.selRect.height); + canvas->drawRect(rect, paint); } + canvas->restore(); - const auto colorSettings = ColorSettings(colorSpace); - info.fFormat = colorSettings.pixFormat; - auto target = GrBackendRenderTargets::MakeGL(width, height, sampleCnt, stencil, info); - sk_sp surface(SkSurfaces::WrapBackendRenderTarget(dContext.get(), - target, - kBottomLeft_GrSurfaceOrigin, - colorSettings.colorType, - colorSpace, - nullptr)); - return surface; + emscripten_log(EM_LOG_CONSOLE, "Flushing and submitting"); + skgpu::ganesh::FlushAndSubmit(surface); } -sk_sp MakeOnScreenGLSurface(sk_sp dContext, int width, int height, - sk_sp colorSpace) -{ - GrGLint sampleCnt; - emscripten_glGetIntegerv(GL_SAMPLES, &sampleCnt); - - GrGLint stencil; - emscripten_glGetIntegerv(GL_STENCIL_BITS, &stencil); - - return MakeOnScreenGLSurface(dContext, width, height, colorSpace, sampleCnt, stencil); +void SetObjects(int num_objects) { + emscripten_log(EM_LOG_CONSOLE, "Resizing objects vector capacity %d", num_objects); + objects.resize(num_objects); } -sk_sp MakeOnScreenGLSurface(sk_sp dContext, int width, int height) { - GrGLint sampleCnt; - emscripten_glGetIntegerv(GL_SAMPLES, &sampleCnt); - - GrGLint stencil; - emscripten_glGetIntegerv(GL_STENCIL_BITS, &stencil); - - return MakeOnScreenGLSurface(dContext, width, height, SkColorSpace::MakeSRGB(), sampleCnt, stencil); -} - -sk_sp MakeRenderTarget(sk_sp dContext, int width, int height) -{ - SkImageInfo info = SkImageInfo::MakeN32( - width, height, SkAlphaType::kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); - - sk_sp surface(SkSurfaces::RenderTarget(dContext.get(), - skgpu::Budgeted::kYes, - info, - 0, - kBottomLeft_GrSurfaceOrigin, - nullptr, - true)); - return surface; -} - -sk_sp MakeRenderTarget(sk_sp dContext, SimpleImageInfo sii) -{ - sk_sp surface(SkSurfaces::RenderTarget(dContext.get(), - skgpu::Budgeted::kYes, - toSkImageInfo(sii), - 0, - kBottomLeft_GrSurfaceOrigin, - nullptr, - true)); - return surface; -} -#endif // CK_ENABLE_WEBGL - -#ifdef CK_ENABLE_WEBGPU - -sk_sp MakeGrContext() -{ - GrContextOptions options; - wgpu::Device device = wgpu::Device::Acquire(emscripten_webgpu_get_device()); - return GrDirectContext::MakeDawn(device, options); -} - -sk_sp MakeGPUTextureSurface(sk_sp dContext, - uint32_t textureHandle, uint32_t textureFormat, - int width, int height, sk_sp colorSpace) -{ - if (!colorSpace) - { - colorSpace = SkColorSpace::MakeSRGB(); - } - - wgpu::TextureFormat format = static_cast(textureFormat); - wgpu::Texture texture(emscripten_webgpu_import_texture(textureHandle)); - emscripten_webgpu_release_js_handle(textureHandle); - - // GrDawnRenderTargetInfo currently only supports a 1-mip TextureView. - constexpr uint32_t mipLevelCount = 1; - constexpr uint32_t sampleCount = 1; - - GrDawnTextureInfo info; - info.fTexture = texture; - info.fFormat = format; - info.fLevelCount = mipLevelCount; - - GrBackendTexture target(width, height, info); - return SkSurfaces::WrapBackendTexture( - dContext.get(), - target, - kTopLeft_GrSurfaceOrigin, - sampleCount, - colorSpace->isSRGB() ? kRGBA_8888_SkColorType : kRGBA_F16_SkColorType, - colorSpace, - nullptr); -} - -bool ReplaceBackendTexture(SkSurface &surface, uint32_t textureHandle, uint32_t textureFormat, - int width, int height) -{ - wgpu::TextureFormat format = static_cast(textureFormat); - wgpu::Texture texture(emscripten_webgpu_import_texture(textureHandle)); - emscripten_webgpu_release_js_handle(textureHandle); - - GrDawnTextureInfo info; - info.fTexture = texture; - info.fFormat = format; - info.fLevelCount = 1; - - // Use kDiscard_ContentChangeMode to discard the contents of the old backing texture. This not - // only avoids an unnecessary blit, we also don't support copying the contents of a swapchain - // texture due to the default GPUCanvasConfiguration usage bits we used when configuring the - // GPUCanvasContext in JS. - // - // The default usage bits only contain GPUTextureUsage.RENDER_ATTACHMENT. To support a copy we - // would need to also set GPUTextureUsage.TEXTURE_BINDING (to sample it in a shader) or - // GPUTextureUsage.COPY_SRC (for a copy command). - // - // See https://www.w3.org/TR/webgpu/#namespacedef-gputextureusage and - // https://www.w3.org/TR/webgpu/#dictdef-gpucanvasconfiguration. - GrBackendTexture target(width, height, info); - return surface.replaceBackendTexture(target, kTopLeft_GrSurfaceOrigin, - SkSurface::kDiscard_ContentChangeMode); -} - -#endif // CK_ENABLE_WEBGPU - -//======================================================================================== -// Path things -//======================================================================================== - -// All these Apply* methods are simple wrappers to avoid returning an object. -// The default WASM bindings produce code that will leak if a return value -// isn't assigned to a JS variable and has delete() called on it. -// These Apply methods, combined with the smarter binding code allow for chainable -// commands that don't leak if the return value is ignored (i.e. when used intuitively). -void ApplyAddPath(SkPath &orig, const SkPath &newPath, - SkScalar scaleX, SkScalar skewX, SkScalar transX, - SkScalar skewY, SkScalar scaleY, SkScalar transY, - SkScalar pers0, SkScalar pers1, SkScalar pers2, - bool extendPath) -{ - SkMatrix m = SkMatrix::MakeAll(scaleX, skewX, transX, - skewY, scaleY, transY, - pers0, pers1, pers2); - orig.addPath(newPath, m, extendPath ? SkPath::kExtend_AddPathMode : SkPath::kAppend_AddPathMode); -} - -void ApplyArcToTangent(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, - SkScalar radius) -{ - p.arcTo(x1, y1, x2, y2, radius); -} - -void ApplyArcToArcSize(SkPath &orig, SkScalar rx, SkScalar ry, SkScalar xAxisRotate, - bool useSmallArc, bool ccw, SkScalar x, SkScalar y) -{ - auto arcSize = useSmallArc ? SkPath::ArcSize::kSmall_ArcSize : SkPath::ArcSize::kLarge_ArcSize; - auto sweep = ccw ? SkPathDirection::kCCW : SkPathDirection::kCW; - orig.arcTo(rx, ry, xAxisRotate, arcSize, sweep, x, y); -} - -void ApplyRArcToArcSize(SkPath &orig, SkScalar rx, SkScalar ry, SkScalar xAxisRotate, - bool useSmallArc, bool ccw, SkScalar dx, SkScalar dy) -{ - auto arcSize = useSmallArc ? SkPath::ArcSize::kSmall_ArcSize : SkPath::ArcSize::kLarge_ArcSize; - auto sweep = ccw ? SkPathDirection::kCCW : SkPathDirection::kCW; - orig.rArcTo(rx, ry, xAxisRotate, arcSize, sweep, dx, dy); -} - -void ApplyClose(SkPath &p) -{ - p.close(); -} - -void ApplyConicTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, - SkScalar w) -{ - p.conicTo(x1, y1, x2, y2, w); -} - -void ApplyRConicTo(SkPath &p, SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, - SkScalar w) -{ - p.rConicTo(dx1, dy1, dx2, dy2, w); -} - -void ApplyCubicTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, - SkScalar x3, SkScalar y3) -{ - p.cubicTo(x1, y1, x2, y2, x3, y3); -} - -void ApplyRCubicTo(SkPath &p, SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, - SkScalar dx3, SkScalar dy3) -{ - p.rCubicTo(dx1, dy1, dx2, dy2, dx3, dy3); -} - -void ApplyLineTo(SkPath &p, SkScalar x, SkScalar y) -{ - p.lineTo(x, y); -} - -void ApplyRLineTo(SkPath &p, SkScalar dx, SkScalar dy) -{ - p.rLineTo(dx, dy); -} - -void ApplyMoveTo(SkPath &p, SkScalar x, SkScalar y) -{ - p.moveTo(x, y); -} - -void ApplyRMoveTo(SkPath &p, SkScalar dx, SkScalar dy) -{ - p.rMoveTo(dx, dy); -} - -void ApplyReset(SkPath &p) -{ - p.reset(); -} - -void ApplyRewind(SkPath &p) -{ - p.rewind(); -} - -void ApplyQuadTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) -{ - p.quadTo(x1, y1, x2, y2); -} - -void ApplyRQuadTo(SkPath &p, SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2) -{ - p.rQuadTo(dx1, dy1, dx2, dy2); -} - -void ApplyTransform(SkPath &orig, - SkScalar scaleX, SkScalar skewX, SkScalar transX, - SkScalar skewY, SkScalar scaleY, SkScalar transY, - SkScalar pers0, SkScalar pers1, SkScalar pers2) -{ - SkMatrix m = SkMatrix::MakeAll(scaleX, skewX, transX, - skewY, scaleY, transY, - pers0, pers1, pers2); - orig.transform(m); -} - -#ifdef CK_INCLUDE_PATHOPS -bool ApplySimplify(SkPath &path) -{ - return Simplify(path, &path); -} - -bool ApplyPathOp(SkPath &pathOne, const SkPath &pathTwo, SkPathOp op) -{ - return Op(pathOne, pathTwo, op, &pathOne); -} - -SkPathOrNull MakePathFromOp(const SkPath &pathOne, const SkPath &pathTwo, SkPathOp op) -{ - SkPath out; - if (Op(pathOne, pathTwo, op, &out)) - { - return emscripten::val(out); - } - return emscripten::val::null(); -} - -SkPathOrNull MakeAsWinding(const SkPath &self) -{ - SkPath out; - if (AsWinding(self, &out)) - { - return emscripten::val(out); - } - return emscripten::val::null(); -} -#endif - -JSString ToSVGString(const SkPath &path) -{ - return emscripten::val(SkParsePath::ToSVGString(path).c_str()); -} - -SkPathOrNull MakePathFromSVGString(std::string str) -{ - SkPath path; - if (SkParsePath::FromSVGString(str.c_str(), &path)) - { - return emscripten::val(path); - } - return emscripten::val::null(); -} - -bool CanInterpolate(const SkPath &path1, const SkPath &path2) -{ - return path1.isInterpolatable(path2); -} - -SkPathOrNull MakePathFromInterpolation(const SkPath &path1, const SkPath &path2, SkScalar weight) -{ - SkPath out; - bool succeed = path1.interpolate(path2, weight, &out); - if (succeed) - { - return emscripten::val(out); - } - return emscripten::val::null(); -} - -SkPath CopyPath(const SkPath &a) -{ - SkPath copy(a); - return copy; -} - -bool Equals(const SkPath &a, const SkPath &b) -{ - return a == b; -} - -// ================================================================================= -// Creating/Exporting Paths with cmd arrays -// ================================================================================= - -static const int MOVE = 0; -static const int LINE = 1; -static const int QUAD = 2; -static const int CONIC = 3; -static const int CUBIC = 4; -static const int CLOSE = 5; - -Float32Array ToCmds(const SkPath &path) -{ - std::vector cmds; - for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) - { - switch (verb) - { - case SkPathVerb::kMove: - cmds.insert(cmds.end(), {MOVE, pts[0].x(), pts[0].y()}); - break; - case SkPathVerb::kLine: - cmds.insert(cmds.end(), {LINE, pts[1].x(), pts[1].y()}); - break; - case SkPathVerb::kQuad: - cmds.insert(cmds.end(), {QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y()}); - break; - case SkPathVerb::kConic: - cmds.insert(cmds.end(), {CONIC, - pts[1].x(), pts[1].y(), - pts[2].x(), pts[2].y(), *w}); - break; - case SkPathVerb::kCubic: - cmds.insert(cmds.end(), {CUBIC, - pts[1].x(), pts[1].y(), - pts[2].x(), pts[2].y(), - pts[3].x(), pts[3].y()}); - break; - case SkPathVerb::kClose: - cmds.push_back(CLOSE); - break; - } - } - return MakeTypedArray(cmds.size(), (const float *)cmds.data()); -} - -SkPathOrNull MakePathFromCmds(WASMPointerF32 cptr, int numCmds) -{ - const auto *cmds = reinterpret_cast(cptr); - SkPath path; - float x1, y1, x2, y2, x3, y3; - -// if there are not enough arguments, bail with the path we've constructed so far. -#define CHECK_NUM_ARGS(n) \ - if ((i + n) > numCmds) \ - { \ - SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \ - return emscripten::val::null(); \ - } - - for (int i = 0; i < numCmds;) - { - switch (sk_float_floor2int(cmds[i++])) - { - case MOVE: - CHECK_NUM_ARGS(2) - x1 = cmds[i++]; - y1 = cmds[i++]; - path.moveTo(x1, y1); - break; - case LINE: - CHECK_NUM_ARGS(2) - x1 = cmds[i++]; - y1 = cmds[i++]; - path.lineTo(x1, y1); - break; - case QUAD: - CHECK_NUM_ARGS(4) - x1 = cmds[i++]; - y1 = cmds[i++]; - x2 = cmds[i++]; - y2 = cmds[i++]; - path.quadTo(x1, y1, x2, y2); - break; - case CONIC: - CHECK_NUM_ARGS(5) - x1 = cmds[i++]; - y1 = cmds[i++]; - x2 = cmds[i++]; - y2 = cmds[i++]; - x3 = cmds[i++]; // weight - path.conicTo(x1, y1, x2, y2, x3); - break; - case CUBIC: - CHECK_NUM_ARGS(6) - x1 = cmds[i++]; - y1 = cmds[i++]; - x2 = cmds[i++]; - y2 = cmds[i++]; - x3 = cmds[i++]; - y3 = cmds[i++]; - path.cubicTo(x1, y1, x2, y2, x3, y3); - break; - case CLOSE: - path.close(); - break; - default: - SkDebugf(" path: UNKNOWN command %f, aborting dump...\n", cmds[i - 1]); - return emscripten::val::null(); - } - } - -#undef CHECK_NUM_ARGS - - return emscripten::val(path); -} - -void PathAddVerbsPointsWeights(SkPath &path, WASMPointerU8 verbsPtr, int numVerbs, - WASMPointerF32 ptsPtr, int numPts, - WASMPointerF32 wtsPtr, int numWts) -{ - const uint8_t *verbs = reinterpret_cast(verbsPtr); - const float *pts = reinterpret_cast(ptsPtr); - const float *weights = reinterpret_cast(wtsPtr); - -#define CHECK_NUM_POINTS(n) \ - if ((ptIdx + n) > numPts) \ - { \ - SkDebugf("Not enough points to match the verbs. Saw %d points\n", numPts); \ - return; \ - } -#define CHECK_NUM_WEIGHTS(n) \ - if ((wtIdx + n) > numWts) \ - { \ - SkDebugf("Not enough weights to match the verbs. Saw %d weights\n", numWts); \ - return; \ - } - - path.incReserve(numPts); - int ptIdx = 0; - int wtIdx = 0; - for (int v = 0; v < numVerbs; ++v) - { - switch (verbs[v]) - { - case MOVE: - CHECK_NUM_POINTS(2) - path.moveTo(pts[ptIdx], pts[ptIdx + 1]); - ptIdx += 2; - break; - case LINE: - CHECK_NUM_POINTS(2) - path.lineTo(pts[ptIdx], pts[ptIdx + 1]); - ptIdx += 2; - break; - case QUAD: - CHECK_NUM_POINTS(4) - path.quadTo(pts[ptIdx], pts[ptIdx + 1], pts[ptIdx + 2], pts[ptIdx + 3]); - ptIdx += 4; - break; - case CONIC: - CHECK_NUM_POINTS(4) - CHECK_NUM_WEIGHTS(1) - path.conicTo(pts[ptIdx], pts[ptIdx + 1], pts[ptIdx + 2], pts[ptIdx + 3], - weights[wtIdx]); - ptIdx += 4; - wtIdx++; - break; - case CUBIC: - CHECK_NUM_POINTS(6) - path.cubicTo(pts[ptIdx], pts[ptIdx + 1], - pts[ptIdx + 2], pts[ptIdx + 3], - pts[ptIdx + 4], pts[ptIdx + 5]); - ptIdx += 6; - break; - case CLOSE: - path.close(); - break; - } - } -#undef CHECK_NUM_POINTS -#undef CHECK_NUM_WEIGHTS -} - -SkPath MakePathFromVerbsPointsWeights(WASMPointerU8 verbsPtr, int numVerbs, - WASMPointerF32 ptsPtr, int numPts, - WASMPointerF32 wtsPtr, int numWts) -{ - SkPath path; - PathAddVerbsPointsWeights(path, verbsPtr, numVerbs, ptsPtr, numPts, wtsPtr, numWts); - return path; -} - -//======================================================================================== -// Path Effects -//======================================================================================== - -bool ApplyDash(SkPath &path, SkScalar on, SkScalar off, SkScalar phase) -{ - SkScalar intervals[] = {on, off}; - auto pe = SkDashPathEffect::Make(intervals, 2, phase); - if (!pe) - { - SkDebugf("Invalid args to dash()\n"); - return false; - } - SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle); - if (pe->filterPath(&path, path, &rec, nullptr)) - { - return true; - } - SkDebugf("Could not make dashed path\n"); - return false; -} - -bool ApplyTrim(SkPath &path, SkScalar startT, SkScalar stopT, bool isComplement) -{ - auto mode = isComplement ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal; - auto pe = SkTrimPathEffect::Make(startT, stopT, mode); - if (!pe) - { - SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n"); - return false; - } - SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle); - if (pe->filterPath(&path, path, &rec, nullptr)) - { - return true; - } - SkDebugf("Could not trim path\n"); - return false; -} - -struct StrokeOpts -{ - // Default values are set in interface.js which allows clients - // to set any number of them. Otherwise, the binding code complains if - // any are omitted. - SkScalar width; - SkScalar miter_limit; - SkPaint::Join join; - SkPaint::Cap cap; - float precision; -}; - -bool ApplyStroke(SkPath &path, StrokeOpts opts) -{ - SkPaint p; - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeCap(opts.cap); - p.setStrokeJoin(opts.join); - p.setStrokeWidth(opts.width); - p.setStrokeMiter(opts.miter_limit); - - return skpathutils::FillPathWithPaint(path, p, &path, nullptr, opts.precision); -} - -// This function is private, we call it in interface.js -void computeTonalColors(WASMPointerF32 cPtrAmbi, WASMPointerF32 cPtrSpot) -{ - // private methods accepting colors take pointers to floats already copied into wasm memory. - float *ambiFloats = reinterpret_cast(cPtrAmbi); - float *spotFloats = reinterpret_cast(cPtrSpot); - SkColor4f ambiColor = {ambiFloats[0], ambiFloats[1], ambiFloats[2], ambiFloats[3]}; - SkColor4f spotColor = {spotFloats[0], spotFloats[1], spotFloats[2], spotFloats[3]}; - - // This function takes SkColor - SkColor resultAmbi, resultSpot; - SkShadowUtils::ComputeTonalColors( - ambiColor.toSkColor(), spotColor.toSkColor(), - &resultAmbi, &resultSpot); - - // Convert back to color4f - const SkColor4f ambi4f = SkColor4f::FromColor(resultAmbi); - const SkColor4f spot4f = SkColor4f::FromColor(resultSpot); - - // Re-use the caller's allocated memory to hold the result. - memcpy(ambiFloats, ambi4f.vec(), 4 * sizeof(SkScalar)); - memcpy(spotFloats, spot4f.vec(), 4 * sizeof(SkScalar)); -} - -#ifdef CK_INCLUDE_RUNTIME_EFFECT -struct RuntimeEffectUniform -{ - int columns; - int rows; - int slot; // the index into the uniforms array that this uniform begins. - bool isInteger; -}; - -RuntimeEffectUniform fromUniform(const SkRuntimeEffect::Uniform &u) -{ - RuntimeEffectUniform su; - su.rows = u.count; // arrayLength - su.columns = 1; - su.isInteger = false; - using Type = SkRuntimeEffect::Uniform::Type; - switch (u.type) - { - case Type::kFloat: - break; - case Type::kFloat2: - su.columns = 2; - break; - case Type::kFloat3: - su.columns = 3; - break; - case Type::kFloat4: - su.columns = 4; - break; - case Type::kFloat2x2: - su.columns = 2; - su.rows *= 2; - break; - case Type::kFloat3x3: - su.columns = 3; - su.rows *= 3; - break; - case Type::kFloat4x4: - su.columns = 4; - su.rows *= 4; - break; - case Type::kInt: - su.isInteger = true; - break; - case Type::kInt2: - su.columns = 2; - su.isInteger = true; - break; - case Type::kInt3: - su.columns = 3; - su.isInteger = true; - break; - case Type::kInt4: - su.columns = 4; - su.isInteger = true; - break; - } - su.slot = u.offset / sizeof(float); - return su; -} - -void castUniforms(void *data, size_t dataLen, const SkRuntimeEffect &effect) -{ - if (dataLen != effect.uniformSize()) - { - // Incorrect number of uniforms. Our code below could read/write off the end of the buffer. - // However, shader creation is going to fail anyway, so just do nothing. - return; - } - - float *fltData = reinterpret_cast(data); - for (const auto &u : effect.uniforms()) - { - RuntimeEffectUniform reu = fromUniform(u); - if (reu.isInteger) - { - // The SkSL is expecting integers in the uniform data - for (int i = 0; i < reu.columns * reu.rows; ++i) - { - int numAsInt = static_cast(fltData[reu.slot + i]); - fltData[reu.slot + i] = SkBits2Float(numAsInt); - } - } - } -} -#endif - -sk_sp alwaysSaveTypefaceBytes(SkTypeface *face, void *) -{ - return face->serialize(SkTypeface::SerializeBehavior::kDoIncludeData); -} - -// These objects have private destructors / delete methods - I don't think -// we need to do anything other than tell emscripten to do nothing. -namespace emscripten -{ - namespace internal - { - template - void raw_destructor(ClassType *); - - template <> - void raw_destructor(SkContourMeasure *ptr) - { - } - - template <> - void raw_destructor(SkVertices *ptr) - { - } - -#ifndef CK_NO_FONTS - template <> - void raw_destructor(SkTextBlob *ptr) - { - } - - template <> - void raw_destructor(SkTypeface *ptr) - { - } -#endif - } -} - -// toBytes returns a Uint8Array that has a copy of the data in the given SkData. -Uint8Array toBytes(sk_sp data) -{ - // By making the copy using the JS transliteration, we don't risk the SkData object being - // cleaned up before we make the copy. - return emscripten::val( - // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#memory-views - typed_memory_view(data->size(), data->bytes())) - .call("slice"); // slice with no args makes a copy of the memory view. -} - -#ifdef CK_ENABLE_WEBGL -// We need to call into the JS side of things to free webGL contexts. This object will be called -// with _setTextureCleanup after CanvasKit loads. The object will have one attribute, -// a function called deleteTexture that takes two ints. -JSObject textureCleanup = emscripten::val::null(); - -struct TextureReleaseContext -{ - // This refers to which webgl context, i.e. which surface, owns the texture. We need this - // to route the deleteTexture to the right context. - uint32_t webglHandle; - // This refers to the index of the texture in the complete list of textures. - uint32_t texHandle; -}; - -void deleteJSTexture(SkImages::ReleaseContext rc) -{ - auto ctx = reinterpret_cast(rc); - textureCleanup.call("deleteTexture", ctx->webglHandle, ctx->texHandle); - delete ctx; -} - -class ExternalWebGLTexture : public GrExternalTexture -{ -public: - ExternalWebGLTexture(GrBackendTexture backendTexture, uint32_t textureHandle, EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context) : fBackendTexture(backendTexture), fWebglHandle(context), fTextureHandle(textureHandle) {} - - GrBackendTexture getBackendTexture() override - { - return fBackendTexture; - } - - void dispose() override - { - textureCleanup.call("deleteTexture", fWebglHandle, fTextureHandle); - } - -private: - GrBackendTexture fBackendTexture; - - // This refers to which webgl context, i.e. which surface, owns the texture. We need this - // to route the deleteTexture to the right context. - uint32_t fWebglHandle; - // This refers to the index of the texture in the complete list of textures. - uint32_t fTextureHandle; -}; - -class WebGLTextureImageGenerator : public GrExternalTextureGenerator -{ -public: - WebGLTextureImageGenerator(SkImageInfo ii, JSObject callbackObj) : GrExternalTextureGenerator(ii), - fCallback(callbackObj) {} - - ~WebGLTextureImageGenerator() override - { - // This cleans up the associated TextureSource that is used to make the texture - // (i.e. "makeTexture" below). We expect this destructor to be called when the - // SkImage that this Generator belongs to is destroyed. - fCallback.call("freeSrc"); - } - - std::unique_ptr generateExternalTexture(GrRecordingContext *ctx, - GrMipMapped mipmapped) override - { - GrGLTextureInfo glInfo; - - // This callback is defined in webgl.js - glInfo.fID = fCallback.call("makeTexture"); - - // The format and target should match how we make the texture on the JS side - // See the implementation of the makeTexture function. - glInfo.fFormat = GR_GL_RGBA8; - glInfo.fTarget = GR_GL_TEXTURE_2D; - - auto backendTexture = GrBackendTextures::MakeGL(fInfo.width(), - fInfo.height(), - mipmapped, - glInfo); - - // In order to bind the image source to the texture, makeTexture has changed which - // texture is "in focus" for the WebGL context. - GrAsDirectContext(ctx)->resetContext(kTextureBinding_GrGLBackendState); - return std::make_unique( - backendTexture, glInfo.fID, emscripten_webgl_get_current_context()); - } - -private: - JSObject fCallback; -}; - -// callbackObj has two functions in it, one to create a texture "makeTexture" and one to clean up -// the underlying texture source "freeSrc". This way, we can create WebGL textures for each -// surface/WebGLContext that the image is used on (we cannot share WebGLTextures across contexts). -sk_sp MakeImageFromGenerator(SimpleImageInfo ii, JSObject callbackObj) -{ - auto gen = std::make_unique(toSkImageInfo(ii), callbackObj); - return SkImages::DeferredFromTextureGenerator(std::move(gen)); -} -#endif // CK_ENABLE_WEBGL - -static Uint8Array encodeImage(GrDirectContext *dContext, - sk_sp img, - SkEncodedImageFormat fmt, - int quality) -{ - sk_sp data = nullptr; - if (fmt == SkEncodedImageFormat::kJPEG) - { - SkJpegEncoder::Options opts; - opts.fQuality = quality; - data = SkJpegEncoder::Encode(dContext, img.get(), opts); - } - else if (fmt == SkEncodedImageFormat::kPNG) - { - data = SkPngEncoder::Encode(dContext, img.get(), {}); - } - else - { - SkWebpEncoder::Options opts; - if (quality >= 100) - { - opts.fCompression = SkWebpEncoder::Compression::kLossless; - opts.fQuality = 75; // This is effort to compress - } - else - { - opts.fCompression = SkWebpEncoder::Compression::kLossy; - opts.fQuality = quality; - } - data = SkWebpEncoder::Encode(dContext, img.get(), opts); - } - if (!data) - { - return emscripten::val::null(); - } - return toBytes(data); -} - -extern "C" { - EMSCRIPTEN_KEEPALIVE int add(int a, int b) { - return a + b; - } +void SetObject(int index, float x, float y, float width, float height) { + emscripten_log(EM_LOG_CONSOLE, "Setting object at %d %f %f %f %f", index, x, y, width, height); + objects[index].selRect.x = x; + objects[index].selRect.y = y; + objects[index].selRect.width = width; + objects[index].selRect.height = height; } EMSCRIPTEN_BINDINGS(Renderer) { -#ifdef ENABLE_GPU - constant("gpu", true); - function("_MakeGrContext", &MakeGrContext); -#endif // ENABLE_GPU - -#ifdef CK_ENABLE_WEBGL - constant("webgl", true); - function("_MakeOnScreenGLSurface", select_overload(sk_sp, int, int, sk_sp)>(&MakeOnScreenGLSurface)); - function("_MakeOnScreenGLSurface", select_overload(sk_sp, int, int, sk_sp, int, int)>(&MakeOnScreenGLSurface)); - function("_MakeOnScreenGLSurface", select_overload(sk_sp, int, int)>(&MakeOnScreenGLSurface)); - function("_MakeRenderTargetWH", select_overload(sk_sp, int, int)>(&MakeRenderTarget)); - function("_MakeRenderTargetII", select_overload(sk_sp, SimpleImageInfo)>(&MakeRenderTarget)); -#endif // CK_ENABLE_WEBGL - -#ifdef CK_ENABLE_WEBGPU - constant("webgpu", true); - function("_MakeGPUTextureSurface", &MakeGPUTextureSurface); -#endif // CK_ENABLE_WEBGPU - - function("getDecodeCacheLimitBytes", &SkResourceCache::GetTotalByteLimit); - function("setDecodeCacheLimitBytes", &SkResourceCache::SetTotalByteLimit); - function("getDecodeCacheUsedBytes", &SkResourceCache::GetTotalBytesUsed); - - function("_computeTonalColors", &computeTonalColors); - function("_decodeAnimatedImage", optional_override([](WASMPointerU8 iptr, size_t length) -> sk_sp - { - uint8_t* imgData = reinterpret_cast(iptr); - auto bytes = SkData::MakeFromMalloc(imgData, length); - auto aCodec = SkAndroidCodec::MakeFromData(std::move(bytes)); - if (nullptr == aCodec) { - return nullptr; - } - - return SkAnimatedImage::Make(std::move(aCodec)); }), - allow_raw_pointers()); - function("_decodeImage", optional_override([](WASMPointerU8 iptr, size_t length) -> sk_sp - { - uint8_t* imgData = reinterpret_cast(iptr); - sk_sp bytes = SkData::MakeFromMalloc(imgData, length); - return SkImages::DeferredFromEncodedData(std::move(bytes)); }), - allow_raw_pointers()); - - // These won't be called directly, there are corresponding JS helpers to deal with arrays. - function("_MakeImage", optional_override([](SimpleImageInfo ii, WASMPointerU8 pPtr, int plen, size_t rowBytes) -> sk_sp - { - uint8_t* pixels = reinterpret_cast(pPtr); - SkImageInfo info = toSkImageInfo(ii); - sk_sp pixelData = SkData::MakeFromMalloc(pixels, plen); - - return SkImages::RasterFromData(info, pixelData, rowBytes); }), - allow_raw_pointers()); - - function("_getShadowLocalBounds", optional_override([]( - WASMPointerF32 ctmPtr, const SkPath &path, - WASMPointerF32 zPlaneParamPtr, WASMPointerF32 lightPosPtr, - SkScalar lightRadius, uint32_t flags, WASMPointerF32 outPtr) -> bool - { - SkMatrix ctm; - const SkScalar* nineMatrixValues = reinterpret_cast(ctmPtr); - ctm.set9(nineMatrixValues); - const SkVector3* zPlaneParams = reinterpret_cast(zPlaneParamPtr); - const SkVector3* lightPos = reinterpret_cast(lightPosPtr); - SkRect* outputBounds = reinterpret_cast(outPtr); - return SkShadowUtils::GetLocalBounds(ctm, path, *zPlaneParams, *lightPos, lightRadius, - flags, outputBounds); })); - -#ifdef CK_SERIALIZE_SKP - function("_MakePicture", optional_override([](WASMPointerU8 dPtr, size_t bytes) -> sk_sp - { - uint8_t* d = reinterpret_cast(dPtr); - sk_sp data = SkData::MakeFromMalloc(d, bytes); - - return SkPicture::MakeFromData(data.get(), nullptr); }), - allow_raw_pointers()); -#endif - -#ifdef ENABLE_GPU - class_("GrDirectContext") - .smart_ptr>("sk_sp") - .function("_getResourceCacheLimitBytes", - optional_override([](GrDirectContext &self) -> size_t - { - int maxResources = 0;// ignored - size_t currMax = 0; - self.getResourceCacheLimits(&maxResources, &currMax); - return currMax; })) - .function("_getResourceCacheUsageBytes", - optional_override([](GrDirectContext &self) -> size_t - { - int usedResources = 0;// ignored - size_t currUsage = 0; - self.getResourceCacheUsage(&usedResources, &currUsage); - return currUsage; })) - .function("_releaseResourcesAndAbandonContext", - &GrDirectContext::releaseResourcesAndAbandonContext) - .function("_setResourceCacheLimitBytes", - optional_override([](GrDirectContext &self, size_t maxResourceBytes) -> void - { - int maxResources = 0; - size_t currMax = 0; // ignored - self.getResourceCacheLimits(&maxResources, &currMax); - self.setResourceCacheLimits(maxResources, maxResourceBytes); })); -#endif // ENABLE_GPU -#ifdef CK_ENABLE_WEBGL - // This allows us to give the C++ code a JS callback to delete textures that - // have been passed in via makeImageFromTexture and makeImageFromTextureSource. - function("_setTextureCleanup", optional_override([](JSObject callbackObj) -> void - { textureCleanup = callbackObj; })); -#endif - - class_("AnimatedImage") - .smart_ptr>("sk_sp") - .function("currentFrameDuration", &SkAnimatedImage::currentFrameDuration) - .function("decodeNextFrame", &SkAnimatedImage::decodeNextFrame) - .function("getFrameCount", &SkAnimatedImage::getFrameCount) - .function("getRepetitionCount", &SkAnimatedImage::getRepetitionCount) - .function("height", optional_override([](SkAnimatedImage &self) -> int32_t - { - // getBounds returns an SkRect, but internally, the width and height are ints. - return SkScalarFloorToInt(self.getBounds().height()); })) - .function("makeImageAtCurrentFrame", &SkAnimatedImage::getCurrentFrame) - .function("reset", &SkAnimatedImage::reset) - .function("width", optional_override([](SkAnimatedImage &self) -> int32_t - { return SkScalarFloorToInt(self.getBounds().width()); })); - - class_("Blender") - .smart_ptr>("sk_sp") - .class_function("Mode", &SkBlender::Mode); - - class_("Canvas") - .constructor<>() - .constructor() - .function("_clear", optional_override([](SkCanvas &self, WASMPointerF32 cPtr) - { self.clear(ptrToSkColor4f(cPtr)); })) - .function("clipPath", select_overload(&SkCanvas::clipPath)) - .function("_clipRRect", optional_override([](SkCanvas &self, WASMPointerF32 fPtr, SkClipOp op, bool doAntiAlias) - { self.clipRRect(ptrToSkRRect(fPtr), op, doAntiAlias); })) - .function("_clipRect", optional_override([](SkCanvas &self, WASMPointerF32 fPtr, SkClipOp op, bool doAntiAlias) - { - const SkRect* rect = reinterpret_cast(fPtr); - self.clipRect(*rect, op, doAntiAlias); })) - .function("_concat", optional_override([](SkCanvas &self, WASMPointerF32 mPtr) - { - //TODO(skbug.com/10108): make the JS side be column major. - const SkScalar* sixteenMatrixValues = reinterpret_cast(mPtr); - SkM44 m = SkM44::RowMajor(sixteenMatrixValues); - self.concat(m); })) - .function("_drawArc", optional_override([](SkCanvas &self, WASMPointerF32 fPtr, - SkScalar startAngle, SkScalar sweepAngle, - bool useCenter, const SkPaint &paint) - { - const SkRect* oval = reinterpret_cast(fPtr); - self.drawArc(*oval, startAngle, sweepAngle, useCenter, paint); })) - .function("_drawAtlasOptions", optional_override([](SkCanvas &self, const sk_sp &atlas, WASMPointerF32 xptr, WASMPointerF32 rptr, WASMPointerU32 cptr, int count, SkBlendMode mode, SkFilterMode filter, SkMipmapMode mipmap, const SkPaint *paint) -> void - { - const SkRSXform* dstXforms = reinterpret_cast(xptr); - const SkRect* srcRects = reinterpret_cast(rptr); - const SkColor* colors = nullptr; - if (cptr) { - colors = reinterpret_cast(cptr); - } - SkSamplingOptions sampling(filter, mipmap); - self.drawAtlas(atlas.get(), dstXforms, srcRects, colors, count, mode, sampling, - nullptr, paint); }), - allow_raw_pointers()) - .function("_drawAtlasCubic", optional_override([](SkCanvas &self, const sk_sp &atlas, WASMPointerF32 xptr, WASMPointerF32 rptr, WASMPointerU32 cptr, int count, SkBlendMode mode, float B, float C, const SkPaint *paint) -> void - { - const SkRSXform* dstXforms = reinterpret_cast(xptr); - const SkRect* srcRects = reinterpret_cast(rptr); - const SkColor* colors = nullptr; - if (cptr) { - colors = reinterpret_cast(cptr); - } - SkSamplingOptions sampling({B, C}); - self.drawAtlas(atlas.get(), dstXforms, srcRects, colors, count, mode, sampling, - nullptr, paint); }), - allow_raw_pointers()) - .function("_drawCircle", select_overload(&SkCanvas::drawCircle)) - .function("_drawColor", optional_override([](SkCanvas &self, WASMPointerF32 cPtr) - { self.drawColor(ptrToSkColor4f(cPtr)); })) - .function("_drawColor", optional_override([](SkCanvas &self, WASMPointerF32 cPtr, SkBlendMode mode) - { self.drawColor(ptrToSkColor4f(cPtr), mode); })) - .function("_drawColorInt", optional_override([](SkCanvas &self, SkColor color, SkBlendMode mode) - { self.drawColor(color, mode); })) - .function("_drawDRRect", optional_override([](SkCanvas &self, WASMPointerF32 outerPtr, - WASMPointerF32 innerPtr, const SkPaint &paint) - { self.drawDRRect(ptrToSkRRect(outerPtr), ptrToSkRRect(innerPtr), paint); })) - .function("_drawGlyphs", optional_override([](SkCanvas &self, - int count, - WASMPointerU16 glyphs, - WASMPointerF32 positions, - float x, float y, - const SkFont &font, - const SkPaint &paint) -> void - { self.drawGlyphs(count, - reinterpret_cast(glyphs), - reinterpret_cast(positions), - {x, y}, font, paint); })) - // TODO: deprecate this version, and require sampling - .function("_drawImage", optional_override([](SkCanvas &self, const sk_sp &image, SkScalar x, SkScalar y, const SkPaint *paint) - { self.drawImage(image.get(), x, y, SkSamplingOptions(), paint); }), - allow_raw_pointers()) - .function("_drawImageCubic", optional_override([](SkCanvas &self, const sk_sp &img, SkScalar left, SkScalar top, float B, float C, // See SkSamplingOptions.h for docs. - const SkPaint *paint) -> void - { self.drawImage(img.get(), left, top, SkSamplingOptions({B, C}), paint); }), - allow_raw_pointers()) - .function("_drawImageOptions", optional_override([](SkCanvas &self, const sk_sp &img, SkScalar left, SkScalar top, SkFilterMode filter, SkMipmapMode mipmap, const SkPaint *paint) -> void - { self.drawImage(img.get(), left, top, {filter, mipmap}, paint); }), - allow_raw_pointers()) - - .function("_drawImageNine", optional_override([](SkCanvas &self, const sk_sp &image, WASMPointerU32 centerPtr, WASMPointerF32 dstPtr, SkFilterMode filter, const SkPaint *paint) -> void - { - const SkIRect* center = reinterpret_cast(centerPtr); - const SkRect* dst = reinterpret_cast(dstPtr); - - self.drawImageNine(image.get(), *center, *dst, filter, paint); }), - allow_raw_pointers()) - // TODO: deprecate this version, and require sampling - .function("_drawImageRect", optional_override([](SkCanvas &self, const sk_sp &image, WASMPointerF32 srcPtr, WASMPointerF32 dstPtr, const SkPaint *paint, bool fastSample) -> void - { - const SkRect* src = reinterpret_cast(srcPtr); - const SkRect* dst = reinterpret_cast(dstPtr); - self.drawImageRect(image, *src, *dst, SkSamplingOptions(), paint, - fastSample ? SkCanvas::kFast_SrcRectConstraint: - SkCanvas::kStrict_SrcRectConstraint); }), - allow_raw_pointers()) - .function("_drawImageRectCubic", optional_override([](SkCanvas &self, const sk_sp &image, WASMPointerF32 srcPtr, WASMPointerF32 dstPtr, float B, float C, // See SkSamplingOptions.h for docs. - const SkPaint *paint) -> void - { - const SkRect* src = reinterpret_cast(srcPtr); - const SkRect* dst = reinterpret_cast(dstPtr); - auto constraint = SkCanvas::kStrict_SrcRectConstraint; // TODO: get from caller - self.drawImageRect(image.get(), *src, *dst, SkSamplingOptions({B, C}), paint, constraint); }), - allow_raw_pointers()) - .function("_drawImageRectOptions", optional_override([](SkCanvas &self, const sk_sp &image, WASMPointerF32 srcPtr, WASMPointerF32 dstPtr, SkFilterMode filter, SkMipmapMode mipmap, const SkPaint *paint) -> void - { - const SkRect* src = reinterpret_cast(srcPtr); - const SkRect* dst = reinterpret_cast(dstPtr); - auto constraint = SkCanvas::kStrict_SrcRectConstraint; // TODO: get from caller - self.drawImageRect(image.get(), *src, *dst, {filter, mipmap}, paint, constraint); }), - allow_raw_pointers()) - .function("_drawLine", select_overload(&SkCanvas::drawLine)) - .function("_drawOval", optional_override([](SkCanvas &self, WASMPointerF32 fPtr, - const SkPaint &paint) -> void - { - const SkRect* oval = reinterpret_cast(fPtr); - self.drawOval(*oval, paint); })) - .function("_drawPaint", &SkCanvas::drawPaint) -#ifdef CK_INCLUDE_PARAGRAPH - .function("_drawParagraph", optional_override([](SkCanvas &self, skia::textlayout::Paragraph *p, SkScalar x, SkScalar y) - { p->paint(&self, x, y); }), - allow_raw_pointers()) -#endif - .function("_drawPath", &SkCanvas::drawPath) - .function("_drawPatch", optional_override([](SkCanvas &self, - WASMPointerF32 cubics, - WASMPointerU32 colors, - WASMPointerF32 texs, - SkBlendMode mode, - const SkPaint &paint) -> void - { self.drawPatch(reinterpret_cast(cubics), - reinterpret_cast(colors), - reinterpret_cast(texs), - mode, paint); })) - // Of note, picture is *not* what is colloquially thought of as a "picture", what we call - // a bitmap. An SkPicture is a series of draw commands. - .function("_drawPicture", select_overload &)>(&SkCanvas::drawPicture)) - .function("_drawPoints", optional_override([](SkCanvas &self, SkCanvas::PointMode mode, - WASMPointerF32 pptr, - int count, SkPaint &paint) -> void - { - const SkPoint* pts = reinterpret_cast(pptr); - self.drawPoints(mode, count, pts, paint); })) - .function("_drawRRect", optional_override([](SkCanvas &self, WASMPointerF32 fPtr, const SkPaint &paint) - { self.drawRRect(ptrToSkRRect(fPtr), paint); })) - .function("_drawRect", optional_override([](SkCanvas &self, WASMPointerF32 fPtr, - const SkPaint &paint) -> void - { - const SkRect* rect = reinterpret_cast(fPtr); - self.drawRect(*rect, paint); })) - .function("_drawRect4f", optional_override([](SkCanvas &self, SkScalar left, SkScalar top, - SkScalar right, SkScalar bottom, - const SkPaint &paint) -> void - { - const SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - self.drawRect(rect, paint); })) - .function("_drawShadow", optional_override([](SkCanvas &self, const SkPath &path, - WASMPointerF32 zPlaneParamPtr, - WASMPointerF32 lightPosPtr, - SkScalar lightRadius, - WASMPointerF32 ambientColorPtr, - WASMPointerF32 spotColorPtr, - uint32_t flags) - { - const SkVector3* zPlaneParams = reinterpret_cast(zPlaneParamPtr); - const SkVector3* lightPos = reinterpret_cast(lightPosPtr); - - SkShadowUtils::DrawShadow(&self, path, *zPlaneParams, *lightPos, lightRadius, - ptrToSkColor4f(ambientColorPtr).toSkColor(), - ptrToSkColor4f(spotColorPtr).toSkColor(), - flags); })) -#ifndef CK_NO_FONTS - .function("_drawSimpleText", optional_override([](SkCanvas &self, WASMPointerU8 sptr, - size_t len, SkScalar x, SkScalar y, const SkFont &font, - const SkPaint &paint) - { - const char* str = reinterpret_cast(sptr); - - self.drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint); })) - .function("_drawTextBlob", select_overload &, SkScalar, SkScalar, const SkPaint &)>(&SkCanvas::drawTextBlob)) -#endif - .function("_drawVertices", select_overload &, SkBlendMode, const SkPaint &)>(&SkCanvas::drawVertices)) - - .function("_getDeviceClipBounds", optional_override([](const SkCanvas &self, WASMPointerI32 iPtr) - { - SkIRect* outputRect = reinterpret_cast(iPtr); - if (!outputRect) { - return; // output pointer cannot be null - } - self.getDeviceClipBounds(outputRect); })) - // 4x4 matrix functions - // Just like with getTotalMatrix, we allocate the buffer for the 16 floats to go in from - // interface.js, so it can also free them when its done. - .function("_getLocalToDevice", optional_override([](const SkCanvas &self, WASMPointerF32 mPtr) - { - SkScalar* sixteenMatrixValues = reinterpret_cast(mPtr); - if (!sixteenMatrixValues) { - return; // matrix cannot be null - } - SkM44 m = self.getLocalToDevice(); - m.getRowMajor(sixteenMatrixValues); })) - .function("getSaveCount", &SkCanvas::getSaveCount) - // We allocate room for the matrix from the JS side and free it there so as to not have - // an awkward moment where we malloc something here and "just know" to free it on the - // JS side. - .function("_getTotalMatrix", optional_override([](const SkCanvas &self, WASMPointerU8 mPtr) - { - SkScalar* nineMatrixValues = reinterpret_cast(mPtr); - if (!nineMatrixValues) { - return; // matrix cannot be null - } - SkMatrix m = self.getTotalMatrix(); - m.get9(nineMatrixValues); })) - .function("_makeSurface", optional_override([](SkCanvas &self, SimpleImageInfo sii) -> sk_sp - { return self.makeSurface(toSkImageInfo(sii), nullptr); }), - allow_raw_pointers()) - - .function("_readPixels", optional_override([](SkCanvas &self, SimpleImageInfo di, WASMPointerU8 pPtr, size_t dstRowBytes, int srcX, int srcY) - { - uint8_t* pixels = reinterpret_cast(pPtr); - SkImageInfo dstInfo = toSkImageInfo(di); - - return self.readPixels(dstInfo, pixels, dstRowBytes, srcX, srcY); }), - allow_raw_pointers()) - .function("restore", &SkCanvas::restore) - .function("restoreToCount", &SkCanvas::restoreToCount) - .function("rotate", select_overload(&SkCanvas::rotate)) - .function("save", &SkCanvas::save) - .function("_saveLayer", optional_override([](SkCanvas &self, const SkPaint *p, WASMPointerF32 fPtr, const SkImageFilter *backdrop, SkCanvas::SaveLayerFlags flags) -> int - { - SkRect* bounds = reinterpret_cast(fPtr); - return self.saveLayer(SkCanvas::SaveLayerRec(bounds, p, backdrop, flags)); }), - allow_raw_pointers()) - .function("saveLayerPaint", optional_override([](SkCanvas &self, const SkPaint p) -> int - { return self.saveLayer(SkCanvas::SaveLayerRec(nullptr, &p, 0)); })) - .function("scale", &SkCanvas::scale) - .function("skew", &SkCanvas::skew) - .function("translate", &SkCanvas::translate) - .function("_writePixels", optional_override([](SkCanvas &self, SimpleImageInfo di, - WASMPointerU8 pPtr, - size_t srcRowBytes, int dstX, int dstY) - { - uint8_t* pixels = reinterpret_cast(pPtr); - SkImageInfo dstInfo = toSkImageInfo(di); - - return self.writePixels(dstInfo, pixels, srcRowBytes, dstX, dstY); })); - - class_("ColorFilter") - .smart_ptr>("sk_sp>") - .class_function("_MakeBlend", optional_override([](WASMPointerF32 cPtr, SkBlendMode mode, - sk_sp colorSpace) -> sk_sp - { return SkColorFilters::Blend(ptrToSkColor4f(cPtr), colorSpace, mode); })) - .class_function("MakeCompose", &SkColorFilters::Compose) - .class_function("MakeLerp", &SkColorFilters::Lerp) - .class_function("MakeLinearToSRGBGamma", &SkColorFilters::LinearToSRGBGamma) - .class_function("_makeMatrix", optional_override([](WASMPointerF32 fPtr) - { - float* twentyFloats = reinterpret_cast(fPtr); - return SkColorFilters::Matrix(twentyFloats); })) - .class_function("MakeSRGBToLinearGamma", &SkColorFilters::SRGBToLinearGamma) - .class_function("MakeLuma", &SkLumaColorFilter::Make); - - class_("ContourMeasureIter") - .constructor() - .function("next", &SkContourMeasureIter::next); - - class_("ContourMeasure") - .smart_ptr>("sk_sp>") - .function("_getPosTan", optional_override([](SkContourMeasure &self, - SkScalar distance, - WASMPointerF32 oPtr) -> void - { - SkPoint* pointAndVector = reinterpret_cast(oPtr); - if (!self.getPosTan(distance, pointAndVector, pointAndVector + 1)) { - SkDebugf("zero-length path in getPosTan\n"); - } })) - .function("getSegment", optional_override([](SkContourMeasure &self, SkScalar startD, - SkScalar stopD, bool startWithMoveTo) -> SkPath - { - SkPath p; - bool ok = self.getSegment(startD, stopD, &p, startWithMoveTo); - if (ok) { - return p; - } - return SkPath(); })) - .function("isClosed", &SkContourMeasure::isClosed) - .function("length", &SkContourMeasure::length); - -#ifndef CK_NO_FONTS - class_("Font") - .constructor<>() - .constructor>() - .constructor, SkScalar>() - .constructor, SkScalar, SkScalar, SkScalar>() - .function("_getGlyphWidthBounds", optional_override([](SkFont &self, WASMPointerU16 gPtr, int numGlyphs, WASMPointerF32 wPtr, WASMPointerF32 rPtr, SkPaint *paint) - { - const SkGlyphID* glyphs = reinterpret_cast(gPtr); - // On the JS side only one of these is set at a time for easier ergonomics. - SkRect* outputRects = reinterpret_cast(rPtr); - SkScalar* outputWidths = reinterpret_cast(wPtr); - self.getWidthsBounds(glyphs, numGlyphs, outputWidths, outputRects, paint); }), - allow_raw_pointers()) - .function("_getGlyphIDs", optional_override([](SkFont &self, WASMPointerU8 sptr, - size_t strLen, size_t expectedCodePoints, - WASMPointerU16 iPtr) -> int - { - char* str = reinterpret_cast(sptr); - SkGlyphID* glyphIDs = reinterpret_cast(iPtr); - - int actualCodePoints = self.textToGlyphs(str, strLen, SkTextEncoding::kUTF8, - glyphIDs, expectedCodePoints); - return actualCodePoints; })) - .function("getMetrics", optional_override([](SkFont &self) -> JSObject - { - SkFontMetrics fm; - self.getMetrics(&fm); - - JSObject j = emscripten::val::object(); - j.set("ascent", fm.fAscent); - j.set("descent", fm.fDescent); - j.set("leading", fm.fLeading); - if (!(fm.fFlags & SkFontMetrics::kBoundsInvalid_Flag)) { - const float rect[] = { - fm.fXMin, fm.fTop, fm.fXMax, fm.fBottom - }; - j.set("bounds", MakeTypedArray(4, rect)); - } - return j; })) - .function("_getGlyphIntercepts", optional_override([](SkFont &self, WASMPointerU16 gPtr, size_t numGlyphs, bool ownGlyphs, WASMPointerF32 pPtr, size_t numPos, bool ownPos, float top, float bottom) -> Float32Array - { - JSSpan glyphs(gPtr, numGlyphs, ownGlyphs); - JSSpan pos (pPtr, numPos, ownPos); - if (glyphs.size() > (pos.size() >> 1)) { - return emscripten::val("Not enough x,y position pairs for glyphs"); - } - auto sects = self.getIntercepts(glyphs.data(), SkToInt(glyphs.size()), - (const SkPoint*)pos.data(), top, bottom); - return MakeTypedArray(sects.size(), (const float*)sects.data()); }), - allow_raw_pointers()) - .function("getScaleX", &SkFont::getScaleX) - .function("getSize", &SkFont::getSize) - .function("getSkewX", &SkFont::getSkewX) - .function("isEmbolden", &SkFont::isEmbolden) - .function("getTypeface", &SkFont::getTypeface, allow_raw_pointers()) - .function("setEdging", &SkFont::setEdging) - .function("setEmbeddedBitmaps", &SkFont::setEmbeddedBitmaps) - .function("setHinting", &SkFont::setHinting) - .function("setLinearMetrics", &SkFont::setLinearMetrics) - .function("setScaleX", &SkFont::setScaleX) - .function("setSize", &SkFont::setSize) - .function("setSkewX", &SkFont::setSkewX) - .function("setEmbolden", &SkFont::setEmbolden) - .function("setSubpixel", &SkFont::setSubpixel) - .function("setTypeface", &SkFont::setTypeface, allow_raw_pointers()); - - class_("FontMgr") - .smart_ptr>("sk_sp") - .class_function("_fromData", optional_override([](WASMPointerU32 dPtr, WASMPointerU32 sPtr, int numFonts) -> sk_sp - { - auto datas = reinterpret_cast(dPtr); - auto sizes = reinterpret_cast(sPtr); - - std::unique_ptr[]> skdatas(new sk_sp[numFonts]); - for (int i = 0; i < numFonts; ++i) { - skdatas[i] = SkData::MakeFromMalloc(datas[i], sizes[i]); - } - - return SkFontMgr_New_Custom_Data(SkSpan(skdatas.get(), numFonts)); }), - allow_raw_pointers()) - .function("countFamilies", &SkFontMgr::countFamilies) - .function("getFamilyName", optional_override([](SkFontMgr &self, int index) -> JSString - { - if (index < 0 || index >= self.countFamilies()) { - return emscripten::val::null(); - } - SkString s; - self.getFamilyName(index, &s); - return emscripten::val(s.c_str()); })) - .function("matchFamilyStyle", optional_override([](SkFontMgr &self, std::string name, emscripten::val jsFontStyle) -> sk_sp - { - auto weight = SkFontStyle::Weight(jsFontStyle["weight"].isUndefined() ? SkFontStyle::kNormal_Weight : jsFontStyle["weight"].as()); - auto width = SkFontStyle::Width(jsFontStyle["width"].isUndefined() ? SkFontStyle::kNormal_Width : jsFontStyle["width"].as()); - auto slant = SkFontStyle::Slant(jsFontStyle["slant"].isUndefined() ? SkFontStyle::kUpright_Slant : static_cast(jsFontStyle["slant"].as())); - - SkFontStyle style(weight, width, slant); - - return self.matchFamilyStyle(name.c_str(), style); }), - allow_raw_pointers()) -#ifdef SK_DEBUG - .function("dumpFamilies", optional_override([](SkFontMgr &self) - { - int numFam = self.countFamilies(); - SkDebugf("There are %d font families\n", numFam); - for (int i = 0 ; i< numFam; i++) { - SkString s; - self.getFamilyName(i, &s); - SkDebugf("\t%s\n", s.c_str()); - } })) -#endif - .function("_makeTypefaceFromData", optional_override([](SkFontMgr &self, WASMPointerU8 fPtr, int flen) -> sk_sp - { - uint8_t* font = reinterpret_cast(fPtr); - sk_sp fontData = SkData::MakeFromMalloc(font, flen); - - return self.makeFromData(fontData); }), - allow_raw_pointers()); -#endif // CK_NO_FONTS - - class_("Image") - .smart_ptr>("sk_sp") -#ifdef CK_ENABLE_WEBGL - .class_function("_makeFromGenerator", &MakeImageFromGenerator) -#endif - // Note that this needs to be cleaned up with delete(). - .function("getColorSpace", optional_override([](sk_sp self) -> sk_sp - { return self->imageInfo().refColorSpace(); }), - allow_raw_pointers()) - .function("getImageInfo", optional_override([](sk_sp self) -> JSObject - { - // We cannot return a SimpleImageInfo because the colorspace object would be leaked. - JSObject result = emscripten::val::object(); - SkImageInfo ii = self->imageInfo(); - result.set("alphaType", ii.alphaType()); - result.set("colorType", ii.colorType()); - result.set("height", ii.height()); - result.set("width", ii.width()); - return result; })) - .function("height", &SkImage::height) - .function("_encodeToBytes", optional_override([](sk_sp self, - SkEncodedImageFormat fmt, - int quality) -> Uint8Array - { return encodeImage(nullptr, self, fmt, quality); })) -#if defined(ENABLE_GPU) - .function("_encodeToBytes", optional_override([](sk_sp self, SkEncodedImageFormat fmt, int quality, GrDirectContext *dContext) -> Uint8Array - { return encodeImage(dContext, self, fmt, quality); }), - allow_raw_pointers()) -#endif - .function("makeCopyWithDefaultMipmaps", optional_override([](sk_sp self) -> sk_sp - { return self->withDefaultMipmaps(); })) - .function("_makeShaderCubic", optional_override([](sk_sp self, SkTileMode tx, SkTileMode ty, float B, float C, // See SkSamplingOptions.h for docs. - WASMPointerF32 mPtr) -> sk_sp - { return self->makeShader(tx, ty, SkSamplingOptions({B, C}), OptionalMatrix(mPtr)); }), - allow_raw_pointers()) - .function("_makeShaderOptions", optional_override([](sk_sp self, SkTileMode tx, SkTileMode ty, SkFilterMode filter, SkMipmapMode mipmap, WASMPointerF32 mPtr) -> sk_sp - { return self->makeShader(tx, ty, {filter, mipmap}, OptionalMatrix(mPtr)); }), - allow_raw_pointers()) -#if defined(ENABLE_GPU) - .function("_readPixels", optional_override([](sk_sp self, SimpleImageInfo sii, WASMPointerU8 pPtr, size_t dstRowBytes, int srcX, int srcY, GrDirectContext *dContext) -> bool - { - uint8_t* pixels = reinterpret_cast(pPtr); - SkImageInfo ii = toSkImageInfo(sii); - return self->readPixels(dContext, ii, pixels, dstRowBytes, srcX, srcY); }), - allow_raw_pointers()) -#endif - .function("_readPixels", optional_override([](sk_sp self, SimpleImageInfo sii, WASMPointerU8 pPtr, size_t dstRowBytes, int srcX, int srcY) -> bool - { - uint8_t* pixels = reinterpret_cast(pPtr); - SkImageInfo ii = toSkImageInfo(sii); - return self->readPixels(nullptr, ii, pixels, dstRowBytes, srcX, srcY); }), - allow_raw_pointers()) - .function("width", &SkImage::width); - - class_("ImageFilter") - .smart_ptr>("sk_sp") - .function("_getOutputBounds", optional_override([](const SkImageFilter &self, WASMPointerF32 bPtr, WASMPointerF32 mPtr, WASMPointerU32 oPtr) -> void - { - SkRect* rect = reinterpret_cast(bPtr); - OptionalMatrix ctm(mPtr); - SkIRect* output = reinterpret_cast(oPtr); - output[0] = self.filterBounds(ctm.mapRect(*rect).roundOut(), ctm, SkImageFilter::kForward_MapDirection); })) - .class_function("MakeBlend", optional_override([](SkBlendMode mode, sk_sp background, - sk_sp foreground) -> sk_sp - { return SkImageFilters::Blend(mode, background, foreground); })) - .class_function("MakeBlur", optional_override([](SkScalar sigmaX, SkScalar sigmaY, - SkTileMode tileMode, sk_sp input) -> sk_sp - { return SkImageFilters::Blur(sigmaX, sigmaY, tileMode, input); })) - .class_function("MakeColorFilter", optional_override([](sk_sp cf, - sk_sp input) -> sk_sp - { return SkImageFilters::ColorFilter(cf, input); })) - .class_function("MakeCompose", &SkImageFilters::Compose) - .class_function("MakeDilate", optional_override([](SkScalar radiusX, SkScalar radiusY, - sk_sp input) -> sk_sp - { return SkImageFilters::Dilate(radiusX, radiusY, input); })) - .class_function("MakeDisplacementMap", optional_override([](SkColorChannel xChannelSelector, - SkColorChannel yChannelSelector, - SkScalar scale, sk_sp displacement, - sk_sp color) -> sk_sp - { return SkImageFilters::DisplacementMap(xChannelSelector, yChannelSelector, - scale, displacement, color); })) - .class_function("MakeShader", optional_override([](sk_sp shader) -> sk_sp - { return SkImageFilters::Shader(shader); })) - .class_function("_MakeDropShadow", optional_override([](SkScalar dx, SkScalar dy, - SkScalar sigmaX, SkScalar sigmaY, - WASMPointerF32 cPtr, sk_sp input) -> sk_sp - { - SkColor4f c = ptrToSkColor4f(cPtr); - return SkImageFilters::DropShadow(dx, dy, sigmaX, sigmaY, c.toSkColor(), input); })) - .class_function("_MakeDropShadowOnly", optional_override([](SkScalar dx, SkScalar dy, - SkScalar sigmaX, SkScalar sigmaY, - WASMPointerF32 cPtr, sk_sp input) -> sk_sp - { - SkColor4f c = ptrToSkColor4f(cPtr); - return SkImageFilters::DropShadowOnly(dx, dy, sigmaX, sigmaY, c.toSkColor(), input); })) - .class_function("MakeErode", optional_override([](SkScalar radiusX, SkScalar radiusY, - sk_sp input) -> sk_sp - { return SkImageFilters::Erode(radiusX, radiusY, input); })) - .class_function("_MakeImageCubic", optional_override([](sk_sp image, - float B, float C, - WASMPointerF32 srcPtr, - WASMPointerF32 dstPtr) -> sk_sp - { - const SkRect* src = reinterpret_cast(srcPtr); - const SkRect* dst = reinterpret_cast(dstPtr); - if (src && dst) { - return SkImageFilters::Image(image, *src, *dst, SkSamplingOptions({B, C})); - } - return SkImageFilters::Image(image, SkSamplingOptions({B, C})); })) - .class_function("_MakeImageOptions", optional_override([](sk_sp image, - SkFilterMode fm, - SkMipmapMode mm, - WASMPointerF32 srcPtr, - WASMPointerF32 dstPtr) -> sk_sp - { - const SkRect* src = reinterpret_cast(srcPtr); - const SkRect* dst = reinterpret_cast(dstPtr); - if (src && dst) { - return SkImageFilters::Image(image, *src, *dst, SkSamplingOptions(fm, mm)); - } - return SkImageFilters::Image(image, SkSamplingOptions(fm, mm)); })) - .class_function("_MakeMatrixTransformCubic", - optional_override([](WASMPointerF32 mPtr, float B, float C, - sk_sp input) -> sk_sp - { - OptionalMatrix matr(mPtr); - return SkImageFilters::MatrixTransform(matr, SkSamplingOptions({B, C}), input); })) - .class_function("_MakeMatrixTransformOptions", - optional_override([](WASMPointerF32 mPtr, SkFilterMode fm, SkMipmapMode mm, - sk_sp input) -> sk_sp - { - OptionalMatrix matr(mPtr); - return SkImageFilters::MatrixTransform(matr, SkSamplingOptions(fm, mm), input); })) - .class_function("MakeOffset", optional_override([](SkScalar dx, SkScalar dy, - sk_sp input) -> sk_sp - { return SkImageFilters::Offset(dx, dy, input); })); - - class_("MaskFilter") - .smart_ptr>("sk_sp") - .class_function("MakeBlur", optional_override([](SkBlurStyle style, SkScalar sigma, bool respectCTM) -> sk_sp - { - // Adds a little helper because emscripten doesn't expose default params. - return SkMaskFilter::MakeBlur(style, sigma, respectCTM); }), - allow_raw_pointers()); - - class_("Paint") - .constructor<>() - .function("copy", optional_override([](const SkPaint &self) -> SkPaint - { - SkPaint p(self); - return p; })) - // provide an allocated place to put the returned color - .function("_getColor", optional_override([](SkPaint &self, WASMPointerF32 cPtr) -> void - { - const SkColor4f& c = self.getColor4f(); - float* fourFloats = reinterpret_cast(cPtr); - memcpy(fourFloats, c.vec(), 4 * sizeof(SkScalar)); })) - .function("getStrokeCap", &SkPaint::getStrokeCap) - .function("getStrokeJoin", &SkPaint::getStrokeJoin) - .function("getStrokeMiter", &SkPaint::getStrokeMiter) - .function("getStrokeWidth", &SkPaint::getStrokeWidth) - .function("setAntiAlias", &SkPaint::setAntiAlias) - .function("setAlphaf", &SkPaint::setAlphaf) - .function("setBlendMode", &SkPaint::setBlendMode) - .function("setBlender", &SkPaint::setBlender) - .function("_setColor", optional_override([](SkPaint &self, WASMPointerF32 cPtr, - sk_sp colorSpace) - { self.setColor(ptrToSkColor4f(cPtr), colorSpace.get()); })) - .function("setColorInt", optional_override([](SkPaint &self, SkColor color) - { self.setColor(SkColor4f::FromColor(color), nullptr); })) - .function("setColorInt", optional_override([](SkPaint &self, SkColor color, - sk_sp colorSpace) - { self.setColor(SkColor4f::FromColor(color), colorSpace.get()); })) - .function("setColorFilter", &SkPaint::setColorFilter) - .function("setDither", &SkPaint::setDither) - .function("setImageFilter", &SkPaint::setImageFilter) - .function("setMaskFilter", &SkPaint::setMaskFilter) - .function("setPathEffect", &SkPaint::setPathEffect) - .function("setShader", &SkPaint::setShader) - .function("setStrokeCap", &SkPaint::setStrokeCap) - .function("setStrokeJoin", &SkPaint::setStrokeJoin) - .function("setStrokeMiter", &SkPaint::setStrokeMiter) - .function("setStrokeWidth", &SkPaint::setStrokeWidth) - .function("setStyle", &SkPaint::setStyle); - - class_("ColorSpace") - .smart_ptr>("sk_sp") - .class_function("Equals", optional_override([](sk_sp a, sk_sp b) -> bool - { return SkColorSpace::Equals(a.get(), b.get()); })) - // These are private because they are to be called once in interface.js to - // avoid clients having to delete the returned objects. - .class_function("_MakeSRGB", &SkColorSpace::MakeSRGB) - .class_function("_MakeDisplayP3", optional_override([]() -> sk_sp - { return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3); })) - .class_function("_MakeAdobeRGB", optional_override([]() -> sk_sp - { return SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB); })); - - class_("PathEffect") - .smart_ptr>("sk_sp") - .class_function("MakeCorner", &SkCornerPathEffect::Make) - .class_function("_MakeDash", optional_override([](WASMPointerF32 cptr, int count, SkScalar phase) -> sk_sp - { - const float* intervals = reinterpret_cast(cptr); - return SkDashPathEffect::Make(intervals, count, phase); }), - allow_raw_pointers()) - .class_function("MakeDiscrete", &SkDiscretePathEffect::Make) - .class_function("_MakeLine2D", optional_override([](SkScalar width, WASMPointerF32 mPtr) -> sk_sp - { - SkMatrix matrix; - const SkScalar* nineMatrixValues = reinterpret_cast(mPtr); - matrix.set9(nineMatrixValues); - return SkLine2DPathEffect::Make(width, matrix); }), - allow_raw_pointers()) - .class_function("MakePath1D", &SkPath1DPathEffect::Make) - .class_function("_MakePath2D", optional_override([](WASMPointerF32 mPtr, SkPath path) -> sk_sp - { - SkMatrix matrix; - const SkScalar* nineMatrixValues = reinterpret_cast(mPtr); - matrix.set9(nineMatrixValues); - return SkPath2DPathEffect::Make(matrix, path); }), - allow_raw_pointers()); - - // TODO(kjlubick, reed) Make SkPath immutable and only creatable via a factory/builder. - class_("Path") - .constructor<>() -#ifdef CK_INCLUDE_PATHOPS - .class_function("MakeFromOp", &MakePathFromOp) -#endif - .class_function("MakeFromSVGString", &MakePathFromSVGString) - .class_function("MakeFromPathInterpolation", &MakePathFromInterpolation) - .class_function("CanInterpolate", &CanInterpolate) - .class_function("_MakeFromCmds", &MakePathFromCmds) - .class_function("_MakeFromVerbsPointsWeights", &MakePathFromVerbsPointsWeights) - .function("_addArc", optional_override([](SkPath &self, - WASMPointerF32 fPtr, - SkScalar startAngle, SkScalar sweepAngle) -> void - { - const SkRect* oval = reinterpret_cast(fPtr); - self.addArc(*oval, startAngle, sweepAngle); })) - .function("_addOval", optional_override([](SkPath &self, - WASMPointerF32 fPtr, - bool ccw, unsigned start) -> void - { - const SkRect* oval = reinterpret_cast(fPtr); - self.addOval(*oval, ccw ? SkPathDirection::kCCW : SkPathDirection::kCW, start); })) - .function("_addCircle", optional_override([](SkPath &self, - SkScalar x, - SkScalar y, - SkScalar r, - bool ccw) -> void - { self.addCircle(x, y, r, ccw ? SkPathDirection::kCCW : SkPathDirection::kCW); })) - // interface.js has 3 overloads of addPath - .function("_addPath", &ApplyAddPath) - .function("_addPoly", optional_override([](SkPath &self, - WASMPointerF32 fPtr, - int count, bool close) -> void - { - const SkPoint* pts = reinterpret_cast(fPtr); - self.addPoly(pts, count, close); })) - .function("_addRect", optional_override([](SkPath &self, - WASMPointerF32 fPtr, - bool ccw) -> void - { - const SkRect* rect = reinterpret_cast(fPtr); - self.addRect(*rect, ccw ? SkPathDirection::kCCW : SkPathDirection::kCW); })) - .function("_addRRect", optional_override([](SkPath &self, - WASMPointerF32 fPtr, - bool ccw) -> void - { self.addRRect(ptrToSkRRect(fPtr), ccw ? SkPathDirection::kCCW : SkPathDirection::kCW); })) - .function("_addVerbsPointsWeights", &PathAddVerbsPointsWeights) - .function("_arcToOval", optional_override([](SkPath &self, - WASMPointerF32 fPtr, SkScalar startAngle, - SkScalar sweepAngle, bool forceMoveTo) -> void - { - const SkRect* oval = reinterpret_cast(fPtr); - self.arcTo(*oval, startAngle, sweepAngle, forceMoveTo); })) - .function("_arcToRotated", &ApplyArcToArcSize) - .function("_arcToTangent", ApplyArcToTangent) - .function("_close", &ApplyClose) - .function("_conicTo", &ApplyConicTo) - .function("countPoints", &SkPath::countPoints) - .function("contains", &SkPath::contains) - .function("_cubicTo", &ApplyCubicTo) - .function("_getPoint", optional_override([](SkPath &self, int index, - WASMPointerF32 oPtr) -> void - { - SkPoint* output = reinterpret_cast(oPtr); - *output = self.getPoint(index); })) - .function("isEmpty", &SkPath::isEmpty) - .function("isVolatile", &SkPath::isVolatile) - .function("_lineTo", &ApplyLineTo) - .function("_moveTo", &ApplyMoveTo) - .function("_quadTo", &ApplyQuadTo) - .function("_rArcTo", &ApplyRArcToArcSize) - .function("_rConicTo", &ApplyRConicTo) - .function("_rCubicTo", &ApplyRCubicTo) - .function("_rLineTo", &ApplyRLineTo) - .function("_rMoveTo", &ApplyRMoveTo) - .function("_rQuadTo", &ApplyRQuadTo) - .function("reset", &ApplyReset) - .function("rewind", &ApplyRewind) - .function("setIsVolatile", &SkPath::setIsVolatile) - .function("_transform", select_overload(&ApplyTransform)) - - // PathEffects - .function("_dash", &ApplyDash) - .function("_trim", &ApplyTrim) - .function("_stroke", &ApplyStroke) - -#ifdef CK_INCLUDE_PATHOPS - // PathOps - .function("_simplify", &ApplySimplify) - .function("_op", &ApplyPathOp) - .function("makeAsWinding", &MakeAsWinding) -#endif - // Exporting - .function("toSVGString", &ToSVGString) - .function("toCmds", &ToCmds) - - .function("setFillType", select_overload(&SkPath::setFillType)) - .function("getFillType", &SkPath::getFillType) - .function("_getBounds", optional_override([](SkPath &self, - WASMPointerF32 fPtr) -> void - { - SkRect* output = reinterpret_cast(fPtr); - output[0] = self.getBounds(); })) - .function("_computeTightBounds", optional_override([](SkPath &self, - WASMPointerF32 fPtr) -> void - { - SkRect* output = reinterpret_cast(fPtr); - output[0] = self.computeTightBounds(); })) - .function("equals", &Equals) - .function("copy", &CopyPath) -#ifdef SK_DEBUG - .function("dump", select_overload(&SkPath::dump)) - .function("dumpHex", select_overload(&SkPath::dumpHex)) -#endif - ; - - static SkRTreeFactory bbhFactory; - class_("PictureRecorder") - .constructor<>() - .function("_beginRecording", optional_override([](SkPictureRecorder &self, WASMPointerF32 fPtr, bool computeBounds) -> SkCanvas * - { - SkRect* bounds = reinterpret_cast(fPtr); - return self.beginRecording(*bounds, computeBounds ? &bbhFactory : nullptr); }), - allow_raw_pointers()) - .function("finishRecordingAsPicture", optional_override([](SkPictureRecorder &self) -> sk_sp - { return self.finishRecordingAsPicture(); }), - allow_raw_pointers()); - - class_("Picture") - .smart_ptr>("sk_sp") - .function("_makeShader", optional_override([](SkPicture &self, SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, WASMPointerF32 mPtr, WASMPointerF32 rPtr) -> sk_sp - { - OptionalMatrix localMatrix(mPtr); - SkRect* tileRect = reinterpret_cast(rPtr); - return self.makeShader(tmx, tmy, mode, &localMatrix, tileRect); }), - allow_raw_pointers()) - .function("_cullRect", optional_override([](SkPicture &self, - WASMPointerF32 fPtr) -> void - { - SkRect* output = reinterpret_cast(fPtr); - output[0] = self.cullRect(); })) - .function("approximateBytesUsed", &SkPicture::approximateBytesUsed) -#ifdef CK_SERIALIZE_SKP - // The serialized format of an SkPicture (informally called an "skp"), is not something - // that clients should ever rely on. The format may change at anytime and no promises - // are made for backwards or forward compatibility. - .function("serialize", optional_override([](SkPicture &self) -> Uint8Array - { - // We want to make sure we always save the underlying data of the Typeface to the - // SkPicture. By default, the data for "system" fonts is not saved, just an identifier - // (e.g. the family name and style). We do not want the user to have to supply a - // FontMgr with the correct fonts by name when deserializing, so we choose to always - // serialize the underlying data. This makes the SKPs a bit bigger, but easier to use. - SkSerialProcs sp; - sp.fTypefaceProc = &alwaysSaveTypefaceBytes; - - sk_sp data = self.serialize(&sp); - if (!data) { - return emscripten::val::null(); - } - return toBytes(data); }), - allow_raw_pointers()) -#endif - ; - - class_("Shader") - .smart_ptr>("sk_sp") - .class_function("MakeBlend", select_overload(SkBlendMode, sk_sp, sk_sp)>(&SkShaders::Blend)) - .class_function("_MakeColor", - optional_override([](WASMPointerF32 cPtr, sk_sp colorSpace) -> sk_sp - { return SkShaders::Color(ptrToSkColor4f(cPtr), colorSpace); })) - .class_function("MakeFractalNoise", optional_override([]( - SkScalar baseFreqX, SkScalar baseFreqY, - int numOctaves, SkScalar seed, - int tileW, int tileH) -> sk_sp - { - // if tileSize is empty (e.g. tileW <= 0 or tileH <= 0, it will be ignored. - SkISize tileSize = SkISize::Make(tileW, tileH); - return SkShaders::MakeFractalNoise(baseFreqX, baseFreqY, numOctaves, seed, &tileSize); })) - // Here and in other gradient functions, cPtr is a pointer to an array of data - // representing colors. whether this is an array of SkColor or SkColor4f is indicated - // by the colorType argument. Only RGBA_8888 and RGBA_F32 are accepted. - .class_function("_MakeLinearGradient", optional_override([](WASMPointerF32 fourFloatsPtr, WASMPointerF32 cPtr, SkColorType colorType, WASMPointerF32 pPtr, int count, SkTileMode mode, uint32_t flags, WASMPointerF32 mPtr, sk_sp colorSpace) -> sk_sp - { - const SkPoint* points = reinterpret_cast(fourFloatsPtr); - const SkScalar* positions = reinterpret_cast(pPtr); - OptionalMatrix localMatrix(mPtr); - - if (colorType == SkColorType::kRGBA_F32_SkColorType) { - const SkColor4f* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeLinear(points, colors, colorSpace, positions, count, - mode, flags, &localMatrix); - } else if (colorType == SkColorType::kRGBA_8888_SkColorType) { - const SkColor* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeLinear(points, colors, positions, count, - mode, flags, &localMatrix); - } - SkDebugf("%d is not an accepted colorType\n", colorType); - return nullptr; }), - allow_raw_pointers()) - .class_function("_MakeRadialGradient", optional_override([](SkScalar cx, SkScalar cy, SkScalar radius, WASMPointerF32 cPtr, SkColorType colorType, WASMPointerF32 pPtr, int count, SkTileMode mode, uint32_t flags, WASMPointerF32 mPtr, sk_sp colorSpace) -> sk_sp - { - const SkScalar* positions = reinterpret_cast(pPtr); - OptionalMatrix localMatrix(mPtr); - if (colorType == SkColorType::kRGBA_F32_SkColorType) { - const SkColor4f* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeRadial({cx, cy}, radius, colors, colorSpace, - positions, count, mode, flags, &localMatrix); - } else if (colorType == SkColorType::kRGBA_8888_SkColorType) { - const SkColor* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeRadial({cx, cy}, radius, colors, positions, - count, mode, flags, &localMatrix); - } - SkDebugf("%d is not an accepted colorType\n", colorType); - return nullptr; }), - allow_raw_pointers()) - .class_function("_MakeSweepGradient", optional_override([](SkScalar cx, SkScalar cy, WASMPointerF32 cPtr, SkColorType colorType, WASMPointerF32 pPtr, int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, WASMPointerF32 mPtr, sk_sp colorSpace) -> sk_sp - { - const SkScalar* positions = reinterpret_cast(pPtr); - OptionalMatrix localMatrix(mPtr); - if (colorType == SkColorType::kRGBA_F32_SkColorType) { - const SkColor4f* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeSweep(cx, cy, colors, colorSpace, positions, count, - mode, startAngle, endAngle, flags, - &localMatrix); - } else if (colorType == SkColorType::kRGBA_8888_SkColorType) { - const SkColor* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeSweep(cx, cy, colors, positions, count, - mode, startAngle, endAngle, flags, - &localMatrix); - } - SkDebugf("%d is not an accepted colorType\n", colorType); - return nullptr; }), - allow_raw_pointers()) - .class_function("MakeTurbulence", optional_override([]( - SkScalar baseFreqX, SkScalar baseFreqY, - int numOctaves, SkScalar seed, - int tileW, int tileH) -> sk_sp - { - // if tileSize is empty (e.g. tileW <= 0 or tileH <= 0, it will be ignored. - SkISize tileSize = SkISize::Make(tileW, tileH); - return SkShaders::MakeTurbulence(baseFreqX, baseFreqY, numOctaves, seed, &tileSize); })) - .class_function("_MakeTwoPointConicalGradient", optional_override([](WASMPointerF32 fourFloatsPtr, SkScalar startRadius, SkScalar endRadius, WASMPointerF32 cPtr, SkColorType colorType, WASMPointerF32 pPtr, int count, SkTileMode mode, uint32_t flags, WASMPointerF32 mPtr, sk_sp colorSpace) -> sk_sp - { - const SkPoint* startAndEnd = reinterpret_cast(fourFloatsPtr); - const SkScalar* positions = reinterpret_cast(pPtr); - OptionalMatrix localMatrix(mPtr); - - if (colorType == SkColorType::kRGBA_F32_SkColorType) { - const SkColor4f* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeTwoPointConical(startAndEnd[0], startRadius, - startAndEnd[1], endRadius, - colors, colorSpace, positions, count, mode, - flags, &localMatrix); - } else if (colorType == SkColorType::kRGBA_8888_SkColorType) { - const SkColor* colors = reinterpret_cast(cPtr); - return SkGradientShader::MakeTwoPointConical(startAndEnd[0], - startRadius, - startAndEnd[1], - endRadius, - colors, - positions, - count, - mode, - flags, - &localMatrix); - } - SkDebugf("%d is not an accepted colorType\n", colorType); - return nullptr; }), - allow_raw_pointers()); - -#ifdef CK_INCLUDE_RUNTIME_EFFECT -#ifdef SKSL_ENABLE_TRACING - class_("DebugTrace") - .smart_ptr>("sk_sp") - .function("writeTrace", optional_override([](SkSL::DebugTrace &self) -> std::string - { - SkDynamicMemoryWStream wstream; - self.writeTrace(&wstream); - sk_sp trace = wstream.detachAsData(); - return std::string(reinterpret_cast(trace->bytes()), trace->size()); })); - - value_object("TracedShader") - .field("shader", &SkRuntimeEffect::TracedShader::shader) - .field("debugTrace", &SkRuntimeEffect::TracedShader::debugTrace); -#endif - - class_("RuntimeEffect") - .smart_ptr>("sk_sp") - .class_function("_Make", optional_override([](std::string sksl, - emscripten::val errHandler) -> sk_sp - { - SkString s(sksl.c_str(), sksl.length()); - auto [effect, errorText] = SkRuntimeEffect::MakeForShader(s); - if (!effect) { - errHandler.call("onError", val(errorText.c_str())); - return nullptr; - } - return effect; })) - .class_function("_MakeForBlender", optional_override([](std::string sksl, - emscripten::val errHandler) -> sk_sp - { - SkString s(sksl.c_str(), sksl.length()); - auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(s); - if (!effect) { - errHandler.call("onError", val(errorText.c_str())); - return nullptr; - } - return effect; })) -#ifdef SKSL_ENABLE_TRACING - .class_function("MakeTraced", optional_override([]( - sk_sp shader, - int traceCoordX, - int traceCoordY) -> SkRuntimeEffect::TracedShader - { return SkRuntimeEffect::MakeTraced(shader, SkIPoint::Make(traceCoordX, traceCoordY)); })) -#endif - .function("_makeShader", optional_override([](SkRuntimeEffect &self, - WASMPointerF32 fPtr, - size_t fLen, - bool shouldOwnUniforms, - WASMPointerF32 mPtr) -> sk_sp - { - void* uniformData = reinterpret_cast(fPtr); - castUniforms(uniformData, fLen, self); - sk_sp uniforms; - if (shouldOwnUniforms) { - uniforms = SkData::MakeFromMalloc(uniformData, fLen); - } else { - uniforms = SkData::MakeWithoutCopy(uniformData, fLen); - } - - OptionalMatrix localMatrix(mPtr); - return self.makeShader(uniforms, nullptr, 0, &localMatrix); })) - .function("_makeShaderWithChildren", optional_override([](SkRuntimeEffect &self, - WASMPointerF32 fPtr, - size_t fLen, - bool shouldOwnUniforms, - WASMPointerU32 cPtrs, - size_t cLen, - WASMPointerF32 mPtr) -> sk_sp - { - void* uniformData = reinterpret_cast(fPtr); - castUniforms(uniformData, fLen, self); - sk_sp uniforms; - if (shouldOwnUniforms) { - uniforms = SkData::MakeFromMalloc(uniformData, fLen); - } else { - uniforms = SkData::MakeWithoutCopy(uniformData, fLen); - } - - sk_sp* children = new sk_sp[cLen]; - SkShader** childrenPtrs = reinterpret_cast(cPtrs); - for (size_t i = 0; i < cLen; i++) { - // This bare pointer was already part of an sk_sp (owned outside of here), - // so we want to ref the new sk_sp so makeShader doesn't clean it up. - children[i] = sk_ref_sp(childrenPtrs[i]); - } - OptionalMatrix localMatrix(mPtr); - auto s = self.makeShader(uniforms, children, cLen, &localMatrix); - delete[] children; - return s; })) - .function("_makeBlender", optional_override([](SkRuntimeEffect &self, - WASMPointerF32 fPtr, - size_t fLen, - bool shouldOwnUniforms) -> sk_sp - { - void* uniformData = reinterpret_cast(fPtr); - castUniforms(uniformData, fLen, self); - sk_sp uniforms; - if (shouldOwnUniforms) { - uniforms = SkData::MakeFromMalloc(uniformData, fLen); - } else { - uniforms = SkData::MakeWithoutCopy(uniformData, fLen); - } - - return self.makeBlender(uniforms, {}); })) - .function("getUniformCount", optional_override([](SkRuntimeEffect &self) -> int - { return self.uniforms().size(); })) - .function("getUniformFloatCount", optional_override([](SkRuntimeEffect &self) -> int - { return self.uniformSize() / sizeof(float); })) - .function("getUniformName", optional_override([](SkRuntimeEffect &self, int i) -> JSString - { - auto it = self.uniforms().begin() + i; - return emscripten::val(std::string(it->name).c_str()); })) - .function("getUniform", optional_override([](SkRuntimeEffect &self, int i) -> RuntimeEffectUniform - { - auto it = self.uniforms().begin() + i; - RuntimeEffectUniform su = fromUniform(*it); - return su; })); - - value_object("RuntimeEffectUniform") - .field("columns", &RuntimeEffectUniform::columns) - .field("rows", &RuntimeEffectUniform::rows) - .field("slot", &RuntimeEffectUniform::slot) - .field("isInteger", &RuntimeEffectUniform::isInteger); - - constant("rt_effect", true); -#endif - - class_("Surface") - .smart_ptr>("sk_sp") - .class_function("_makeRasterDirect", optional_override([](const SimpleImageInfo ii, WASMPointerU8 pPtr, size_t rowBytes) -> sk_sp - { - uint8_t* pixels = reinterpret_cast(pPtr); - SkImageInfo imageInfo = toSkImageInfo(ii); - return SkSurfaces::WrapPixels(imageInfo, pixels, rowBytes, nullptr); }), - allow_raw_pointers()) - .function("_flush", optional_override([](SkSurface &self) - { -#ifdef CK_ENABLE_WEBGL - skgpu::ganesh::FlushAndSubmit(&self); -#endif - })) - .function("_getCanvas", &SkSurface::getCanvas, allow_raw_pointers()) - .function("imageInfo", optional_override([](SkSurface &self) -> SimpleImageInfo - { - const auto& ii = self.imageInfo(); - return {ii.width(), ii.height(), ii.colorType(), ii.alphaType(), ii.refColorSpace()}; })) - .function("height", &SkSurface::height) -#ifdef CK_ENABLE_WEBGL - .function("_makeImageFromTexture", optional_override([](SkSurface &self, uint32_t webglHandle, uint32_t texHandle, SimpleImageInfo ii) -> sk_sp - { - auto releaseCtx = new TextureReleaseContext{webglHandle, texHandle}; - GrGLTextureInfo gti = {GR_GL_TEXTURE_2D, texHandle, - GR_GL_RGBA8}; // TODO(kjlubick) look at ii for this - auto gbt = GrBackendTextures::MakeGL(ii.width, ii.height, skgpu::Mipmapped::kNo, gti); - auto dContext = GrAsDirectContext(self.getCanvas()->recordingContext()); - - return SkImages::BorrowTextureFrom(dContext, - gbt, - GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, - ii.colorType, - ii.alphaType, - ii.colorSpace, - deleteJSTexture, - releaseCtx); })) -#endif // CK_ENABLE_WEBGL -#ifdef CK_ENABLE_WEBGPU - .function("_replaceBackendTexture", optional_override([](SkSurface &self, uint32_t texHandle, uint32_t texFormat, int width, int height) - { return ReplaceBackendTexture(self, texHandle, texFormat, width, height); })) -#endif // CK_ENABLE_WEBGPU - .function("_makeImageSnapshot", optional_override([](SkSurface &self, WASMPointerU32 iPtr) -> sk_sp - { - SkIRect* bounds = reinterpret_cast(iPtr); - if (!bounds) { - return self.makeImageSnapshot(); - } - return self.makeImageSnapshot(*bounds); })) - .function("_makeSurface", optional_override([](SkSurface &self, SimpleImageInfo sii) -> sk_sp - { return self.makeSurface(toSkImageInfo(sii)); }), - allow_raw_pointers()) -#ifdef ENABLE_GPU - .function("reportBackendTypeIsGPU", optional_override([](SkSurface &self) -> bool - { return self.getCanvas()->recordingContext() != nullptr; })) - .function("sampleCnt", optional_override([](SkSurface &self) -> int - { - auto backendRT = SkSurfaces::GetBackendRenderTarget( - &self, SkSurfaces::BackendHandleAccess::kFlushRead); - return (backendRT.isValid()) ? backendRT.sampleCnt() : 0; })) - .function("_resetContext", optional_override([](SkSurface &self) -> void - { GrAsDirectContext(self.recordingContext())->resetContext(kTextureBinding_GrGLBackendState); })) -#else - .function("reportBackendTypeIsGPU", optional_override([](SkSurface &self) -> bool - { return false; })) -#endif - .function("width", &SkSurface::width); - -#ifndef CK_NO_FONTS - class_("TextBlob") - .smart_ptr>("sk_sp") - .class_function("_MakeFromRSXform", optional_override([](WASMPointerU8 sptr, size_t strBtyes, WASMPointerF32 xptr, const SkFont &font) -> sk_sp - { - const char* str = reinterpret_cast(sptr); - const SkRSXform* xforms = reinterpret_cast(xptr); - - return SkTextBlob::MakeFromRSXform(str, strBtyes, xforms, font, SkTextEncoding::kUTF8); }), - allow_raw_pointers()) - .class_function("_MakeFromRSXformGlyphs", optional_override([](WASMPointerU16 gPtr, size_t byteLen, WASMPointerF32 xptr, const SkFont &font) -> sk_sp - { - const SkGlyphID* glyphs = reinterpret_cast(gPtr); - const SkRSXform* xforms = reinterpret_cast(xptr); - - return SkTextBlob::MakeFromRSXform(glyphs, byteLen, xforms, font, SkTextEncoding::kGlyphID); }), - allow_raw_pointers()) - .class_function("_MakeFromText", optional_override([](WASMPointerU8 sptr, size_t len, const SkFont &font) -> sk_sp - { - const char* str = reinterpret_cast(sptr); - return SkTextBlob::MakeFromText(str, len, font, SkTextEncoding::kUTF8); }), - allow_raw_pointers()) - .class_function("_MakeFromGlyphs", optional_override([](WASMPointerU16 gPtr, size_t byteLen, const SkFont &font) -> sk_sp - { - const SkGlyphID* glyphs = reinterpret_cast(gPtr); - return SkTextBlob::MakeFromText(glyphs, byteLen, font, SkTextEncoding::kGlyphID); }), - allow_raw_pointers()); - - class_("Typeface") - .smart_ptr>("sk_sp") - .class_function("_MakeFreeTypeFaceFromData", optional_override([](WASMPointerU8 fPtr, int flen) -> sk_sp - { - uint8_t* font = reinterpret_cast(fPtr); - sk_sp fontData = SkData::MakeFromMalloc(font, flen); - - return SkFontMgr::RefDefault()->makeFromData(fontData); }), - allow_raw_pointers()) - .function("_getGlyphIDs", optional_override([](SkTypeface &self, WASMPointerU8 sptr, - size_t strLen, size_t expectedCodePoints, - WASMPointerU16 iPtr) -> int - { - char* str = reinterpret_cast(sptr); - SkGlyphID* glyphIDs = reinterpret_cast(iPtr); - - int actualCodePoints = self.textToGlyphs(str, strLen, SkTextEncoding::kUTF8, - glyphIDs, expectedCodePoints); - return actualCodePoints; })); -#endif - - class_("Vertices") - .smart_ptr>("sk_sp") - .function("_bounds", optional_override([](SkVertices &self, - WASMPointerF32 fPtr) -> void - { - SkRect* output = reinterpret_cast(fPtr); - output[0] = self.bounds(); })) - .function("uniqueID", &SkVertices::uniqueID); - - // Not intended to be called directly by clients - class_("_VerticesBuilder") - .constructor() - .function("colors", optional_override([](SkVertices::Builder &self) -> WASMPointerF32 - { - // Emscripten won't let us return bare pointers, but we can return ints just fine. - return reinterpret_cast(self.colors()); })) - .function("detach", &SkVertices::Builder::detach) - .function("indices", optional_override([](SkVertices::Builder &self) -> WASMPointerU16 - { - // Emscripten won't let us return bare pointers, but we can return ints just fine. - return reinterpret_cast(self.indices()); })) - .function("positions", optional_override([](SkVertices::Builder &self) -> WASMPointerF32 - { - // Emscripten won't let us return bare pointers, but we can return ints just fine. - return reinterpret_cast(self.positions()); })) - .function("texCoords", optional_override([](SkVertices::Builder &self) -> WASMPointerF32 - { - // Emscripten won't let us return bare pointers, but we can return ints just fine. - return reinterpret_cast(self.texCoords()); })); - - enum_("AlphaType") - .value("Opaque", SkAlphaType::kOpaque_SkAlphaType) - .value("Premul", SkAlphaType::kPremul_SkAlphaType) - .value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType); - - enum_("BlendMode") - .value("Clear", SkBlendMode::kClear) - .value("Src", SkBlendMode::kSrc) - .value("Dst", SkBlendMode::kDst) - .value("SrcOver", SkBlendMode::kSrcOver) - .value("DstOver", SkBlendMode::kDstOver) - .value("SrcIn", SkBlendMode::kSrcIn) - .value("DstIn", SkBlendMode::kDstIn) - .value("SrcOut", SkBlendMode::kSrcOut) - .value("DstOut", SkBlendMode::kDstOut) - .value("SrcATop", SkBlendMode::kSrcATop) - .value("DstATop", SkBlendMode::kDstATop) - .value("Xor", SkBlendMode::kXor) - .value("Plus", SkBlendMode::kPlus) - .value("Modulate", SkBlendMode::kModulate) - .value("Screen", SkBlendMode::kScreen) - .value("Overlay", SkBlendMode::kOverlay) - .value("Darken", SkBlendMode::kDarken) - .value("Lighten", SkBlendMode::kLighten) - .value("ColorDodge", SkBlendMode::kColorDodge) - .value("ColorBurn", SkBlendMode::kColorBurn) - .value("HardLight", SkBlendMode::kHardLight) - .value("SoftLight", SkBlendMode::kSoftLight) - .value("Difference", SkBlendMode::kDifference) - .value("Exclusion", SkBlendMode::kExclusion) - .value("Multiply", SkBlendMode::kMultiply) - .value("Hue", SkBlendMode::kHue) - .value("Saturation", SkBlendMode::kSaturation) - .value("Color", SkBlendMode::kColor) - .value("Luminosity", SkBlendMode::kLuminosity); - - enum_("BlurStyle") - .value("Normal", SkBlurStyle::kNormal_SkBlurStyle) - .value("Solid", SkBlurStyle::kSolid_SkBlurStyle) - .value("Outer", SkBlurStyle::kOuter_SkBlurStyle) - .value("Inner", SkBlurStyle::kInner_SkBlurStyle); - - enum_("ClipOp") - .value("Difference", SkClipOp::kDifference) - .value("Intersect", SkClipOp::kIntersect); - - enum_("ColorChannel") - .value("Red", SkColorChannel::kR) - .value("Green", SkColorChannel::kG) - .value("Blue", SkColorChannel::kB) - .value("Alpha", SkColorChannel::kA); - - enum_("ColorType") - .value("Alpha_8", SkColorType::kAlpha_8_SkColorType) - .value("RGB_565", SkColorType::kRGB_565_SkColorType) - .value("RGBA_8888", SkColorType::kRGBA_8888_SkColorType) - .value("BGRA_8888", SkColorType::kBGRA_8888_SkColorType) - .value("RGBA_1010102", SkColorType::kRGBA_1010102_SkColorType) - .value("RGB_101010x", SkColorType::kRGB_101010x_SkColorType) - .value("Gray_8", SkColorType::kGray_8_SkColorType) - .value("RGBA_F16", SkColorType::kRGBA_F16_SkColorType) - .value("RGBA_F32", SkColorType::kRGBA_F32_SkColorType); - - enum_("FillType") - .value("Winding", SkPathFillType::kWinding) - .value("EvenOdd", SkPathFillType::kEvenOdd); - - enum_("FilterMode") - .value("Nearest", SkFilterMode::kNearest) - .value("Linear", SkFilterMode::kLinear); - - // Only used to control the encode function. - // TODO(kjlubick): compile these out when the appropriate encoder is disabled. - enum_("ImageFormat") - .value("PNG", SkEncodedImageFormat::kPNG) - .value("JPEG", SkEncodedImageFormat::kJPEG) - .value("WEBP", SkEncodedImageFormat::kWEBP); - - enum_("MipmapMode") - .value("None", SkMipmapMode::kNone) - .value("Nearest", SkMipmapMode::kNearest) - .value("Linear", SkMipmapMode::kLinear); - - enum_("PaintStyle") - .value("Fill", SkPaint::Style::kFill_Style) - .value("Stroke", SkPaint::Style::kStroke_Style); - - enum_("Path1DEffect") - .value("Translate", SkPath1DPathEffect::Style::kTranslate_Style) - .value("Rotate", SkPath1DPathEffect::Style::kRotate_Style) - .value("Morph", SkPath1DPathEffect::Style::kMorph_Style); - -#ifdef CK_INCLUDE_PATHOPS - enum_("PathOp") - .value("Difference", SkPathOp::kDifference_SkPathOp) - .value("Intersect", SkPathOp::kIntersect_SkPathOp) - .value("Union", SkPathOp::kUnion_SkPathOp) - .value("XOR", SkPathOp::kXOR_SkPathOp) - .value("ReverseDifference", SkPathOp::kReverseDifference_SkPathOp); -#endif - - enum_("PointMode") - .value("Points", SkCanvas::PointMode::kPoints_PointMode) - .value("Lines", SkCanvas::PointMode::kLines_PointMode) - .value("Polygon", SkCanvas::PointMode::kPolygon_PointMode); - - enum_("StrokeCap") - .value("Butt", SkPaint::Cap::kButt_Cap) - .value("Round", SkPaint::Cap::kRound_Cap) - .value("Square", SkPaint::Cap::kSquare_Cap); - - enum_("StrokeJoin") - .value("Miter", SkPaint::Join::kMiter_Join) - .value("Round", SkPaint::Join::kRound_Join) - .value("Bevel", SkPaint::Join::kBevel_Join); - -#ifndef CK_NO_FONTS - enum_("FontHinting") - .value("None", SkFontHinting::kNone) - .value("Slight", SkFontHinting::kSlight) - .value("Normal", SkFontHinting::kNormal) - .value("Full", SkFontHinting::kFull); - - enum_("FontEdging") -#ifndef CK_NO_ALIAS_FONT - .value("Alias", SkFont::Edging::kAlias) -#endif - .value("AntiAlias", SkFont::Edging::kAntiAlias) - .value("SubpixelAntiAlias", SkFont::Edging::kSubpixelAntiAlias); -#endif - - enum_("TileMode") - .value("Clamp", SkTileMode::kClamp) - .value("Repeat", SkTileMode::kRepeat) - .value("Mirror", SkTileMode::kMirror) - .value("Decal", SkTileMode::kDecal); - - enum_("VertexMode") - .value("Triangles", SkVertices::VertexMode::kTriangles_VertexMode) - .value("TrianglesStrip", SkVertices::VertexMode::kTriangleStrip_VertexMode) - .value("TriangleFan", SkVertices::VertexMode::kTriangleFan_VertexMode); - - // A value object is much simpler than a class - it is returned as a JS - // object and does not require delete(). - // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#value-types - - value_object("ImageInfo") - .field("width", &SimpleImageInfo::width) - .field("height", &SimpleImageInfo::height) - .field("colorType", &SimpleImageInfo::colorType) - .field("alphaType", &SimpleImageInfo::alphaType) - .field("colorSpace", &SimpleImageInfo::colorSpace); - - value_object("StrokeOpts") - .field("width", &StrokeOpts::width) - .field("miter_limit", &StrokeOpts::miter_limit) - .field("join", &StrokeOpts::join) - .field("cap", &StrokeOpts::cap) - .field("precision", &StrokeOpts::precision); - - constant("MOVE_VERB", MOVE); - constant("LINE_VERB", LINE); - constant("QUAD_VERB", QUAD); - constant("CONIC_VERB", CONIC); - constant("CUBIC_VERB", CUBIC); - constant("CLOSE_VERB", CLOSE); - - constant("SaveLayerInitWithPrevious", (int)SkCanvas::SaveLayerFlagsSet::kInitWithPrevious_SaveLayerFlag); - constant("SaveLayerF16ColorType", (int)SkCanvas::SaveLayerFlagsSet::kF16ColorType); - - constant("ShadowTransparentOccluder", (int)SkShadowFlags::kTransparentOccluder_ShadowFlag); - constant("ShadowGeometricOnly", (int)SkShadowFlags::kGeometricOnly_ShadowFlag); - constant("ShadowDirectionalLight", (int)SkShadowFlags::kDirectionalLight_ShadowFlag); - -#ifdef CK_INCLUDE_PARAGRAPH - constant("_GlyphRunFlags_isWhiteSpace", (int)skia::textlayout::Paragraph::kWhiteSpace_VisitorFlag); -#endif + function("_InitCanvas", InitCanvas); + function("_DrawCanvas", DrawCanvas); + function("_SetObjects", SetObjects); + function("_SetObject", SetObject); } diff --git a/frontend/src/app/render_v2.cljs b/frontend/src/app/render_v2.cljs index 87c867934..bf63f5585 100644 --- a/frontend/src/app/render_v2.cljs +++ b/frontend/src/app/render_v2.cljs @@ -53,4 +53,7 @@ (cond ;; Rust (contains? cf/flags :render-v2-rs) - (render-v2-rs/set-objects vbox zoom base-objects))) + (render-v2-rs/set-objects vbox zoom base-objects) + + (contains? cf/flags :render-v2-cpp) + (render-v2-cpp/set-objects vbox zoom base-objects))) diff --git a/frontend/src/app/render_v2/cpp.cljs b/frontend/src/app/render_v2/cpp.cljs index e0696cf8b..5f1e599dd 100644 --- a/frontend/src/app/render_v2/cpp.cljs +++ b/frontend/src/app/render_v2/cpp.cljs @@ -15,21 +15,22 @@ (defn set-canvas [canvas vbox zoom base-objects] - (js/console.log "setting canvas" canvas) (.setCanvas ^js internal-module canvas #js {:antialias false}) - (js/console.log "canvas set") + (.setObjects ^js internal-module vbox zoom base-objects) (.drawCanvas ^js internal-module vbox zoom base-objects)) (defn draw-canvas [vbox zoom base-objects] - (js/console.log "draw canvas" vbox zoom base-objects) (.drawCanvas ^js internal-module vbox zoom base-objects)) +(defn set-objects + [vbox zoom base-objects] + (.setObjects ^js internal-module vbox zoom base-objects)) + (defn on-init [module'] (set! internal-module module') - (js/console.log "internal-module" internal-module module') - (js/console.log "add 2 + 2" (._add ^js module' 2 2))) + (js/console.log "internal-module" internal-module module')) (defn init [] diff --git a/frontend/src/app/render_v2/cpp.js b/frontend/src/app/render_v2/cpp.js index 534a5f049..6ce8a8217 100644 --- a/frontend/src/app/render_v2/cpp.js +++ b/frontend/src/app/render_v2/cpp.js @@ -40,12 +40,6 @@ Module['ready'] = new Promise(function(resolve, reject) { } - if (!Object.getOwnPropertyDescriptor(Module['ready'], '_add')) { - Object.defineProperty(Module['ready'], '_add', { configurable: true, get: function() { abort('You are getting _add on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js') } }); - Object.defineProperty(Module['ready'], '_add', { configurable: true, set: function() { abort('You are setting _add on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js') } }); - } - - if (!Object.getOwnPropertyDescriptor(Module['ready'], '___getTypeName')) { Object.defineProperty(Module['ready'], '___getTypeName', { configurable: true, get: function() { abort('You are getting ___getTypeName on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js') } }); Object.defineProperty(Module['ready'], '___getTypeName', { configurable: true, set: function() { abort('You are setting ___getTypeName on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js') } }); @@ -70,12 +64,8 @@ Module['ready'] = new Promise(function(resolve, reject) { (function (Renderer) { console.log("preamble", Renderer); - // - let gr; - let surface; - + // Sets canvas. Renderer.setCanvas = function setCanvas(canvas, attrs) { - console.log("GL", GL); const context = GL.createContext(canvas, attrs); if (!context) { throw new Error('Could not create a new WebGL context') @@ -86,80 +76,26 @@ Module['ready'] = new Promise(function(resolve, reject) { // to handle certain GPU corner cases. GL.currentContext.GLctx.getExtension('WEBGL_debug_renderer_info'); - console.log("setCanvas", canvas, attrs); - gr = this._MakeGrContext(); - console.log("gr", gr); + // Initializes everything needed. + this._InitCanvas(canvas.width, canvas.height); + }; - surface = this._MakeOnScreenGLSurface(gr, canvas.width, canvas.height); - console.log("surface", surface); - if (!surface) { - throw new Error('Cannot initialize surface') + Renderer.setObjects = function setObjects(vbox, zoom, objects) { + this._SetObjects(objects.cnt); + for (let index = 0; index < objects.cnt; index++) { + const object = objects.arr[index * 2 + 1]; + this._SetObject( + index, + object.selrect.x, + object.selrect.y, + object.selrect.width, + object.selrect.height, + ); } }; - function wasMalloced(obj) { - return obj && obj['_ck']; - } - - function copy1dArray(arr, dest, ptr) { - if (!arr || !arr.length) return null; - if (wasMalloced(arr)) { - return arr.byteOffset; - } - const bytesPerElement = Renderer[dest].BYTES_PER_ELEMENT; - if (!ptr) { - ptr = Renderer._malloc(arr.length * bytesPerElement); - } - Renderer[dest].set(arr, ptr / bytesPerElement); - return ptr; - } - - function copyRectToWasm(fourFloats, ptr) { - return copy1dArray(fourFloats, 'HEAPF32', ptr || null); - } - - function copyColorToWasm(color4f, ptr) { - return copy1dArray(color4f, 'HEAPF32', ptr || null); - } - Renderer.drawCanvas = function drawCanvas(vbox, zoom, objects) { - console.log("vbox", vbox); - console.log("zoom", zoom); - if (!surface) { - throw new Error('Surface uninitialized'); - } - - console.log("renderer", Renderer); - console.log("surface", surface); - - // Esto es una ÑAPA terrible, no me gusta. - if (!Renderer.Paint.prototype.setColor) { - Renderer.Paint.prototype.setColor = function(color4f, colorSpace = null) { - const cPtr = copyColorToWasm(color4f); - this._setColor(cPtr, colorSpace); - } - } - - const paint = new Renderer.Paint(); - paint.setColor(Float32Array.of(1.0, 0, 0, 1.0)); - paint.setStyle(Renderer.PaintStyle.Fill); - paint.setAntiAlias(true); - console.log("paint", paint); - - const canvas = surface._getCanvas(); - console.log("canvas", canvas); - - const cPtr = copyColorToWasm(Float32Array.of(0.0, 0.0, 0.0, 1.0)) - canvas._clear(cPtr); - console.log("canvas cleared"); - - for (const { val: object } of objects) { - console.log("object", object); - const rr = Float32Array.of(object.selrect.x, object.selrect.y, object.selrect.width, object.selrect.height); - - const rPtr = copyRectToWasm(rr); - canvas._drawRect(rPtr, paint); - } + this._DrawCanvas(vbox.x, vbox.y, zoom); }; console.log("postamble"); @@ -294,13 +230,13 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { scriptDirectory = ''; } - scriptDirectory += 'js/render_v2/cpp/'; if (!(typeof window == 'object' || typeof importScripts == 'function')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); // Differentiate the Web Worker from the Node Worker case, as reading must // be done differently. { // include: web_or_worker_shell_read.js + scriptDirectory += 'js/render_v2/cpp/'; read_ = (url) => { @@ -2015,18 +1951,34 @@ var ASM_CONSTS = { abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM'); } - var structRegistrations = {}; - - function runDestructors(destructors) { - while (destructors.length) { - var ptr = destructors.pop(); - var del = destructors.pop(); - del(ptr); + function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) {} + + function getShiftFromSize(size) { + switch (size) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 8: return 3; + default: + throw new TypeError('Unknown type size: ' + size); } } - function simpleReadValueFromPointer(pointer) { - return this['fromWireType'](HEAP32[((pointer)>>2)]); + function embind_init_charCodes() { + var codes = new Array(256); + for (var i = 0; i < 256; ++i) { + codes[i] = String.fromCharCode(i); + } + embind_charCodes = codes; + } + var embind_charCodes = undefined; + function readLatin1String(ptr) { + var ret = ""; + var c = ptr; + while (HEAPU8[c]) { + ret += embind_charCodes[HEAPU8[c++]]; + } + return ret; } var awaitingDependencies = {}; @@ -2079,6 +2031,11 @@ var ASM_CONSTS = { return errorClass; } + var BindingError = undefined; + function throwBindingError(message) { + throw new BindingError(message); + } + var InternalError = undefined; function throwInternalError(message) { throw new InternalError(message); @@ -2122,106 +2079,6 @@ var ASM_CONSTS = { onComplete(typeConverters); } } - function __embind_finalize_value_object(structType) { - var reg = structRegistrations[structType]; - delete structRegistrations[structType]; - - var rawConstructor = reg.rawConstructor; - var rawDestructor = reg.rawDestructor; - var fieldRecords = reg.fields; - var fieldTypes = fieldRecords.map((field) => field.getterReturnType). - concat(fieldRecords.map((field) => field.setterArgumentType)); - whenDependentTypesAreResolved([structType], fieldTypes, (fieldTypes) => { - var fields = {}; - fieldRecords.forEach((field, i) => { - var fieldName = field.fieldName; - var getterReturnType = fieldTypes[i]; - var getter = field.getter; - var getterContext = field.getterContext; - var setterArgumentType = fieldTypes[i + fieldRecords.length]; - var setter = field.setter; - var setterContext = field.setterContext; - fields[fieldName] = { - read: (ptr) => { - return getterReturnType['fromWireType']( - getter(getterContext, ptr)); - }, - write: (ptr, o) => { - var destructors = []; - setter(setterContext, ptr, setterArgumentType['toWireType'](destructors, o)); - runDestructors(destructors); - } - }; - }); - - return [{ - name: reg.name, - 'fromWireType': function(ptr) { - var rv = {}; - for (var i in fields) { - rv[i] = fields[i].read(ptr); - } - rawDestructor(ptr); - return rv; - }, - 'toWireType': function(destructors, o) { - // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: - // assume all fields are present without checking. - for (var fieldName in fields) { - if (!(fieldName in o)) { - throw new TypeError('Missing field: "' + fieldName + '"'); - } - } - var ptr = rawConstructor(); - for (fieldName in fields) { - fields[fieldName].write(ptr, o[fieldName]); - } - if (destructors !== null) { - destructors.push(rawDestructor, ptr); - } - return ptr; - }, - 'argPackAdvance': 8, - 'readValueFromPointer': simpleReadValueFromPointer, - destructorFunction: rawDestructor, - }]; - }); - } - - function __embind_register_bigint(primitiveType, name, size, minRange, maxRange) {} - - function getShiftFromSize(size) { - switch (size) { - case 1: return 0; - case 2: return 1; - case 4: return 2; - case 8: return 3; - default: - throw new TypeError('Unknown type size: ' + size); - } - } - - function embind_init_charCodes() { - var codes = new Array(256); - for (var i = 0; i < 256; ++i) { - codes[i] = String.fromCharCode(i); - } - embind_charCodes = codes; - } - var embind_charCodes = undefined; - function readLatin1String(ptr) { - var ret = ""; - var c = ptr; - while (HEAPU8[c]) { - ret += embind_charCodes[HEAPU8[c++]]; - } - return ret; - } - - var BindingError = undefined; - function throwBindingError(message) { - throw new BindingError(message); - } /** @param {Object=} options */ function registerType(rawType, registeredInstance, options = {}) { if (!('argPackAdvance' in registeredInstance)) { @@ -2282,334 +2139,242 @@ var ASM_CONSTS = { }); } - function ClassHandle_isAliasOf(other) { - if (!(this instanceof ClassHandle)) { - return false; - } - if (!(other instanceof ClassHandle)) { - return false; - } + var emval_free_list = []; - var leftClass = this.$$.ptrType.registeredClass; - var left = this.$$.ptr; - var rightClass = other.$$.ptrType.registeredClass; - var right = other.$$.ptr; - - while (leftClass.baseClass) { - left = leftClass.upcast(left); - leftClass = leftClass.baseClass; - } - - while (rightClass.baseClass) { - right = rightClass.upcast(right); - rightClass = rightClass.baseClass; - } - - return leftClass === rightClass && left === right; - } - - function shallowCopyInternalPointer(o) { - return { - count: o.count, - deleteScheduled: o.deleteScheduled, - preservePointerOnDelete: o.preservePointerOnDelete, - ptr: o.ptr, - ptrType: o.ptrType, - smartPtr: o.smartPtr, - smartPtrType: o.smartPtrType, - }; - } - - function throwInstanceAlreadyDeleted(obj) { - function getInstanceTypeName(handle) { - return handle.$$.ptrType.registeredClass.name; - } - throwBindingError(getInstanceTypeName(obj) + ' instance already deleted'); - } - - var finalizationRegistry = false; - - function detachFinalizer(handle) {} - - function runDestructor($$) { - if ($$.smartPtr) { - $$.smartPtrType.rawDestructor($$.smartPtr); - } else { - $$.ptrType.registeredClass.rawDestructor($$.ptr); - } - } - function releaseClassHandle($$) { - $$.count.value -= 1; - var toDelete = 0 === $$.count.value; - if (toDelete) { - runDestructor($$); + var emval_handle_array = [{},{value:undefined},{value:null},{value:true},{value:false}]; + function __emval_decref(handle) { + if (handle > 4 && 0 === --emval_handle_array[handle].refcount) { + emval_handle_array[handle] = undefined; + emval_free_list.push(handle); } } - function downcastPointer(ptr, ptrClass, desiredClass) { - if (ptrClass === desiredClass) { - return ptr; + function count_emval_handles() { + var count = 0; + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== undefined) { + ++count; + } } - if (undefined === desiredClass.baseClass) { - return null; // no conversion - } - - var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); - if (rv === null) { - return null; - } - return desiredClass.downcast(rv); + return count; } - var registeredPointers = {}; - - function getInheritedInstanceCount() { - return Object.keys(registeredInstances).length; + function get_first_emval() { + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== undefined) { + return emval_handle_array[i]; + } + } + return null; } + function init_emval() { + Module['count_emval_handles'] = count_emval_handles; + Module['get_first_emval'] = get_first_emval; + } + var Emval = {toValue:(handle) => { + if (!handle) { + throwBindingError('Cannot use deleted val. handle = ' + handle); + } + return emval_handle_array[handle].value; + },toHandle:(value) => { + switch (value) { + case undefined: return 1; + case null: return 2; + case true: return 3; + case false: return 4; + default:{ + var handle = emval_free_list.length ? + emval_free_list.pop() : + emval_handle_array.length; - function getLiveInheritedInstances() { - var rv = []; - for (var k in registeredInstances) { - if (registeredInstances.hasOwnProperty(k)) { - rv.push(registeredInstances[k]); + emval_handle_array[handle] = {refcount: 1, value: value}; + return handle; } - } - return rv; - } + } + }}; - var deletionQueue = []; - function flushPendingDeletes() { - while (deletionQueue.length) { - var obj = deletionQueue.pop(); - obj.$$.deleteScheduled = false; - obj['delete'](); - } + function simpleReadValueFromPointer(pointer) { + return this['fromWireType'](HEAP32[((pointer)>>2)]); } - - var delayFunction = undefined; - function setDelayFunction(fn) { - delayFunction = fn; - if (deletionQueue.length && delayFunction) { - delayFunction(flushPendingDeletes); - } - } - function init_embind() { - Module['getInheritedInstanceCount'] = getInheritedInstanceCount; - Module['getLiveInheritedInstances'] = getLiveInheritedInstances; - Module['flushPendingDeletes'] = flushPendingDeletes; - Module['setDelayFunction'] = setDelayFunction; - } - var registeredInstances = {}; - - function getBasestPointer(class_, ptr) { - if (ptr === undefined) { - throwBindingError('ptr should not be undefined'); - } - while (class_.baseClass) { - ptr = class_.upcast(ptr); - class_ = class_.baseClass; - } - return ptr; - } - function getInheritedInstance(class_, ptr) { - ptr = getBasestPointer(class_, ptr); - return registeredInstances[ptr]; - } - - function makeClassHandle(prototype, record) { - if (!record.ptrType || !record.ptr) { - throwInternalError('makeClassHandle requires ptr and ptrType'); - } - var hasSmartPtrType = !!record.smartPtrType; - var hasSmartPtr = !!record.smartPtr; - if (hasSmartPtrType !== hasSmartPtr) { - throwInternalError('Both smartPtrType and smartPtr must be specified'); - } - record.count = { value: 1 }; - return attachFinalizer(Object.create(prototype, { - $$: { - value: record, - }, - })); - } - function RegisteredPointer_fromWireType(ptr) { - // ptr is a raw pointer (or a raw smartpointer) - - // rawPointer is a maybe-null raw pointer - var rawPointer = this.getPointee(ptr); - if (!rawPointer) { - this.destructor(ptr); - return null; - } - - var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer); - if (undefined !== registeredInstance) { - // JS object has been neutered, time to repopulate it - if (0 === registeredInstance.$$.count.value) { - registeredInstance.$$.ptr = rawPointer; - registeredInstance.$$.smartPtr = ptr; - return registeredInstance['clone'](); - } else { - // else, just increment reference count on existing object - // it already has a reference to the smart pointer - var rv = registeredInstance['clone'](); - this.destructor(ptr); + function __embind_register_emval(rawType, name) { + name = readLatin1String(name); + registerType(rawType, { + name: name, + 'fromWireType': function(handle) { + var rv = Emval.toValue(handle); + __emval_decref(handle); return rv; - } - } + }, + 'toWireType': function(destructors, value) { + return Emval.toHandle(value); + }, + 'argPackAdvance': 8, + 'readValueFromPointer': simpleReadValueFromPointer, + destructorFunction: null, // This type does not need a destructor - function makeDefaultHandle() { - if (this.isSmartPointer) { - return makeClassHandle(this.registeredClass.instancePrototype, { - ptrType: this.pointeeType, - ptr: rawPointer, - smartPtrType: this, - smartPtr: ptr, - }); - } else { - return makeClassHandle(this.registeredClass.instancePrototype, { - ptrType: this, - ptr: ptr, - }); - } - } - - var actualType = this.registeredClass.getActualType(rawPointer); - var registeredPointerRecord = registeredPointers[actualType]; - if (!registeredPointerRecord) { - return makeDefaultHandle.call(this); - } - - var toType; - if (this.isConst) { - toType = registeredPointerRecord.constPointerType; - } else { - toType = registeredPointerRecord.pointerType; - } - var dp = downcastPointer( - rawPointer, - this.registeredClass, - toType.registeredClass); - if (dp === null) { - return makeDefaultHandle.call(this); - } - if (this.isSmartPointer) { - return makeClassHandle(toType.registeredClass.instancePrototype, { - ptrType: toType, - ptr: dp, - smartPtrType: this, - smartPtr: ptr, - }); - } else { - return makeClassHandle(toType.registeredClass.instancePrototype, { - ptrType: toType, - ptr: dp, - }); - } - } - function attachFinalizer(handle) { - if ('undefined' === typeof FinalizationRegistry) { - attachFinalizer = (handle) => handle; - return handle; - } - // If the running environment has a FinalizationRegistry (see - // https://github.com/tc39/proposal-weakrefs), then attach finalizers - // for class handles. We check for the presence of FinalizationRegistry - // at run-time, not build-time. - finalizationRegistry = new FinalizationRegistry((info) => { - console.warn(info.leakWarning.stack.replace(/^Error: /, '')); - releaseClassHandle(info.$$); + // TODO: do we need a deleteObject here? write a test where + // emval is passed into JS via an interface }); - attachFinalizer = (handle) => { - var $$ = handle.$$; - var hasSmartPtr = !!$$.smartPtr; - if (hasSmartPtr) { - // We should not call the destructor on raw pointers in case other code expects the pointee to live - var info = { $$: $$ }; - // Create a warning as an Error instance in advance so that we can store - // the current stacktrace and point to it when / if a leak is detected. - // This is more useful than the empty stacktrace of `FinalizationRegistry` - // callback. - var cls = $$.ptrType.registeredClass; - info.leakWarning = new Error("Embind found a leaked C++ instance " + cls.name + " <0x" + $$.ptr.toString(16) + ">.\n" + - "We'll free it automatically in this case, but this functionality is not reliable across various environments.\n" + - "Make sure to invoke .delete() manually once you're done with the instance instead.\n" + - "Originally allocated"); // `.stack` will add "at ..." after this sentence - if ('captureStackTrace' in Error) { - Error.captureStackTrace(info.leakWarning, RegisteredPointer_fromWireType); - } - finalizationRegistry.register(handle, info, handle); - } - return handle; - }; - detachFinalizer = (handle) => finalizationRegistry.unregister(handle); - return attachFinalizer(handle); } - function ClassHandle_clone() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); + + function embindRepr(v) { + if (v === null) { + return 'null'; } - - if (this.$$.preservePointerOnDelete) { - this.$$.count.value += 1; - return this; + var t = typeof v; + if (t === 'object' || t === 'array' || t === 'function') { + return v.toString(); } else { - var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { - $$: { - value: shallowCopyInternalPointer(this.$$), + return '' + v; + } + } + + function floatReadValueFromPointer(name, shift) { + switch (shift) { + case 2: return function(pointer) { + return this['fromWireType'](HEAPF32[pointer >> 2]); + }; + case 3: return function(pointer) { + return this['fromWireType'](HEAPF64[pointer >> 3]); + }; + default: + throw new TypeError("Unknown float type: " + name); + } + } + function __embind_register_float(rawType, name, size) { + var shift = getShiftFromSize(size); + name = readLatin1String(name); + registerType(rawType, { + name: name, + 'fromWireType': function(value) { + return value; + }, + 'toWireType': function(destructors, value) { + if (typeof value != "number" && typeof value != "boolean") { + throw new TypeError('Cannot convert "' + embindRepr(value) + '" to ' + this.name); + } + // The VM will perform JS to Wasm value conversion, according to the spec: + // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue + return value; + }, + 'argPackAdvance': 8, + 'readValueFromPointer': floatReadValueFromPointer(name, shift), + destructorFunction: null, // This type does not need a destructor + }); + } + + function new_(constructor, argumentList) { + if (!(constructor instanceof Function)) { + throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function"); + } + if (constructor === Function) { + throw new Error('new_ cannot create a new Function with DYNAMIC_EXECUTION == 0.'); + } + /* + * Previously, the following line was just: + * function dummy() {}; + * Unfortunately, Chrome was preserving 'dummy' as the object's name, even + * though at creation, the 'dummy' has the correct constructor name. Thus, + * objects created with IMVU.new would show up in the debugger as 'dummy', + * which isn't very helpful. Using IMVU.createNamedFunction addresses the + * issue. Doublely-unfortunately, there's no way to write a test for this + * behavior. -NRD 2013.02.22 + */ + var dummy = createNamedFunction(constructor.name || 'unknownFunctionName', function(){}); + dummy.prototype = constructor.prototype; + var obj = new dummy; + + var r = constructor.apply(obj, argumentList); + return (r instanceof Object) ? r : obj; + } + + function runDestructors(destructors) { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } + } + function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { + // humanName: a human-readable string name for the function to be generated. + // argTypes: An array that contains the embind type objects for all types in the function signature. + // argTypes[0] is the type object for the function return value. + // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method. + // argTypes[2...] are the actual function parameters. + // classType: The embind type object for the class to be bound, or null if this is not a method of a class. + // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. + // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. + var argCount = argTypes.length; + + if (argCount < 2) { + throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); + } + + var isClassMethodFunc = (argTypes[1] !== null && classType !== null); + + // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. + // TODO: This omits argument count check - enable only at -O3 or similar. + // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { + // return FUNCTION_TABLE[fn]; + // } + + // Determine if we need to use a dynamic stack to store the destructors for the function parameters. + // TODO: Remove this completely once all function invokers are being dynamically generated. + var needsDestructorStack = false; + + for (var i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. + if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack + needsDestructorStack = true; + break; + } + } + + var returns = (argTypes[0].name !== "void"); + + var expectedArgCount = argCount - 2; + var argsWired = new Array(expectedArgCount); + var invokerFuncArgs = []; + var destructors = []; + return function() { + if (arguments.length !== expectedArgCount) { + throwBindingError('function ' + humanName + ' called with ' + + arguments.length + ' arguments, expected ' + expectedArgCount + + ' args!'); + } + destructors.length = 0; + var thisWired; + invokerFuncArgs.length = isClassMethodFunc ? 2 : 1; + invokerFuncArgs[0] = cppTargetFunc; + if (isClassMethodFunc) { + thisWired = argTypes[1]['toWireType'](destructors, this); + invokerFuncArgs[1] = thisWired; + } + for (var i = 0; i < expectedArgCount; ++i) { + argsWired[i] = argTypes[i + 2]['toWireType'](destructors, arguments[i]); + invokerFuncArgs.push(argsWired[i]); + } + + var rv = cppInvokerFunc.apply(null, invokerFuncArgs); + + function onDone(rv) { + if (needsDestructorStack) { + runDestructors(destructors); + } else { + for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; i++) { + var param = i === 1 ? thisWired : argsWired[i - 2]; + if (argTypes[i].destructorFunction !== null) { + argTypes[i].destructorFunction(param); + } + } } - })); - clone.$$.count.value += 1; - clone.$$.deleteScheduled = false; - return clone; - } - } + if (returns) { + return argTypes[0]['fromWireType'](rv); + } + } - function ClassHandle_delete() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - - if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { - throwBindingError('Object already scheduled for deletion'); - } - - detachFinalizer(this); - releaseClassHandle(this.$$); - - if (!this.$$.preservePointerOnDelete) { - this.$$.smartPtr = undefined; - this.$$.ptr = undefined; - } - } - - function ClassHandle_isDeleted() { - return !this.$$.ptr; - } - - function ClassHandle_deleteLater() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { - throwBindingError('Object already scheduled for deletion'); - } - deletionQueue.push(this); - if (deletionQueue.length === 1 && delayFunction) { - delayFunction(flushPendingDeletes); - } - this.$$.deleteScheduled = true; - return this; - } - function init_ClassHandle() { - ClassHandle.prototype['isAliasOf'] = ClassHandle_isAliasOf; - ClassHandle.prototype['clone'] = ClassHandle_clone; - ClassHandle.prototype['delete'] = ClassHandle_delete; - ClassHandle.prototype['isDeleted'] = ClassHandle_isDeleted; - ClassHandle.prototype['deleteLater'] = ClassHandle_deleteLater; - } - function ClassHandle() { + return onDone(rv); + }; } function ensureOverloadTable(proto, methodName, humanName) { @@ -2652,231 +2417,14 @@ var ASM_CONSTS = { } } - /** @constructor */ - function RegisteredClass(name, - constructor, - instancePrototype, - rawDestructor, - baseClass, - getActualType, - upcast, - downcast) { - this.name = name; - this.constructor = constructor; - this.instancePrototype = instancePrototype; - this.rawDestructor = rawDestructor; - this.baseClass = baseClass; - this.getActualType = getActualType; - this.upcast = upcast; - this.downcast = downcast; - this.pureVirtualFunctions = []; - } - - function upcastPointer(ptr, ptrClass, desiredClass) { - while (ptrClass !== desiredClass) { - if (!ptrClass.upcast) { - throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); - } - ptr = ptrClass.upcast(ptr); - ptrClass = ptrClass.baseClass; - } - return ptr; - } - function constNoSmartPtrRawPointerToWireType(destructors, handle) { - if (handle === null) { - if (this.isReference) { - throwBindingError('null is not a valid ' + this.name); - } - return 0; - } - - if (!handle.$$) { - throwBindingError('Cannot pass "' + embindRepr(handle) + '" as a ' + this.name); - } - if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); - } - var handleClass = handle.$$.ptrType.registeredClass; - var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - return ptr; - } - - function genericPointerToWireType(destructors, handle) { - var ptr; - if (handle === null) { - if (this.isReference) { - throwBindingError('null is not a valid ' + this.name); - } - - if (this.isSmartPointer) { - ptr = this.rawConstructor(); - if (destructors !== null) { - destructors.push(this.rawDestructor, ptr); - } - return ptr; - } else { - return 0; - } - } - - if (!handle.$$) { - throwBindingError('Cannot pass "' + embindRepr(handle) + '" as a ' + this.name); - } - if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); - } - if (!this.isConst && handle.$$.ptrType.isConst) { - throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); - } - var handleClass = handle.$$.ptrType.registeredClass; - ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - - if (this.isSmartPointer) { - // TODO: this is not strictly true - // We could support BY_EMVAL conversions from raw pointers to smart pointers - // because the smart pointer can hold a reference to the handle - if (undefined === handle.$$.smartPtr) { - throwBindingError('Passing raw pointer to smart pointer is illegal'); - } - - switch (this.sharingPolicy) { - case 0: // NONE - // no upcasting - if (handle.$$.smartPtrType === this) { - ptr = handle.$$.smartPtr; - } else { - throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); - } - break; - - case 1: // INTRUSIVE - ptr = handle.$$.smartPtr; - break; - - case 2: // BY_EMVAL - if (handle.$$.smartPtrType === this) { - ptr = handle.$$.smartPtr; - } else { - var clonedHandle = handle['clone'](); - ptr = this.rawShare( - ptr, - Emval.toHandle(function() { - clonedHandle['delete'](); - }) - ); - if (destructors !== null) { - destructors.push(this.rawDestructor, ptr); - } - } - break; - - default: - throwBindingError('Unsupporting sharing policy'); - } - } - return ptr; - } - - function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) { - if (handle === null) { - if (this.isReference) { - throwBindingError('null is not a valid ' + this.name); - } - return 0; - } - - if (!handle.$$) { - throwBindingError('Cannot pass "' + embindRepr(handle) + '" as a ' + this.name); - } - if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); - } - if (handle.$$.ptrType.isConst) { - throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); - } - var handleClass = handle.$$.ptrType.registeredClass; - var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - return ptr; - } - - function RegisteredPointer_getPointee(ptr) { - if (this.rawGetPointee) { - ptr = this.rawGetPointee(ptr); - } - return ptr; - } - - function RegisteredPointer_destructor(ptr) { - if (this.rawDestructor) { - this.rawDestructor(ptr); - } - } - - function RegisteredPointer_deleteObject(handle) { - if (handle !== null) { - handle['delete'](); - } - } - function init_RegisteredPointer() { - RegisteredPointer.prototype.getPointee = RegisteredPointer_getPointee; - RegisteredPointer.prototype.destructor = RegisteredPointer_destructor; - RegisteredPointer.prototype['argPackAdvance'] = 8; - RegisteredPointer.prototype['readValueFromPointer'] = simpleReadValueFromPointer; - RegisteredPointer.prototype['deleteObject'] = RegisteredPointer_deleteObject; - RegisteredPointer.prototype['fromWireType'] = RegisteredPointer_fromWireType; - } - /** @constructor - @param {*=} pointeeType, - @param {*=} sharingPolicy, - @param {*=} rawGetPointee, - @param {*=} rawConstructor, - @param {*=} rawShare, - @param {*=} rawDestructor, - */ - function RegisteredPointer( - name, - registeredClass, - isReference, - isConst, - - // smart pointer properties - isSmartPointer, - pointeeType, - sharingPolicy, - rawGetPointee, - rawConstructor, - rawShare, - rawDestructor - ) { - this.name = name; - this.registeredClass = registeredClass; - this.isReference = isReference; - this.isConst = isConst; - - // smart pointer properties - this.isSmartPointer = isSmartPointer; - this.pointeeType = pointeeType; - this.sharingPolicy = sharingPolicy; - this.rawGetPointee = rawGetPointee; - this.rawConstructor = rawConstructor; - this.rawShare = rawShare; - this.rawDestructor = rawDestructor; - - if (!isSmartPointer && registeredClass.baseClass === undefined) { - if (isConst) { - this['toWireType'] = constNoSmartPtrRawPointerToWireType; - this.destructorFunction = null; - } else { - this['toWireType'] = nonConstNoSmartPtrRawPointerToWireType; - this.destructorFunction = null; - } - } else { - this['toWireType'] = genericPointerToWireType; - // Here we must leave this.destructorFunction undefined, since whether genericPointerToWireType returns - // a pointer that needs to be freed up is runtime-dependent, and cannot be evaluated at registration time. - // TODO: Create an alternative mechanism that allows removing the use of var destructors = []; array in - // craftInvokerFunction altogether. + function heap32VectorToArray(count, firstElement) { + var array = []; + for (var i = 0; i < count; i++) { + // TODO(https://github.com/emscripten-core/emscripten/issues/17310): + // Find a way to hoist the `>> 2` or `>> 3` out of this loop. + array.push(HEAPU32[(((firstElement)+(i * 4))>>2)]); } + return array; } /** @param {number=} numArguments */ @@ -2972,567 +2520,6 @@ var ASM_CONSTS = { throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', '])); } - function __embind_register_class(rawType, - rawPointerType, - rawConstPointerType, - baseClassRawType, - getActualTypeSignature, - getActualType, - upcastSignature, - upcast, - downcastSignature, - downcast, - name, - destructorSignature, - rawDestructor) { - name = readLatin1String(name); - getActualType = embind__requireFunction(getActualTypeSignature, getActualType); - if (upcast) { - upcast = embind__requireFunction(upcastSignature, upcast); - } - if (downcast) { - downcast = embind__requireFunction(downcastSignature, downcast); - } - rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); - var legalFunctionName = makeLegalFunctionName(name); - - exposePublicSymbol(legalFunctionName, function() { - // this code cannot run if baseClassRawType is zero - throwUnboundTypeError('Cannot construct ' + name + ' due to unbound types', [baseClassRawType]); - }); - - whenDependentTypesAreResolved( - [rawType, rawPointerType, rawConstPointerType], - baseClassRawType ? [baseClassRawType] : [], - function(base) { - base = base[0]; - - var baseClass; - var basePrototype; - if (baseClassRawType) { - baseClass = base.registeredClass; - basePrototype = baseClass.instancePrototype; - } else { - basePrototype = ClassHandle.prototype; - } - - var constructor = createNamedFunction(legalFunctionName, function() { - if (Object.getPrototypeOf(this) !== instancePrototype) { - throw new BindingError("Use 'new' to construct " + name); - } - if (undefined === registeredClass.constructor_body) { - throw new BindingError(name + " has no accessible constructor"); - } - var body = registeredClass.constructor_body[arguments.length]; - if (undefined === body) { - throw new BindingError("Tried to invoke ctor of " + name + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); - } - return body.apply(this, arguments); - }); - - var instancePrototype = Object.create(basePrototype, { - constructor: { value: constructor }, - }); - - constructor.prototype = instancePrototype; - - var registeredClass = new RegisteredClass(name, - constructor, - instancePrototype, - rawDestructor, - baseClass, - getActualType, - upcast, - downcast); - - var referenceConverter = new RegisteredPointer(name, - registeredClass, - true, - false, - false); - - var pointerConverter = new RegisteredPointer(name + '*', - registeredClass, - false, - false, - false); - - var constPointerConverter = new RegisteredPointer(name + ' const*', - registeredClass, - false, - true, - false); - - registeredPointers[rawType] = { - pointerType: pointerConverter, - constPointerType: constPointerConverter - }; - - replacePublicSymbol(legalFunctionName, constructor); - - return [referenceConverter, pointerConverter, constPointerConverter]; - } - ); - } - - function new_(constructor, argumentList) { - if (!(constructor instanceof Function)) { - throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function"); - } - if (constructor === Function) { - throw new Error('new_ cannot create a new Function with DYNAMIC_EXECUTION == 0.'); - } - /* - * Previously, the following line was just: - * function dummy() {}; - * Unfortunately, Chrome was preserving 'dummy' as the object's name, even - * though at creation, the 'dummy' has the correct constructor name. Thus, - * objects created with IMVU.new would show up in the debugger as 'dummy', - * which isn't very helpful. Using IMVU.createNamedFunction addresses the - * issue. Doublely-unfortunately, there's no way to write a test for this - * behavior. -NRD 2013.02.22 - */ - var dummy = createNamedFunction(constructor.name || 'unknownFunctionName', function(){}); - dummy.prototype = constructor.prototype; - var obj = new dummy; - - var r = constructor.apply(obj, argumentList); - return (r instanceof Object) ? r : obj; - } - function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { - // humanName: a human-readable string name for the function to be generated. - // argTypes: An array that contains the embind type objects for all types in the function signature. - // argTypes[0] is the type object for the function return value. - // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method. - // argTypes[2...] are the actual function parameters. - // classType: The embind type object for the class to be bound, or null if this is not a method of a class. - // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. - // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. - var argCount = argTypes.length; - - if (argCount < 2) { - throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); - } - - var isClassMethodFunc = (argTypes[1] !== null && classType !== null); - - // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. - // TODO: This omits argument count check - enable only at -O3 or similar. - // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { - // return FUNCTION_TABLE[fn]; - // } - - // Determine if we need to use a dynamic stack to store the destructors for the function parameters. - // TODO: Remove this completely once all function invokers are being dynamically generated. - var needsDestructorStack = false; - - for (var i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. - if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack - needsDestructorStack = true; - break; - } - } - - var returns = (argTypes[0].name !== "void"); - - var expectedArgCount = argCount - 2; - var argsWired = new Array(expectedArgCount); - var invokerFuncArgs = []; - var destructors = []; - return function() { - if (arguments.length !== expectedArgCount) { - throwBindingError('function ' + humanName + ' called with ' + - arguments.length + ' arguments, expected ' + expectedArgCount + - ' args!'); - } - destructors.length = 0; - var thisWired; - invokerFuncArgs.length = isClassMethodFunc ? 2 : 1; - invokerFuncArgs[0] = cppTargetFunc; - if (isClassMethodFunc) { - thisWired = argTypes[1]['toWireType'](destructors, this); - invokerFuncArgs[1] = thisWired; - } - for (var i = 0; i < expectedArgCount; ++i) { - argsWired[i] = argTypes[i + 2]['toWireType'](destructors, arguments[i]); - invokerFuncArgs.push(argsWired[i]); - } - - var rv = cppInvokerFunc.apply(null, invokerFuncArgs); - - function onDone(rv) { - if (needsDestructorStack) { - runDestructors(destructors); - } else { - for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; i++) { - var param = i === 1 ? thisWired : argsWired[i - 2]; - if (argTypes[i].destructorFunction !== null) { - argTypes[i].destructorFunction(param); - } - } - } - - if (returns) { - return argTypes[0]['fromWireType'](rv); - } - } - - return onDone(rv); - }; - } - - function heap32VectorToArray(count, firstElement) { - var array = []; - for (var i = 0; i < count; i++) { - // TODO(https://github.com/emscripten-core/emscripten/issues/17310): - // Find a way to hoist the `>> 2` or `>> 3` out of this loop. - array.push(HEAPU32[(((firstElement)+(i * 4))>>2)]); - } - return array; - } - function __embind_register_class_class_function(rawClassType, - methodName, - argCount, - rawArgTypesAddr, - invokerSignature, - rawInvoker, - fn) { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - methodName = readLatin1String(methodName); - rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); - whenDependentTypesAreResolved([], [rawClassType], function(classType) { - classType = classType[0]; - var humanName = classType.name + '.' + methodName; - - function unboundTypesHandler() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); - } - - if (methodName.startsWith("@@")) { - methodName = Symbol[methodName.substring(2)]; - } - - var proto = classType.registeredClass.constructor; - if (undefined === proto[methodName]) { - // This is the first function to be registered with this name. - unboundTypesHandler.argCount = argCount-1; - proto[methodName] = unboundTypesHandler; - } else { - // There was an existing function with the same name registered. Set up - // a function overload routing table. - ensureOverloadTable(proto, methodName, humanName); - proto[methodName].overloadTable[argCount-1] = unboundTypesHandler; - } - - whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - // Replace the initial unbound-types-handler stub with the proper - // function. If multiple overloads are registered, the function handlers - // go into an overload table. - var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */); - var func = craftInvokerFunction(humanName, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn); - if (undefined === proto[methodName].overloadTable) { - func.argCount = argCount-1; - proto[methodName] = func; - } else { - proto[methodName].overloadTable[argCount-1] = func; - } - return []; - }); - return []; - }); - } - - function __embind_register_class_constructor( - rawClassType, - argCount, - rawArgTypesAddr, - invokerSignature, - invoker, - rawConstructor - ) { - assert(argCount > 0); - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - invoker = embind__requireFunction(invokerSignature, invoker); - var args = [rawConstructor]; - var destructors = []; - - whenDependentTypesAreResolved([], [rawClassType], function(classType) { - classType = classType[0]; - var humanName = 'constructor ' + classType.name; - - if (undefined === classType.registeredClass.constructor_body) { - classType.registeredClass.constructor_body = []; - } - if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { - throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount-1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); - } - classType.registeredClass.constructor_body[argCount - 1] = () => { - throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes); - }; - - whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - // Insert empty slot for context type (argTypes[1]). - argTypes.splice(1, 0, null); - classType.registeredClass.constructor_body[argCount - 1] = craftInvokerFunction(humanName, argTypes, null, invoker, rawConstructor); - return []; - }); - return []; - }); - } - - function __embind_register_class_function(rawClassType, - methodName, - argCount, - rawArgTypesAddr, // [ReturnType, ThisType, Args...] - invokerSignature, - rawInvoker, - context, - isPureVirtual) { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - methodName = readLatin1String(methodName); - rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); - - whenDependentTypesAreResolved([], [rawClassType], function(classType) { - classType = classType[0]; - var humanName = classType.name + '.' + methodName; - - if (methodName.startsWith("@@")) { - methodName = Symbol[methodName.substring(2)]; - } - - if (isPureVirtual) { - classType.registeredClass.pureVirtualFunctions.push(methodName); - } - - function unboundTypesHandler() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); - } - - var proto = classType.registeredClass.instancePrototype; - var method = proto[methodName]; - if (undefined === method || (undefined === method.overloadTable && method.className !== classType.name && method.argCount === argCount - 2)) { - // This is the first overload to be registered, OR we are replacing a - // function in the base class with a function in the derived class. - unboundTypesHandler.argCount = argCount - 2; - unboundTypesHandler.className = classType.name; - proto[methodName] = unboundTypesHandler; - } else { - // There was an existing function with the same name registered. Set up - // a function overload routing table. - ensureOverloadTable(proto, methodName, humanName); - proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; - } - - whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context); - - // Replace the initial unbound-handler-stub function with the appropriate member function, now that all types - // are resolved. If multiple overloads are registered for this function, the function goes into an overload table. - if (undefined === proto[methodName].overloadTable) { - // Set argCount in case an overload is registered later - memberFunction.argCount = argCount - 2; - proto[methodName] = memberFunction; - } else { - proto[methodName].overloadTable[argCount - 2] = memberFunction; - } - - return []; - }); - return []; - }); - } - - function __embind_register_constant(name, type, value) { - name = readLatin1String(name); - whenDependentTypesAreResolved([], [type], function(type) { - type = type[0]; - Module[name] = type['fromWireType'](value); - return []; - }); - } - - var emval_free_list = []; - - var emval_handle_array = [{},{value:undefined},{value:null},{value:true},{value:false}]; - function __emval_decref(handle) { - if (handle > 4 && 0 === --emval_handle_array[handle].refcount) { - emval_handle_array[handle] = undefined; - emval_free_list.push(handle); - } - } - - function count_emval_handles() { - var count = 0; - for (var i = 5; i < emval_handle_array.length; ++i) { - if (emval_handle_array[i] !== undefined) { - ++count; - } - } - return count; - } - - function get_first_emval() { - for (var i = 5; i < emval_handle_array.length; ++i) { - if (emval_handle_array[i] !== undefined) { - return emval_handle_array[i]; - } - } - return null; - } - function init_emval() { - Module['count_emval_handles'] = count_emval_handles; - Module['get_first_emval'] = get_first_emval; - } - var Emval = {toValue:(handle) => { - if (!handle) { - throwBindingError('Cannot use deleted val. handle = ' + handle); - } - return emval_handle_array[handle].value; - },toHandle:(value) => { - switch (value) { - case undefined: return 1; - case null: return 2; - case true: return 3; - case false: return 4; - default:{ - var handle = emval_free_list.length ? - emval_free_list.pop() : - emval_handle_array.length; - - emval_handle_array[handle] = {refcount: 1, value: value}; - return handle; - } - } - }}; - function __embind_register_emval(rawType, name) { - name = readLatin1String(name); - registerType(rawType, { - name: name, - 'fromWireType': function(handle) { - var rv = Emval.toValue(handle); - __emval_decref(handle); - return rv; - }, - 'toWireType': function(destructors, value) { - return Emval.toHandle(value); - }, - 'argPackAdvance': 8, - 'readValueFromPointer': simpleReadValueFromPointer, - destructorFunction: null, // This type does not need a destructor - - // TODO: do we need a deleteObject here? write a test where - // emval is passed into JS via an interface - }); - } - - function enumReadValueFromPointer(name, shift, signed) { - switch (shift) { - case 0: return function(pointer) { - var heap = signed ? HEAP8 : HEAPU8; - return this['fromWireType'](heap[pointer]); - }; - case 1: return function(pointer) { - var heap = signed ? HEAP16 : HEAPU16; - return this['fromWireType'](heap[pointer >> 1]); - }; - case 2: return function(pointer) { - var heap = signed ? HEAP32 : HEAPU32; - return this['fromWireType'](heap[pointer >> 2]); - }; - default: - throw new TypeError("Unknown integer type: " + name); - } - } - function __embind_register_enum(rawType, name, size, isSigned) { - var shift = getShiftFromSize(size); - name = readLatin1String(name); - - function ctor() {} - ctor.values = {}; - - registerType(rawType, { - name: name, - constructor: ctor, - 'fromWireType': function(c) { - return this.constructor.values[c]; - }, - 'toWireType': function(destructors, c) { - return c.value; - }, - 'argPackAdvance': 8, - 'readValueFromPointer': enumReadValueFromPointer(name, shift, isSigned), - destructorFunction: null, - }); - exposePublicSymbol(name, ctor); - } - - function requireRegisteredType(rawType, humanName) { - var impl = registeredTypes[rawType]; - if (undefined === impl) { - throwBindingError(humanName + " has unknown type " + getTypeName(rawType)); - } - return impl; - } - function __embind_register_enum_value(rawEnumType, name, enumValue) { - var enumType = requireRegisteredType(rawEnumType, 'enum'); - name = readLatin1String(name); - - var Enum = enumType.constructor; - - var Value = Object.create(enumType.constructor.prototype, { - value: {value: enumValue}, - constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, - }); - Enum.values[enumValue] = Value; - Enum[name] = Value; - } - - function embindRepr(v) { - if (v === null) { - return 'null'; - } - var t = typeof v; - if (t === 'object' || t === 'array' || t === 'function') { - return v.toString(); - } else { - return '' + v; - } - } - - function floatReadValueFromPointer(name, shift) { - switch (shift) { - case 2: return function(pointer) { - return this['fromWireType'](HEAPF32[pointer >> 2]); - }; - case 3: return function(pointer) { - return this['fromWireType'](HEAPF64[pointer >> 3]); - }; - default: - throw new TypeError("Unknown float type: " + name); - } - } - function __embind_register_float(rawType, name, size) { - var shift = getShiftFromSize(size); - name = readLatin1String(name); - registerType(rawType, { - name: name, - 'fromWireType': function(value) { - return value; - }, - 'toWireType': function(destructors, value) { - if (typeof value != "number" && typeof value != "boolean") { - throw new TypeError('Cannot convert "' + embindRepr(value) + '" to ' + this.name); - } - // The VM will perform JS to Wasm value conversion, according to the spec: - // https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue - return value; - }, - 'argPackAdvance': 8, - 'readValueFromPointer': floatReadValueFromPointer(name, shift), - destructorFunction: null, // This type does not need a destructor - }); - } - function __embind_register_function(name, argCount, rawArgTypesAddr, signature, rawInvoker, fn) { var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = readLatin1String(name); @@ -3649,43 +2636,6 @@ var ASM_CONSTS = { }); } - function __embind_register_smart_ptr(rawType, - rawPointeeType, - name, - sharingPolicy, - getPointeeSignature, - rawGetPointee, - constructorSignature, - rawConstructor, - shareSignature, - rawShare, - destructorSignature, - rawDestructor) { - name = readLatin1String(name); - rawGetPointee = embind__requireFunction(getPointeeSignature, rawGetPointee); - rawConstructor = embind__requireFunction(constructorSignature, rawConstructor); - rawShare = embind__requireFunction(shareSignature, rawShare); - rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); - - whenDependentTypesAreResolved([rawType], [rawPointeeType], function(pointeeType) { - pointeeType = pointeeType[0]; - - var registeredPointer = new RegisteredPointer(name, - pointeeType.registeredClass, - false, - false, - // smart pointer properties - true, - pointeeType, - sharingPolicy, - rawGetPointee, - rawConstructor, - rawShare, - rawDestructor); - return [registeredPointer]; - }); - } - function __embind_register_std_string(rawType, name) { name = readLatin1String(name); var stdStringIsUTF8 @@ -3847,45 +2797,6 @@ var ASM_CONSTS = { }); } - function __embind_register_value_object( - rawType, - name, - constructorSignature, - rawConstructor, - destructorSignature, - rawDestructor - ) { - structRegistrations[rawType] = { - name: readLatin1String(name), - rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), - rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), - fields: [], - }; - } - - function __embind_register_value_object_field( - structType, - fieldName, - getterReturnType, - getterSignature, - getter, - getterContext, - setterArgumentType, - setterSignature, - setter, - setterContext - ) { - structRegistrations[structType].fields.push({ - fieldName: readLatin1String(fieldName), - getterReturnType: getterReturnType, - getter: embind__requireFunction(getterSignature, getter), - getterContext: getterContext, - setterArgumentType: setterArgumentType, - setter: embind__requireFunction(setterSignature, setter), - setterContext: setterContext, - }); - } - function __embind_register_void(rawType, name) { name = readLatin1String(name); registerType(rawType, { @@ -3913,189 +2824,6 @@ var ASM_CONSTS = { function __emscripten_throw_longjmp() { throw Infinity; } - function emval_allocateDestructors(destructorsRef) { - var destructors = []; - HEAPU32[((destructorsRef)>>2)] = Emval.toHandle(destructors); - return destructors; - } - - var emval_symbols = {}; - function getStringOrSymbol(address) { - var symbol = emval_symbols[address]; - if (symbol === undefined) { - return readLatin1String(address); - } - return symbol; - } - - var emval_methodCallers = []; - function __emval_call_method(caller, handle, methodName, destructorsRef, args) { - caller = emval_methodCallers[caller]; - handle = Emval.toValue(handle); - methodName = getStringOrSymbol(methodName); - return caller(handle, methodName, emval_allocateDestructors(destructorsRef), args); - } - - function __emval_call_void_method(caller, handle, methodName, args) { - caller = emval_methodCallers[caller]; - handle = Emval.toValue(handle); - methodName = getStringOrSymbol(methodName); - caller(handle, methodName, null, args); - } - - - function emval_get_global() { - if (typeof globalThis == 'object') { - return globalThis; - } - function testGlobal(obj) { - obj['$$$embind_global$$$'] = obj; - var success = typeof $$$embind_global$$$ == 'object' && obj['$$$embind_global$$$'] == obj; - if (!success) { - delete obj['$$$embind_global$$$']; - } - return success; - } - if (typeof $$$embind_global$$$ == 'object') { - return $$$embind_global$$$; - } - if (typeof global == 'object' && testGlobal(global)) { - $$$embind_global$$$ = global; - } else if (typeof self == 'object' && testGlobal(self)) { - $$$embind_global$$$ = self; // This works for both "window" and "self" (Web Workers) global objects - } - if (typeof $$$embind_global$$$ == 'object') { - return $$$embind_global$$$; - } - throw Error('unable to get global object.'); - } - function __emval_get_global(name) { - if (name===0) { - return Emval.toHandle(emval_get_global()); - } else { - name = getStringOrSymbol(name); - return Emval.toHandle(emval_get_global()[name]); - } - } - - function emval_addMethodCaller(caller) { - var id = emval_methodCallers.length; - emval_methodCallers.push(caller); - return id; - } - - function emval_lookupTypes(argCount, argTypes) { - var a = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - a[i] = requireRegisteredType(HEAPU32[(((argTypes)+(i * POINTER_SIZE))>>2)], - "parameter " + i); - } - return a; - } - - var emval_registeredMethods = []; - function __emval_get_method_caller(argCount, argTypes) { - var types = emval_lookupTypes(argCount, argTypes); - var retType = types[0]; - var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; - var returnId = emval_registeredMethods[signatureName]; - if (returnId !== undefined) { - return returnId; - } - - var argN = new Array(argCount - 1); - var invokerFunction = (handle, name, destructors, args) => { - var offset = 0; - for (var i = 0; i < argCount - 1; ++i) { - argN[i] = types[i + 1]['readValueFromPointer'](args + offset); - offset += types[i + 1]['argPackAdvance']; - } - var rv = handle[name].apply(handle, argN); - for (var i = 0; i < argCount - 1; ++i) { - if (types[i + 1].deleteObject) { - types[i + 1].deleteObject(argN[i]); - } - } - if (!retType.isVoid) { - return retType['toWireType'](destructors, rv); - } - }; - returnId = emval_addMethodCaller(invokerFunction); - emval_registeredMethods[signatureName] = returnId; - return returnId; - } - - function __emval_incref(handle) { - if (handle > 4) { - emval_handle_array[handle].refcount += 1; - } - } - - function craftEmvalAllocator(argCount) { - /*This function returns a new function that looks like this: - function emval_allocator_3(constructor, argTypes, args) { - var argType0 = requireRegisteredType(HEAP32[(argTypes >> 2)], "parameter 0"); - var arg0 = argType0['readValueFromPointer'](args); - var argType1 = requireRegisteredType(HEAP32[(argTypes >> 2) + 1], "parameter 1"); - var arg1 = argType1['readValueFromPointer'](args + 8); - var argType2 = requireRegisteredType(HEAP32[(argTypes >> 2) + 2], "parameter 2"); - var arg2 = argType2['readValueFromPointer'](args + 16); - var obj = new constructor(arg0, arg1, arg2); - return Emval.toHandle(obj); - } */ - var argsList = new Array(argCount + 1); - return function(constructor, argTypes, args) { - argsList[0] = constructor; - for (var i = 0; i < argCount; ++i) { - var argType = requireRegisteredType(HEAPU32[(((argTypes)+(i * POINTER_SIZE))>>2)], 'parameter ' + i); - argsList[i + 1] = argType['readValueFromPointer'](args); - args += argType['argPackAdvance']; - } - var obj = new (constructor.bind.apply(constructor, argsList)); - return Emval.toHandle(obj); - }; - } - - var emval_newers = {}; - function __emval_new(handle, argCount, argTypes, args) { - handle = Emval.toValue(handle); - - var newer = emval_newers[argCount]; - if (!newer) { - newer = craftEmvalAllocator(argCount); - emval_newers[argCount] = newer; - } - - return newer(handle, argTypes, args); - } - - function __emval_new_cstring(v) { - return Emval.toHandle(getStringOrSymbol(v)); - } - - function __emval_new_object() { - return Emval.toHandle({}); - } - - function __emval_run_destructors(handle) { - var destructors = Emval.toValue(handle); - runDestructors(destructors); - __emval_decref(handle); - } - - function __emval_set_property(handle, key, value) { - handle = Emval.toValue(handle); - key = Emval.toValue(key); - value = Emval.toValue(value); - handle[key] = value; - } - - function __emval_take_value(type, arg) { - type = requireRegisteredType(type, '_emval_take_value'); - var v = type['readValueFromPointer'](arg); - return Emval.toHandle(v); - } - function __mmap_js(len, prot, flags, fd, off, allocated) { return -52; } @@ -5780,6 +4508,624 @@ var ASM_CONSTS = { GLctx.waitSync(GL.syncs[sync], flags, convertI32PairToI53(timeoutLo, timeoutHi)); } + function reallyNegative(x) { + return x < 0 || (x === 0 && (1/x) === -Infinity); + } + + function convertU32PairToI53(lo, hi) { + return (lo >>> 0) + (hi >>> 0) * 4294967296; + } + + function reSign(value, bits) { + if (value <= 0) { + return value; + } + var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32 + : Math.pow(2, bits-1); + // for huge values, we can hit the precision limit and always get true here. + // so don't do that but, in general there is no perfect solution here. With + // 64-bit ints, we get rounding and errors + // TODO: In i64 mode 1, resign the two parts separately and safely + if (value >= half && (bits <= 32 || value > half)) { + // Cannot bitshift half, as it may be at the limit of the bits JS uses in + // bitshifts + value = -2*half + value; + } + return value; + } + + function unSign(value, bits) { + if (value >= 0) { + return value; + } + // Need some trickery, since if bits == 32, we are right at the limit of the + // bits JS uses in bitshifts + return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value + : Math.pow(2, bits) + value; + } + + function strLen(ptr) { + var end = ptr; + while (HEAPU8[end]) ++end; + return end - ptr; + } + function formatString(format, varargs) { + assert((varargs & 3) === 0); + var textIndex = format; + var argIndex = varargs; + // This must be called before reading a double or i64 vararg. It will bump the pointer properly. + // It also does an assert on i32 values, so it's nice to call it before all varargs calls. + function prepVararg(ptr, type) { + if (type === 'double' || type === 'i64') { + // move so the load is aligned + if (ptr & 7) { + assert((ptr & 7) === 4); + ptr += 4; + } + } else { + assert((ptr & 3) === 0); + } + return ptr; + } + function getNextArg(type) { + // NOTE: Explicitly ignoring type safety. Otherwise this fails: + // int x = 4; printf("%c\n", (char)x); + var ret; + argIndex = prepVararg(argIndex, type); + if (type === 'double') { + ret = HEAPF64[((argIndex)>>3)]; + argIndex += 8; + } else if (type == 'i64') { + ret = [HEAP32[((argIndex)>>2)], + HEAP32[(((argIndex)+(4))>>2)]]; + argIndex += 8; + } else { + assert((argIndex & 3) === 0); + type = 'i32'; // varargs are always i32, i64, or double + ret = HEAP32[((argIndex)>>2)]; + argIndex += 4; + } + return ret; + } + + var ret = []; + var curr, next, currArg; + while (1) { + var startTextIndex = textIndex; + curr = HEAP8[((textIndex)>>0)]; + if (curr === 0) break; + next = HEAP8[((textIndex+1)>>0)]; + if (curr == 37) { + // Handle flags. + var flagAlwaysSigned = false; + var flagLeftAlign = false; + var flagAlternative = false; + var flagZeroPad = false; + var flagPadSign = false; + flagsLoop: while (1) { + switch (next) { + case 43: + flagAlwaysSigned = true; + break; + case 45: + flagLeftAlign = true; + break; + case 35: + flagAlternative = true; + break; + case 48: + if (flagZeroPad) { + break flagsLoop; + } else { + flagZeroPad = true; + break; + } + case 32: + flagPadSign = true; + break; + default: + break flagsLoop; + } + textIndex++; + next = HEAP8[((textIndex+1)>>0)]; + } + + // Handle width. + var width = 0; + if (next == 42) { + width = getNextArg('i32'); + textIndex++; + next = HEAP8[((textIndex+1)>>0)]; + } else { + while (next >= 48 && next <= 57) { + width = width * 10 + (next - 48); + textIndex++; + next = HEAP8[((textIndex+1)>>0)]; + } + } + + // Handle precision. + var precisionSet = false, precision = -1; + if (next == 46) { + precision = 0; + precisionSet = true; + textIndex++; + next = HEAP8[((textIndex+1)>>0)]; + if (next == 42) { + precision = getNextArg('i32'); + textIndex++; + } else { + while (1) { + var precisionChr = HEAP8[((textIndex+1)>>0)]; + if (precisionChr < 48 || + precisionChr > 57) break; + precision = precision * 10 + (precisionChr - 48); + textIndex++; + } + } + next = HEAP8[((textIndex+1)>>0)]; + } + if (precision < 0) { + precision = 6; // Standard default. + precisionSet = false; + } + + // Handle integer sizes. WARNING: These assume a 32-bit architecture! + var argSize; + switch (String.fromCharCode(next)) { + case 'h': + var nextNext = HEAP8[((textIndex+2)>>0)]; + if (nextNext == 104) { + textIndex++; + argSize = 1; // char (actually i32 in varargs) + } else { + argSize = 2; // short (actually i32 in varargs) + } + break; + case 'l': + var nextNext = HEAP8[((textIndex+2)>>0)]; + if (nextNext == 108) { + textIndex++; + argSize = 8; // long long + } else { + argSize = 4; // long + } + break; + case 'L': // long long + case 'q': // int64_t + case 'j': // intmax_t + argSize = 8; + break; + case 'z': // size_t + case 't': // ptrdiff_t + case 'I': // signed ptrdiff_t or unsigned size_t + argSize = 4; + break; + default: + argSize = null; + } + if (argSize) textIndex++; + next = HEAP8[((textIndex+1)>>0)]; + + // Handle type specifier. + switch (String.fromCharCode(next)) { + case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': { + // Integer. + var signed = next == 100 || next == 105; + argSize = argSize || 4; + currArg = getNextArg('i' + (argSize * 8)); + var argText; + // Flatten i64-1 [low, high] into a (slightly rounded) double + if (argSize == 8) { + currArg = next == 117 ? convertU32PairToI53(currArg[0], currArg[1]) : convertI32PairToI53(currArg[0], currArg[1]); + } + // Truncate to requested size. + if (argSize <= 4) { + var limit = Math.pow(256, argSize) - 1; + currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8); + } + // Format the number. + var currAbsArg = Math.abs(currArg); + var prefix = ''; + if (next == 100 || next == 105) { + argText = reSign(currArg, 8 * argSize).toString(10); + } else if (next == 117) { + argText = unSign(currArg, 8 * argSize).toString(10); + currArg = Math.abs(currArg); + } else if (next == 111) { + argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8); + } else if (next == 120 || next == 88) { + prefix = (flagAlternative && currArg != 0) ? '0x' : ''; + if (currArg < 0) { + // Represent negative numbers in hex as 2's complement. + currArg = -currArg; + argText = (currAbsArg - 1).toString(16); + var buffer = []; + for (var i = 0; i < argText.length; i++) { + buffer.push((0xF - parseInt(argText[i], 16)).toString(16)); + } + argText = buffer.join(''); + while (argText.length < argSize * 2) argText = 'f' + argText; + } else { + argText = currAbsArg.toString(16); + } + if (next == 88) { + prefix = prefix.toUpperCase(); + argText = argText.toUpperCase(); + } + } else if (next == 112) { + if (currAbsArg === 0) { + argText = '(nil)'; + } else { + prefix = '0x'; + argText = currAbsArg.toString(16); + } + } + if (precisionSet) { + while (argText.length < precision) { + argText = '0' + argText; + } + } + + // Add sign if needed + if (currArg >= 0) { + if (flagAlwaysSigned) { + prefix = '+' + prefix; + } else if (flagPadSign) { + prefix = ' ' + prefix; + } + } + + // Move sign to prefix so we zero-pad after the sign + if (argText.charAt(0) == '-') { + prefix = '-' + prefix; + argText = argText.substr(1); + } + + // Add padding. + while (prefix.length + argText.length < width) { + if (flagLeftAlign) { + argText += ' '; + } else { + if (flagZeroPad) { + argText = '0' + argText; + } else { + prefix = ' ' + prefix; + } + } + } + + // Insert the result into the buffer. + argText = prefix + argText; + argText.split('').forEach(function(chr) { + ret.push(chr.charCodeAt(0)); + }); + break; + } + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': { + // Float. + currArg = getNextArg('double'); + var argText; + if (isNaN(currArg)) { + argText = 'nan'; + flagZeroPad = false; + } else if (!isFinite(currArg)) { + argText = (currArg < 0 ? '-' : '') + 'inf'; + flagZeroPad = false; + } else { + var isGeneral = false; + var effectivePrecision = Math.min(precision, 20); + + // Convert g/G to f/F or e/E, as per: + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html + if (next == 103 || next == 71) { + isGeneral = true; + precision = precision || 1; + var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10); + if (precision > exponent && exponent >= -4) { + next = ((next == 103) ? 'f' : 'F').charCodeAt(0); + precision -= exponent + 1; + } else { + next = ((next == 103) ? 'e' : 'E').charCodeAt(0); + precision--; + } + effectivePrecision = Math.min(precision, 20); + } + + if (next == 101 || next == 69) { + argText = currArg.toExponential(effectivePrecision); + // Make sure the exponent has at least 2 digits. + if (/[eE][-+]\d$/.test(argText)) { + argText = argText.slice(0, -1) + '0' + argText.slice(-1); + } + } else if (next == 102 || next == 70) { + argText = currArg.toFixed(effectivePrecision); + if (currArg === 0 && reallyNegative(currArg)) { + argText = '-' + argText; + } + } + + var parts = argText.split('e'); + if (isGeneral && !flagAlternative) { + // Discard trailing zeros and periods. + while (parts[0].length > 1 && parts[0].includes('.') && + (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) { + parts[0] = parts[0].slice(0, -1); + } + } else { + // Make sure we have a period in alternative mode. + if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.'; + // Zero pad until required precision. + while (precision > effectivePrecision++) parts[0] += '0'; + } + argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : ''); + + // Capitalize 'E' if needed. + if (next == 69) argText = argText.toUpperCase(); + + // Add sign. + if (currArg >= 0) { + if (flagAlwaysSigned) { + argText = '+' + argText; + } else if (flagPadSign) { + argText = ' ' + argText; + } + } + } + + // Add padding. + while (argText.length < width) { + if (flagLeftAlign) { + argText += ' '; + } else { + if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) { + argText = argText[0] + '0' + argText.slice(1); + } else { + argText = (flagZeroPad ? '0' : ' ') + argText; + } + } + } + + // Adjust case. + if (next < 97) argText = argText.toUpperCase(); + + // Insert the result into the buffer. + argText.split('').forEach(function(chr) { + ret.push(chr.charCodeAt(0)); + }); + break; + } + case 's': { + // String. + var arg = getNextArg('i8*'); + var argLength = arg ? strLen(arg) : '(null)'.length; + if (precisionSet) argLength = Math.min(argLength, precision); + if (!flagLeftAlign) { + while (argLength < width--) { + ret.push(32); + } + } + if (arg) { + for (var i = 0; i < argLength; i++) { + ret.push(HEAPU8[((arg++)>>0)]); + } + } else { + ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true)); + } + if (flagLeftAlign) { + while (argLength < width--) { + ret.push(32); + } + } + break; + } + case 'c': { + // Character. + if (flagLeftAlign) ret.push(getNextArg('i8')); + while (--width > 0) { + ret.push(32); + } + if (!flagLeftAlign) ret.push(getNextArg('i8')); + break; + } + case 'n': { + // Write the length written so far to the next parameter. + var ptr = getNextArg('i32*'); + HEAP32[((ptr)>>2)] = ret.length; + break; + } + case '%': { + // Literal percent sign. + ret.push(curr); + break; + } + default: { + // Unknown specifiers remain untouched. + for (var i = startTextIndex; i < textIndex + 2; i++) { + ret.push(HEAP8[((i)>>0)]); + } + } + } + textIndex += 2; + // TODO: Support a/A (hex float) and m (last error) specifiers. + // TODO: Support %1${specifier} for arg selection. + } else { + ret.push(curr); + textIndex += 1; + } + } + return ret; + } + + function traverseStack(args) { + if (!args || !args.callee || !args.callee.name) { + return [null, '', '']; + } + + var funstr = args.callee.toString(); + var funcname = args.callee.name; + var str = '('; + var first = true; + for (var i in args) { + var a = args[i]; + if (!first) { + str += ", "; + } + first = false; + if (typeof a == 'number' || typeof a == 'string') { + str += a; + } else { + str += '(' + typeof a + ')'; + } + } + str += ')'; + var caller = args.callee.caller; + args = caller ? caller.arguments : []; + if (first) + str = ''; + return [args, funcname, str]; + } + /** @param {number=} flags */ + function _emscripten_get_callstack_js(flags) { + var callstack = jsStackTrace(); + + // Find the symbols in the callstack that corresponds to the functions that + // report callstack information, and remove everything up to these from the + // output. + var iThisFunc = callstack.lastIndexOf('_emscripten_log'); + var iThisFunc2 = callstack.lastIndexOf('_emscripten_get_callstack'); + var iNextLine = callstack.indexOf('\n', Math.max(iThisFunc, iThisFunc2))+1; + callstack = callstack.slice(iNextLine); + + if (flags & 32) { + warnOnce('EM_LOG_DEMANGLE is deprecated; ignoring'); + } + + // If user requested to see the original source stack, but no source map + // information is available, just fall back to showing the JS stack. + if (flags & 8 && typeof emscripten_source_map == 'undefined') { + warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.'); + flags ^= 8; + flags |= 16; + } + + var stack_args = null; + if (flags & 128) { + // To get the actual parameters to the functions, traverse the stack via + // the unfortunately deprecated 'arguments.callee' method, if it works: + stack_args = traverseStack(arguments); + while (stack_args[1].includes('_emscripten_')) + stack_args = traverseStack(stack_args[0]); + } + + // Process all lines: + var lines = callstack.split('\n'); + callstack = ''; + // New FF30 with column info: extract components of form: + // ' Object._main@http://server.com:4324:12' + var newFirefoxRe = new RegExp('\\s*(.*?)@(.*?):([0-9]+):([0-9]+)'); + // Old FF without column info: extract components of form: + // ' Object._main@http://server.com:4324' + var firefoxRe = new RegExp('\\s*(.*?)@(.*):(.*)(:(.*))?'); + // Extract components of form: + // ' at Object._main (http://server.com/file.html:4324:12)' + var chromeRe = new RegExp('\\s*at (.*?) \\\((.*):(.*):(.*)\\\)'); + + for (var l in lines) { + var line = lines[l]; + + var symbolName = ''; + var file = ''; + var lineno = 0; + var column = 0; + + var parts = chromeRe.exec(line); + if (parts && parts.length == 5) { + symbolName = parts[1]; + file = parts[2]; + lineno = parts[3]; + column = parts[4]; + } else { + parts = newFirefoxRe.exec(line); + if (!parts) parts = firefoxRe.exec(line); + if (parts && parts.length >= 4) { + symbolName = parts[1]; + file = parts[2]; + lineno = parts[3]; + // Old Firefox doesn't carry column information, but in new FF30, it + // is present. See https://bugzilla.mozilla.org/show_bug.cgi?id=762556 + column = parts[4]|0; + } else { + // Was not able to extract this line for demangling/sourcemapping + // purposes. Output it as-is. + callstack += line + '\n'; + continue; + } + } + + var haveSourceMap = false; + + if (flags & 8) { + var orig = emscripten_source_map.originalPositionFor({line: lineno, column: column}); + haveSourceMap = (orig && orig.source); + if (haveSourceMap) { + if (flags & 64) { + orig.source = orig.source.substring(orig.source.replace(/\\/g, "/").lastIndexOf('/')+1); + } + callstack += ' at ' + symbolName + ' (' + orig.source + ':' + orig.line + ':' + orig.column + ')\n'; + } + } + if ((flags & 16) || !haveSourceMap) { + if (flags & 64) { + file = file.substring(file.replace(/\\/g, "/").lastIndexOf('/')+1); + } + callstack += (haveSourceMap ? (' = ' + symbolName) : (' at '+ symbolName)) + ' (' + file + ':' + lineno + ':' + column + ')\n'; + } + + // If we are still keeping track with the callstack by traversing via + // 'arguments.callee', print the function parameters as well. + if (flags & 128 && stack_args[0]) { + if (stack_args[1] == symbolName && stack_args[2].length > 0) { + callstack = callstack.replace(/\s+$/, ''); + callstack += ' with values: ' + stack_args[1] + stack_args[2] + '\n'; + } + stack_args = traverseStack(stack_args[0]); + } + } + // Trim extra whitespace at the end of the output. + callstack = callstack.replace(/\s+$/, ''); + return callstack; + } + function _emscripten_log_js(flags, str) { + if (flags & 24) { + str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline. + str += (str.length > 0 ? '\n' : '') + _emscripten_get_callstack_js(flags); + } + + if (flags & 1) { + if (flags & 4) { + console.error(str); + } else if (flags & 2) { + console.warn(str); + } else if (flags & 512) { + console.info(str); + } else if (flags & 256) { + console.debug(str); + } else { + console.log(str); + } + } else if (flags & 6) { + err(str); + } else { + out(str); + } + } + function _emscripten_log(flags, format, varargs) { + var result = formatString(format, varargs); + var str = UTF8ArrayToString(result, 0); + _emscripten_log_js(flags, str); + } + function _emscripten_memcpy_big(dest, src, num) { HEAPU8.copyWithin(dest, src, src + num); } @@ -5858,14 +5204,6 @@ var ASM_CONSTS = { return false; } - function _emscripten_webgl_do_get_current_context() { - return GL.currentContext ? GL.currentContext.handle : 0; - } - function _emscripten_webgl_get_current_context( - ) { - return _emscripten_webgl_do_get_current_context(); - } - var ENV = {}; function getExecutableName() { @@ -6323,14 +5661,11 @@ var ASM_CONSTS = { function _strftime_l(s, maxsize, format, tm) { return _strftime(s, maxsize, format, tm); // no locale support yet } -InternalError = Module['InternalError'] = extendError(Error, 'InternalError');; embind_init_charCodes(); BindingError = Module['BindingError'] = extendError(Error, 'BindingError');; -init_ClassHandle(); -init_embind();; -init_RegisteredPointer(); -UnboundTypeError = Module['UnboundTypeError'] = extendError(Error, 'UnboundTypeError');; +InternalError = Module['InternalError'] = extendError(Error, 'InternalError');; init_emval();; +UnboundTypeError = Module['UnboundTypeError'] = extendError(Error, 'UnboundTypeError');; var GLctx;; for (var i = 0; i < 32; ++i) tempFixedLengthArray.push(new Array(i));; var miniTempWebGLFloatBuffersStorage = new Float32Array(288); @@ -6385,42 +5720,19 @@ var asmLibraryArg = { "__syscall_newfstatat": ___syscall_newfstatat, "__syscall_openat": ___syscall_openat, "__syscall_stat64": ___syscall_stat64, - "_embind_finalize_value_object": __embind_finalize_value_object, "_embind_register_bigint": __embind_register_bigint, "_embind_register_bool": __embind_register_bool, - "_embind_register_class": __embind_register_class, - "_embind_register_class_class_function": __embind_register_class_class_function, - "_embind_register_class_constructor": __embind_register_class_constructor, - "_embind_register_class_function": __embind_register_class_function, - "_embind_register_constant": __embind_register_constant, "_embind_register_emval": __embind_register_emval, - "_embind_register_enum": __embind_register_enum, - "_embind_register_enum_value": __embind_register_enum_value, "_embind_register_float": __embind_register_float, "_embind_register_function": __embind_register_function, "_embind_register_integer": __embind_register_integer, "_embind_register_memory_view": __embind_register_memory_view, - "_embind_register_smart_ptr": __embind_register_smart_ptr, "_embind_register_std_string": __embind_register_std_string, "_embind_register_std_wstring": __embind_register_std_wstring, - "_embind_register_value_object": __embind_register_value_object, - "_embind_register_value_object_field": __embind_register_value_object_field, "_embind_register_void": __embind_register_void, "_emscripten_date_now": __emscripten_date_now, "_emscripten_get_now_is_monotonic": __emscripten_get_now_is_monotonic, "_emscripten_throw_longjmp": __emscripten_throw_longjmp, - "_emval_call_method": __emval_call_method, - "_emval_call_void_method": __emval_call_void_method, - "_emval_decref": __emval_decref, - "_emval_get_global": __emval_get_global, - "_emval_get_method_caller": __emval_get_method_caller, - "_emval_incref": __emval_incref, - "_emval_new": __emval_new, - "_emval_new_cstring": __emval_new_cstring, - "_emval_new_object": __emval_new_object, - "_emval_run_destructors": __emval_run_destructors, - "_emval_set_property": __emval_set_property, - "_emval_take_value": __emval_take_value, "_mmap_js": __mmap_js, "_munmap_js": __munmap_js, "abort": _abort, @@ -6566,9 +5878,9 @@ var asmLibraryArg = { "emscripten_glVertexAttribPointer": _emscripten_glVertexAttribPointer, "emscripten_glViewport": _emscripten_glViewport, "emscripten_glWaitSync": _emscripten_glWaitSync, + "emscripten_log": _emscripten_log, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, - "emscripten_webgl_get_current_context": _emscripten_webgl_get_current_context, "environ_get": _environ_get, "environ_sizes_get": _environ_sizes_get, "exit": _exit, @@ -6615,9 +5927,6 @@ var _fflush = Module["_fflush"] = createExportWrapper("fflush"); /** @type {function(...*):?} */ var _saveSetjmp = Module["_saveSetjmp"] = createExportWrapper("saveSetjmp"); -/** @type {function(...*):?} */ -var _add = Module["_add"] = createExportWrapper("add"); - /** @type {function(...*):?} */ var ___getTypeName = Module["___getTypeName"] = createExportWrapper("__getTypeName"); @@ -6704,9 +6013,6 @@ var dynCall_jii = Module["dynCall_jii"] = createExportWrapper("dynCall_jii"); /** @type {function(...*):?} */ var dynCall_iij = Module["dynCall_iij"] = createExportWrapper("dynCall_iij"); -/** @type {function(...*):?} */ -var dynCall_jiiiii = Module["dynCall_jiiiii"] = createExportWrapper("dynCall_jiiiii"); - /** @type {function(...*):?} */ var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji");