From d157b505e68da9a3b50a0c10b7e4f3d5a1e48592 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 23 May 2020 23:44:07 +0100 Subject: canvas: Support changing canvas size at runtime Signed-off-by: Daniel Silverstone --- .../duktape/CanvasRenderingContext2D.bnd | 147 ++++++++++++++++++++- .../javascript/duktape/HTMLCanvasElement.bnd | 4 +- 2 files changed, 143 insertions(+), 8 deletions(-) (limited to 'content') diff --git a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd index e143abef3..272e8e7c7 100644 --- a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd +++ b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd @@ -9,11 +9,12 @@ */ class CanvasRenderingContext2D { - private struct dom_html_element *canvas; + private struct dom_html_canvas_element *canvas; private struct bitmap *bitmap; private int width; private int height; private size_t stride; + private dom_event_listener *listener; prologue %{ /* prologue */ #include "desktop/gui_internal.h" @@ -202,25 +203,105 @@ static nserror canvas2d_create_bitmap(dom_node *node, struct bitmap **bitmap_out return NSERROR_OK; } +/** + * Handle subtree modified events for our canvas node + * + * If width or height has changed relative to our priv, then + * we need to recreate the bitmap and reset our cached width + * and height values in order to be safe. Plus redraw ourselves. + * + * \param evt The event which occurred + * \param pw The private pointer for our canvas object + */ +static void +canvas2d__handle_dom_event(dom_event *evt, void *pw) +{ + canvas_rendering_context2d_private_t *priv = pw; + dom_ulong width; + dom_ulong height; + dom_exception exc; + struct bitmap *newbitmap, *oldbitmap = NULL; + size_t stride; + dom_event_flow_phase phase; + + exc = dom_event_get_event_phase(evt, &phase); + assert(exc == DOM_NO_ERR); + /* If we're not being hit right now, we're not up for it */ + if (phase != DOM_AT_TARGET) return; + + /* Rather than being complex about things, let's just work out + * what the width and height are and hope nothing else matters + */ + + exc = dom_html_canvas_element_get_width(priv->canvas, &width); + if (exc != DOM_NO_ERR) return; + exc = dom_html_canvas_element_get_height(priv->canvas, &height); + if (exc != DOM_NO_ERR) return; + + if ((int)height == priv->height && (int)width == priv->width) return; + + /* Okay, we need to reallocate our bitmap and re-cache values */ + + newbitmap = guit->bitmap->create(width, height, BITMAP_NEW); + stride = guit->bitmap->get_rowstride(newbitmap); + + if (newbitmap != NULL) { + memset(guit->bitmap->get_buffer(newbitmap), + 0, + stride * height); + guit->bitmap->modified(newbitmap); + } + + if (dom_node_set_user_data(priv->canvas, + corestring_dom___ns_key_canvas_node_data, + newbitmap, canvas2d_user_data_handler, + &oldbitmap) == DOM_NO_ERR) { + if (oldbitmap != NULL) + guit->bitmap->destroy(oldbitmap); + } else { + guit->bitmap->destroy(newbitmap); + /* We'll stick with the old, odd though that might be */ + return; + } + + /* Cache the new values */ + priv->width = (int)width; + priv->height = (int)height; + priv->stride = stride; + priv->bitmap = newbitmap; +} + /* prologue ends */ %}; }; -init CanvasRenderingContext2D(struct dom_html_element *canvas) +init CanvasRenderingContext2D(struct dom_html_canvas_element *canvas) %{ struct bitmap *bitmap; dom_exception exc; assert(canvas != NULL); - + priv->canvas = canvas; dom_node_ref(canvas); - + + exc = dom_event_listener_create(canvas2d__handle_dom_event, + priv, + &priv->listener); + assert(exc == DOM_NO_ERR); + + exc = dom_event_target_add_event_listener( + canvas, + corestring_dom_DOMSubtreeModified, + priv->listener, + false); + assert(exc == DOM_NO_ERR); + exc = dom_node_get_user_data(canvas, corestring_dom___ns_key_canvas_node_data, &bitmap); assert(exc == DOM_NO_ERR); - + if (bitmap == NULL) { if (canvas2d_create_bitmap((dom_node *)canvas, &bitmap) != NSERROR_OK) { @@ -233,7 +314,7 @@ init CanvasRenderingContext2D(struct dom_html_element *canvas) } assert(bitmap != NULL); - + priv->bitmap = bitmap; priv->width = guit->bitmap->get_width(bitmap); priv->height = guit->bitmap->get_height(bitmap); @@ -242,6 +323,14 @@ init CanvasRenderingContext2D(struct dom_html_element *canvas) fini CanvasRenderingContext2D() %{ + dom_exception exc; + exc = dom_event_target_remove_event_listener( + priv->canvas, + corestring_dom_DOMSubtreeModified, + priv->listener, + false); + assert(exc == DOM_NO_ERR); + dom_event_listener_unref(priv->listener); dom_node_unref(priv->canvas); %} @@ -251,6 +340,52 @@ getter CanvasRenderingContext2D::canvas() return 1; %} +getter CanvasRenderingContext2D::width() +%{ + dom_exception exc; + dom_ulong width; + + exc = dom_html_canvas_element_get_width(priv->canvas, &width); + if (exc != DOM_NO_ERR) return 0; + + duk_push_number(ctx, (duk_double_t)width); + return 1; +%} + +setter CanvasRenderingContext2D::width() +%{ + dom_exception exc; + dom_ulong width = duk_get_uint(ctx, 0); + + exc = dom_html_canvas_element_set_width(priv->canvas, width); + if (exc != DOM_NO_ERR) return 0; + + return 1; +%} + +getter CanvasRenderingContext2D::height() +%{ + dom_exception exc; + dom_ulong height; + + exc = dom_html_canvas_element_get_height(priv->canvas, &height); + if (exc != DOM_NO_ERR) return 0; + + duk_push_number(ctx, (duk_double_t)height); + return 1; +%} + +setter CanvasRenderingContext2D::height() +%{ + dom_exception exc; + dom_ulong height = duk_get_uint(ctx, 0); + + exc = dom_html_canvas_element_set_height(priv->canvas, height); + if (exc != DOM_NO_ERR) return 0; + + return 1; +%} + method CanvasRenderingContext2D::createImageData() %{ /* Can be called either with width and height, or with a reference diff --git a/content/handlers/javascript/duktape/HTMLCanvasElement.bnd b/content/handlers/javascript/duktape/HTMLCanvasElement.bnd index 9fa46ff0b..da9f66dee 100644 --- a/content/handlers/javascript/duktape/HTMLCanvasElement.bnd +++ b/content/handlers/javascript/duktape/HTMLCanvasElement.bnd @@ -12,10 +12,10 @@ 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() %{ -- cgit v1.2.3