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