summaryrefslogtreecommitdiff
path: root/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd
diff options
context:
space:
mode:
Diffstat (limited to 'content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd')
-rw-r--r--content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd232
1 files changed, 232 insertions, 0 deletions
diff --git a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd
new file mode 100644
index 000000000..5acf75000
--- /dev/null
+++ b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd
@@ -0,0 +1,232 @@
+/* HTML canvas element rendering context binding using duktape and libdom
+ *
+ * Copyright 2020 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * Released under the terms of the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ */
+
+class CanvasRenderingContext2D {
+ private struct dom_html_element *canvas;
+ private struct bitmap *bitmap;
+ private int width;
+ private int height;
+ private size_t stride;
+ prologue %{
+/* prologue */
+#include "desktop/gui_internal.h"
+#include "desktop/gui_table.h"
+#include "netsurf/bitmap.h"
+#include "utils/corestrings.h"
+/* It's a smidge naughty of us to read
+ * this particular header, but we're needing
+ * to redraw the node we represent
+ */
+#include "content/handlers/html/private.h"
+
+static void redraw_node(dom_node *node)
+{
+ struct box *box = NULL;
+ html_content *htmlc = NULL;
+ dom_exception exc;
+ dom_document *doc;
+
+ exc = dom_node_get_user_data(node,
+ corestring_dom___ns_key_box_node_data,
+ &box);
+ if (exc != DOM_NO_ERR || box == NULL) {
+ return;
+ }
+
+ exc = dom_node_get_owner_document(node, &doc);
+ if (exc != DOM_NO_ERR || doc == NULL) {
+ return;
+ }
+
+ exc = dom_node_get_user_data(doc,
+ corestring_dom___ns_key_html_content_data,
+ &htmlc);
+ if (exc != DOM_NO_ERR || htmlc == NULL) {
+ dom_node_unref(doc);
+ return;
+ }
+
+ html__redraw_a_box(htmlc, box);
+
+ dom_node_unref(doc);
+}
+
+/* prologue ends */
+%};
+};
+
+init CanvasRenderingContext2D(struct dom_html_element *canvas)
+%{
+ struct bitmap *bitmap;
+ dom_exception exc;
+
+ assert(canvas != NULL);
+
+ priv->canvas = canvas;
+ dom_node_ref(canvas);
+
+ exc = dom_node_get_user_data(canvas,
+ corestring_dom___ns_key_canvas_node_data,
+ &bitmap);
+ assert(exc == DOM_NO_ERR);
+ assert(bitmap != NULL);
+
+ priv->bitmap = bitmap;
+ priv->width = guit->bitmap->get_width(bitmap);
+ priv->height = guit->bitmap->get_height(bitmap);
+ priv->stride = guit->bitmap->get_rowstride(bitmap);
+%}
+
+fini CanvasRenderingContext2D()
+%{
+ dom_node_unref(priv->canvas);
+%}
+
+getter CanvasRenderingContext2D::canvas()
+%{
+ dukky_push_node(ctx, (dom_node *)priv->canvas);
+ return 1;
+%}
+
+method CanvasRenderingContext2D::createImageData()
+%{
+ /* Can be called either with width and height, or with a reference
+ * imagedata object
+ */
+ image_data_private_t *idpriv;
+ int width, height;
+
+ if (duk_get_top(ctx) == 2) {
+ width = duk_to_int(ctx, 0);
+ height = duk_to_int(ctx, 1);
+ } else if (dukky_instanceof(ctx, 0, PROTO_NAME(IMAGEDATA))) {
+ duk_get_prop_string(ctx, 0, dukky_magic_string_private);
+ idpriv = duk_get_pointer(ctx, -1);
+ width = idpriv->width;
+ height = idpriv->height;
+ duk_pop(ctx);
+ } else {
+ duk_push_null(ctx);
+ return 1;
+ }
+
+ duk_push_int(ctx, width);
+ duk_push_int(ctx, height);
+ if (dukky_create_object(ctx,
+ PROTO_NAME(IMAGEDATA),
+ 2) != DUK_EXEC_SUCCESS) {
+ return duk_error(ctx,
+ DUK_ERR_ERROR,
+ "Unable to create ImageData");
+ }
+ return 1;
+%}
+
+method CanvasRenderingContext2D::getImageData()
+%{
+ /* called with x, y, width, height */
+ int x = duk_get_int(ctx, 0);
+ int y = duk_get_int(ctx, 1);
+ int width = duk_get_int(ctx, 2);
+ int height = duk_get_int(ctx, 3);
+ image_data_private_t *idpriv;
+ uint8_t *bitmap_base;
+
+ if (width < 1 || height < 1 ||
+ (x + width) > priv->width || (y + height) > priv->height) {
+ return duk_error(ctx, DUK_ERR_RANGE_ERROR, "invalid (%d,%d) (%dx%d)", x, y, width, height);
+ }
+
+ duk_push_int(ctx, width);
+ duk_push_int(ctx, height);
+ if (dukky_create_object(ctx,
+ PROTO_NAME(IMAGEDATA),
+ 2) != DUK_EXEC_SUCCESS) {
+ return duk_error(ctx,
+ DUK_ERR_ERROR,
+ "Unable to create ImageData");
+ }
+
+ /* ... imgdata */
+ duk_get_prop_string(ctx, -1, dukky_magic_string_private);
+ idpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ /* We now have access to the imagedata private, so we need to copy
+ * the pixel range out of ourselves
+ */
+ bitmap_base = guit->bitmap->get_buffer(priv->bitmap);
+ for (int yy = y; yy < (y+height); ++yy) {
+ uint8_t *src_base = bitmap_base + (priv->stride * yy);
+ uint8_t *dst_base = idpriv->data + (width * 4);
+ memcpy(dst_base + (x * 4), src_base + (x * 4), width * 4);
+ }
+ return 1;
+%}
+
+method CanvasRenderingContext2D::putImageData()
+%{
+ /* imgdata, x, y[, clipx, clipy, clipw, cliph] */
+ /* If provided, the clip coordinates are within the input image data */
+ /* We pretend the image is placed at x,y within ourselves, and then we
+ * copy the clip rectangle (defaults to whole image)
+ */
+ image_data_private_t *idpriv;
+ int x = duk_to_int(ctx, 1);
+ int y = duk_to_int(ctx, 2);
+ int clipx = 0;
+ int clipy = 0;
+ int clipw = 0;
+ int cliph = 0;
+ uint8_t *bitmap_base;
+
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(IMAGEDATA))) {
+ return duk_generic_error(ctx, "Expected ImageData as first argument");
+ }
+
+ duk_get_prop_string(ctx, 0, dukky_magic_string_private);
+ idpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ if (duk_get_top(ctx) < 7) {
+ /* Clipping data not provided */
+ clipw = idpriv->width;
+ cliph = idpriv->height;
+ } else {
+ clipx = duk_to_int(ctx, 3);
+ clipy = duk_to_int(ctx, 4);
+ clipw = duk_to_int(ctx, 5);
+ cliph = duk_to_int(ctx, 6);
+ }
+
+ if (x < 0 || y < 0 || /* Not positioning negative */
+ (x + clipx + clipw) > priv->width || /* RHS not beyond bounds */
+ (y + clipy + cliph) > priv->height || /* bottom not beyond bounds */
+ clipx < 0 || clipy < 0 || /* Input in range */
+ (clipx + clipw) > idpriv->width || /* Input in range */
+ (clipy + cliph) > idpriv->height) { /* Input in range */
+ return duk_error(ctx, DUK_ERR_RANGE_ERROR, "invalid inputs");
+ }
+
+ bitmap_base = guit->bitmap->get_buffer(priv->bitmap);
+
+ for (int yy = clipy; yy < (clipy + cliph); yy++) {
+ uint8_t *dst_row = bitmap_base + ((y + yy) * priv->stride);
+ uint8_t *src_row = idpriv->data + (yy * idpriv->width * 4);
+ memcpy(dst_row + ((x + clipx) * 4),
+ src_row + (clipx * 4),
+ clipw * 4);
+ }
+ guit->bitmap->modified(priv->bitmap);
+
+ redraw_node((dom_node *)(priv->canvas));
+
+ return 0;
+%}