summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2020-05-22 19:52:24 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2020-05-22 19:53:23 +0100
commitdaed553a06716328366f5ea1a2ba09ba4872de1d (patch)
tree7c0f232cf242cd5dd83ca10cee2e22618a67208c
parent244c49df26ba943dc7cef60413126fbaf52a4428 (diff)
downloadnetsurf-daed553a06716328366f5ea1a2ba09ba4872de1d.tar.gz
netsurf-daed553a06716328366f5ea1a2ba09ba4872de1d.tar.bz2
javascript: Support Canvas to a basic level
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
-rw-r--r--content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd232
-rw-r--r--content/handlers/javascript/duktape/HTMLCanvasElement.bnd33
-rw-r--r--content/handlers/javascript/duktape/ImageData.bnd44
-rw-r--r--content/handlers/javascript/duktape/dukky.c3
-rw-r--r--content/handlers/javascript/duktape/netsurf.bnd4
5 files changed, 314 insertions, 2 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;
+%}
diff --git a/content/handlers/javascript/duktape/HTMLCanvasElement.bnd b/content/handlers/javascript/duktape/HTMLCanvasElement.bnd
index 189ddb0f4..9fa46ff0b 100644
--- a/content/handlers/javascript/duktape/HTMLCanvasElement.bnd
+++ b/content/handlers/javascript/duktape/HTMLCanvasElement.bnd
@@ -1,6 +1,7 @@
/* HTML canvas element binding using duktape and libdom
*
* Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
+ * Copyright 2020 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -11,8 +12,36 @@
init HTMLCanvasElement(struct dom_html_element *html_canvas_element::html_element);
getter HTMLCanvasElement::width();
-setter HTMLCanvasElement::width();
+/* setter HTMLCanvasElement::width(); */
getter HTMLCanvasElement::height();
-setter HTMLCanvasElement::height();
+/* setter HTMLCanvasElement::height(); */
+
+method HTMLCanvasElement::getContext()
+%{
+ /* modetype[, {options}] */
+ const char *modetype = duk_to_string(ctx, 0);
+ if (strcmp(modetype, "2d") != 0) {
+ duk_push_null(ctx);
+ return 1;
+ }
+
+ duk_push_this(ctx);
+ duk_get_prop_string(ctx, -1, MAGIC(Context2D));
+ if (duk_is_undefined(ctx, -1)) {
+ duk_pop(ctx);
+
+ duk_push_pointer(ctx, ((node_private_t*)priv)->node);
+ if (dukky_create_object(ctx,
+ PROTO_NAME(CANVASRENDERINGCONTEXT2D),
+ 1) != DUK_EXEC_SUCCESS) {
+ return duk_error(ctx,
+ DUK_ERR_ERROR,
+ "Unable to create CanvasRenderingContext2D");
+ }
+ duk_dup(ctx, -1);
+ duk_put_prop_string(ctx, -3, MAGIC(Context2D));
+ }
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/ImageData.bnd b/content/handlers/javascript/duktape/ImageData.bnd
new file mode 100644
index 000000000..17673d92a
--- /dev/null
+++ b/content/handlers/javascript/duktape/ImageData.bnd
@@ -0,0 +1,44 @@
+/* HTML canvas ImageData objects
+ *
+ * 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 ImageData {
+ private int width;
+ private int height;
+ private uint8_t *data;
+};
+
+init ImageData(int width, int height)
+%{
+ priv->width = width;
+ priv->height = height;
+ priv->data = duk_push_buffer(ctx, width * height * 4, false);
+ duk_put_prop_string(ctx, 0, MAGIC(DATA));
+ duk_pop(ctx);
+%}
+
+getter ImageData::width()
+%{
+ duk_push_int(ctx, priv->width);
+ return 1;
+%}
+
+getter ImageData::height()
+%{
+ duk_push_int(ctx, priv->height);
+ return 1;
+%}
+
+getter ImageData::data()
+%{
+ duk_push_this(ctx);
+ duk_get_prop_string(ctx, -1, MAGIC(DATA));
+ duk_push_buffer_object(ctx, -1, 0, priv->width * priv->height * 4, DUK_BUFOBJ_UINT8CLAMPEDARRAY);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 6d877129b..830f48108 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -380,6 +380,9 @@ static void dukky_html_element_class_from_tag_type(dom_html_element_type type,
case DOM_HTML_ELEMENT_TYPE_ISINDEX:
SET_HTML_CLASS(ISINDEX)
break;
+ case DOM_HTML_ELEMENT_TYPE_CANVAS:
+ SET_HTML_CLASS(CANVAS)
+ break;
case DOM_HTML_ELEMENT_TYPE__COUNT:
assert(type != DOM_HTML_ELEMENT_TYPE__COUNT);
/* fallthrough */
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 5fc592771..e47f07d2b 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -200,4 +200,8 @@ init HTMLFormControlsCollection(struct dom_html_collection *coll);
init HTMLOptionsCollection(struct dom_html_collection *coll);
init HTMLPropertiesCollection(struct dom_html_collection *coll);
+/* Stuff to do with canvasses */
+
+#include "CanvasRenderingContext2D.bnd"
+#include "ImageData.bnd"