Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/1223cf078648d9a7f38913cf002398e9aff5ddfe
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/1223cf078648d9a7f38913cf002398e9aff5ddfe
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/1223cf078648d9a7f38913cf002398e9aff5ddfe

The branch, master has been updated
       via  1223cf078648d9a7f38913cf002398e9aff5ddfe (commit)
       via  daed553a06716328366f5ea1a2ba09ba4872de1d (commit)
      from  244c49df26ba943dc7cef60413126fbaf52a4428 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=1223cf078648d9a7f38913cf002398e9aff5ddfe
commit 1223cf078648d9a7f38913cf002398e9aff5ddfe
Author: Daniel Silverstone <dsilv...@digital-scurf.org>
Commit: Daniel Silverstone <dsilv...@digital-scurf.org>

    test/js: Include mandelbrot example
    
    Signed-off-by: Daniel Silverstone <dsilv...@digital-scurf.org>

diff --git a/test/js/index.html b/test/js/index.html
index 2abe954..f922872 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -104,6 +104,7 @@
 <li><a href="assorted-log-doc-write.html">console.log and 
document.write</a></li>
 <li><a href="wikipedia-lcm.html">Example from wikipedia</a></li>
 <li><a href="verify-instanceofness.html">Check instanceof behaviour</a></li>
+<li><a href="mandelbrot.html">Canvas/ImageData Mandelbrot ploter</a></li>
 </ul>
 
 </body>
diff --git a/test/js/mandelbrot.html b/test/js/mandelbrot.html
new file mode 100644
index 0000000..38f77ef
--- /dev/null
+++ b/test/js/mandelbrot.html
@@ -0,0 +1,31 @@
+<html>
+    <head>
+        <title>JS Mandelbrot</title>
+        <script src="https://nerget.com/mandelbrot.js";></script>
+        <script>
+        var drawn = false;
+        var dimension = 2;
+        var cx = -dimension / 2 + 0.5;
+        var cy = -dimension / 2;
+        
+        function log(msg) {
+            document.getElementById("log").innerHTML += msg + "<br/>";
+        }
+        
+        function draw() {
+            var forceSlowPath = 
document.getElementById('forceSlowPath').checked;
+            drawMandelbrot(document.getElementById('canvas').getContext('2d'), 
200, 200, 
+                           cx + dimension / 2, cy + dimension / 2, dimension, 
500, forceSlowPath);
+            drawn = true;
+        }
+        
+        </script>
+    </head>
+    <body>
+        <canvas id="canvas" width="200" height="200" style="border: 1px solid 
black;"></canvas>
+        <br />
+        <input id="forceSlowPath" type="checkbox">Use slow path.</input> <br />
+        <a href="javascript:draw()">Start</a>
+        <div id="log"></div>
+    </body>
+</html>


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=daed553a06716328366f5ea1a2ba09ba4872de1d
commit daed553a06716328366f5ea1a2ba09ba4872de1d
Author: Daniel Silverstone <dsilv...@digital-scurf.org>
Commit: Daniel Silverstone <dsilv...@digital-scurf.org>

    javascript: Support Canvas to a basic level
    
    Signed-off-by: Daniel Silverstone <dsilv...@digital-scurf.org>

diff --git a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd 
b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd
new file mode 100644
index 0000000..5acf750
--- /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 <dsilv...@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 189ddb0..9fa46ff 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 <vi...@netsurf-browser.org>
+ * Copyright 2020 Daniel Silverstone <dsilv...@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 0000000..17673d9
--- /dev/null
+++ b/content/handlers/javascript/duktape/ImageData.bnd
@@ -0,0 +1,44 @@
+/* HTML canvas ImageData objects
+ *
+ * Copyright 2020 Daniel Silverstone <dsilv...@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 6d87712..830f481 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 5fc5927..e47f07d 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"
 


-----------------------------------------------------------------------

Summary of changes:
 .../duktape/CanvasRenderingContext2D.bnd           |  232 ++++++++++++++++++++
 .../javascript/duktape/HTMLCanvasElement.bnd       |   33 ++-
 content/handlers/javascript/duktape/ImageData.bnd  |   44 ++++
 content/handlers/javascript/duktape/dukky.c        |    3 +
 content/handlers/javascript/duktape/netsurf.bnd    |    4 +
 test/js/index.html                                 |    1 +
 test/js/mandelbrot.html                            |   31 +++
 7 files changed, 346 insertions(+), 2 deletions(-)
 create mode 100644 
content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd
 create mode 100644 content/handlers/javascript/duktape/ImageData.bnd
 create mode 100644 test/js/mandelbrot.html

diff --git a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd 
b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd
new file mode 100644
index 0000000..5acf750
--- /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 <dsilv...@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 189ddb0..9fa46ff 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 <vi...@netsurf-browser.org>
+ * Copyright 2020 Daniel Silverstone <dsilv...@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 0000000..17673d9
--- /dev/null
+++ b/content/handlers/javascript/duktape/ImageData.bnd
@@ -0,0 +1,44 @@
+/* HTML canvas ImageData objects
+ *
+ * Copyright 2020 Daniel Silverstone <dsilv...@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 6d87712..830f481 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 5fc5927..e47f07d 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"
 
diff --git a/test/js/index.html b/test/js/index.html
index 2abe954..f922872 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -104,6 +104,7 @@
 <li><a href="assorted-log-doc-write.html">console.log and 
document.write</a></li>
 <li><a href="wikipedia-lcm.html">Example from wikipedia</a></li>
 <li><a href="verify-instanceofness.html">Check instanceof behaviour</a></li>
+<li><a href="mandelbrot.html">Canvas/ImageData Mandelbrot ploter</a></li>
 </ul>
 
 </body>
diff --git a/test/js/mandelbrot.html b/test/js/mandelbrot.html
new file mode 100644
index 0000000..38f77ef
--- /dev/null
+++ b/test/js/mandelbrot.html
@@ -0,0 +1,31 @@
+<html>
+    <head>
+        <title>JS Mandelbrot</title>
+        <script src="https://nerget.com/mandelbrot.js";></script>
+        <script>
+        var drawn = false;
+        var dimension = 2;
+        var cx = -dimension / 2 + 0.5;
+        var cy = -dimension / 2;
+        
+        function log(msg) {
+            document.getElementById("log").innerHTML += msg + "<br/>";
+        }
+        
+        function draw() {
+            var forceSlowPath = 
document.getElementById('forceSlowPath').checked;
+            drawMandelbrot(document.getElementById('canvas').getContext('2d'), 
200, 200, 
+                           cx + dimension / 2, cy + dimension / 2, dimension, 
500, forceSlowPath);
+            drawn = true;
+        }
+        
+        </script>
+    </head>
+    <body>
+        <canvas id="canvas" width="200" height="200" style="border: 1px solid 
black;"></canvas>
+        <br />
+        <input id="forceSlowPath" type="checkbox">Use slow path.</input> <br />
+        <a href="javascript:draw()">Start</a>
+        <div id="log"></div>
+    </body>
+</html>


-- 
NetSurf Browser
_______________________________________________
netsurf-commits mailing list -- netsurf-commits@netsurf-browser.org
To unsubscribe send an email to netsurf-commits-le...@netsurf-browser.org

Reply via email to