From d8f083bf520370738600502697dcc0f4642cfa0e Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 23 May 2020 10:15:30 +0100 Subject: Canvas: Move bitmap management to the 2D render context Signed-off-by: Daniel Silverstone --- content/handlers/html/dom_event.c | 152 ------------------- .../duktape/CanvasRenderingContext2D.bnd | 162 +++++++++++++++++++++ 2 files changed, 162 insertions(+), 152 deletions(-) diff --git a/content/handlers/html/dom_event.c b/content/handlers/html/dom_event.c index 533c9d599..d490cad77 100644 --- a/content/handlers/html/dom_event.c +++ b/content/handlers/html/dom_event.c @@ -106,154 +106,6 @@ static bool html_process_inserted_base(html_content *htmlc, dom_node *node) return true; } -/** - * deal with events from the DOM for canvas node user data - * - * \param operation The DOM operation happening - * \param key The user data key - * \param data The user data (our bitmap) - * \param src The DOM node emitting the event (our ) - * \param dst The target DOM node if applicable - */ -static void -html__canvas_user_data_handler(dom_node_operation operation, - dom_string *key, - void *data, - struct dom_node *src, - struct dom_node *dst) -{ - struct bitmap *newbitmap, *bitmap = (struct bitmap*)data, *oldbitmap = NULL; - int width, height; - size_t stride; - - if (dom_string_isequal(key,corestring_dom___ns_key_canvas_node_data) == false || data == NULL) { - /* Not for us */ - return; - } - - switch (operation) { - case DOM_NODE_CLONED: - width = guit->bitmap->get_width(bitmap); - height = guit->bitmap->get_height(bitmap); - stride = guit->bitmap->get_rowstride(bitmap); - newbitmap = guit->bitmap->create(width, height, - BITMAP_NEW); - if (newbitmap != NULL) { - if (guit->bitmap->get_rowstride(newbitmap) == stride) { - // Compatible bitmap, bung the data over - memcpy(guit->bitmap->get_buffer(newbitmap), - guit->bitmap->get_buffer(bitmap), - stride * height); - guit->bitmap->modified(newbitmap); - } - } - if (dom_node_set_user_data(dst, - corestring_dom___ns_key_canvas_node_data, - newbitmap, html__canvas_user_data_handler, - &oldbitmap) == DOM_NO_ERR) { - if (oldbitmap != NULL) - guit->bitmap->destroy(oldbitmap); - } - break; - - case DOM_NODE_RENAMED: - case DOM_NODE_IMPORTED: - case DOM_NODE_ADOPTED: - break; - - case DOM_NODE_DELETED: - guit->bitmap->destroy(bitmap); - break; - default: - NSLOG(netsurf, INFO, "User data operation not handled."); - assert(0); - } -} - -/** - * process a canvas element being inserted into the DOM - * - * \param htmlc The html content containing the DOM - * \param node The DOM node being inserted - * \return NSERROR_OK on success else appropriate error code - */ -static nserror html_process_inserted_canvas(html_content *htmlc, dom_node *node) -{ - dom_exception exc; - dom_string *width_s = NULL, *height_s = NULL; - unsigned long width = 300, height = 150; - struct bitmap *bitmap, *oldbitmap = NULL; - - if (!htmlc->enable_scripting) { - /* No point processing this element, we're not going to - * render it - */ - return NSERROR_OK; - } - - exc = dom_element_get_attribute(node, - corestring_dom_width, - &width_s); - if (exc == DOM_NO_ERR && width_s != NULL) { - const char *ptr = (const char *)dom_string_data(width_s); - const char *endptr = ptr + dom_string_length(width_s); - char * ended; - unsigned long width_n = strtoul(ptr, &ended, 10); - - if (ended == endptr || strcasecmp(ended, "px") == 0) { - /* parsed it all */ - width = width_n; - } - - dom_string_unref(width_s); - } - - exc = dom_element_get_attribute(node, - corestring_dom_height, - &height_s); - if (exc == DOM_NO_ERR && height_s != NULL) { - const char *ptr = (const char *)dom_string_data(height_s); - const char *endptr = ptr + dom_string_length(height_s); - char * ended; - unsigned long height_n = strtoul(ptr, &ended, 10); - - if (ended == endptr || strcasecmp(ended, "px") == 0) { - /* parsed it all */ - height = height_n; - } - - dom_string_unref(height_s); - } - - bitmap = guit->bitmap->create( - (int)width, (int)height, - BITMAP_NEW); - - if (bitmap == NULL) { - return NSERROR_NOMEM; - } - - memset(guit->bitmap->get_buffer(bitmap), - 0, /* Transparent black */ - height * guit->bitmap->get_rowstride(bitmap)); - guit->bitmap->modified(bitmap); - - exc = dom_node_set_user_data(node, - corestring_dom___ns_key_canvas_node_data, - bitmap, - html__canvas_user_data_handler, - &oldbitmap); - - if (exc != DOM_NO_ERR) { - guit->bitmap->destroy(bitmap); - return NSERROR_DOM; - } - - if (oldbitmap != NULL) - guit->bitmap->destroy(oldbitmap); - - return NSERROR_OK; -} /** @@ -757,10 +609,6 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) html_process_inserted_base(htmlc, (dom_node *)node); break; - case DOM_HTML_ELEMENT_TYPE_CANVAS: - html_process_inserted_canvas(htmlc, (dom_node *)node); - break; - case DOM_HTML_ELEMENT_TYPE_IMG: html_process_inserted_img(htmlc, (dom_node *)node); break; diff --git a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd index 6b6039aa9..e143abef3 100644 --- a/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd +++ b/content/handlers/javascript/duktape/CanvasRenderingContext2D.bnd @@ -58,6 +58,150 @@ static void redraw_node(dom_node *node) dom_node_unref(doc); } +/** + * deal with events from the DOM for canvas node user data + * + * \param operation The DOM operation happening + * \param key The user data key + * \param data The user data (our bitmap) + * \param src The DOM node emitting the event (our ) + * \param dst The target DOM node if applicable + */ +static void +canvas2d_user_data_handler(dom_node_operation operation, + dom_string *key, + void *data, + struct dom_node *src, + struct dom_node *dst) +{ + struct bitmap *newbitmap, *bitmap = (struct bitmap*)data, *oldbitmap = NULL; + int width, height; + size_t stride; + + if (dom_string_isequal(key,corestring_dom___ns_key_canvas_node_data) == false || data == NULL) { + /* Not for us */ + return; + } + + switch (operation) { + case DOM_NODE_CLONED: + width = guit->bitmap->get_width(bitmap); + height = guit->bitmap->get_height(bitmap); + stride = guit->bitmap->get_rowstride(bitmap); + newbitmap = guit->bitmap->create(width, height, + BITMAP_NEW); + if (newbitmap != NULL) { + if (guit->bitmap->get_rowstride(newbitmap) == stride) { + // Compatible bitmap, bung the data over + memcpy(guit->bitmap->get_buffer(newbitmap), + guit->bitmap->get_buffer(bitmap), + stride * height); + guit->bitmap->modified(newbitmap); + } + } + if (dom_node_set_user_data(dst, + corestring_dom___ns_key_canvas_node_data, + newbitmap, canvas2d_user_data_handler, + &oldbitmap) == DOM_NO_ERR) { + if (oldbitmap != NULL) + guit->bitmap->destroy(oldbitmap); + } + break; + + case DOM_NODE_RENAMED: + case DOM_NODE_IMPORTED: + case DOM_NODE_ADOPTED: + break; + + case DOM_NODE_DELETED: + guit->bitmap->destroy(bitmap); + break; + default: + NSLOG(netsurf, INFO, "User data operation not handled."); + assert(0); + } +} + +/** + * Give the canvas element an appropriately sized bitmap + * + * \param node The DOM node being inserted + * \param[out] bitmap_out The bitmap created + * \return NSERROR_OK on success else appropriate error code + */ +static nserror canvas2d_create_bitmap(dom_node *node, struct bitmap **bitmap_out) +{ + dom_exception exc; + dom_string *width_s = NULL, *height_s = NULL; + unsigned long width = 300, height = 150; + struct bitmap *bitmap, *oldbitmap = NULL; + + exc = dom_element_get_attribute(node, + corestring_dom_width, + &width_s); + if (exc == DOM_NO_ERR && width_s != NULL) { + const char *ptr = (const char *)dom_string_data(width_s); + const char *endptr = ptr + dom_string_length(width_s); + char * ended; + unsigned long width_n = strtoul(ptr, &ended, 10); + + if (ended == endptr || strcasecmp(ended, "px") == 0) { + /* parsed it all */ + width = width_n; + } + + dom_string_unref(width_s); + } + + exc = dom_element_get_attribute(node, + corestring_dom_height, + &height_s); + if (exc == DOM_NO_ERR && height_s != NULL) { + const char *ptr = (const char *)dom_string_data(height_s); + const char *endptr = ptr + dom_string_length(height_s); + char * ended; + unsigned long height_n = strtoul(ptr, &ended, 10); + + if (ended == endptr || strcasecmp(ended, "px") == 0) { + /* parsed it all */ + height = height_n; + } + + dom_string_unref(height_s); + } + + bitmap = guit->bitmap->create( + (int)width, (int)height, + BITMAP_NEW); + + if (bitmap == NULL) { + return NSERROR_NOMEM; + } + + memset(guit->bitmap->get_buffer(bitmap), + 0, /* Transparent black */ + height * guit->bitmap->get_rowstride(bitmap)); + guit->bitmap->modified(bitmap); + + exc = dom_node_set_user_data(node, + corestring_dom___ns_key_canvas_node_data, + bitmap, + canvas2d_user_data_handler, + &oldbitmap); + + if (exc != DOM_NO_ERR) { + guit->bitmap->destroy(bitmap); + return NSERROR_DOM; + } + + assert(oldbitmap == NULL); + + if (bitmap_out != NULL) + *bitmap_out = bitmap; + + return NSERROR_OK; +} + /* prologue ends */ %}; }; @@ -76,6 +220,18 @@ init CanvasRenderingContext2D(struct dom_html_element *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) { + priv->bitmap = NULL; + priv->width = -1; + priv->height = -1; + priv->stride = 0; + return; + } + } + assert(bitmap != NULL); priv->bitmap = bitmap; @@ -139,6 +295,9 @@ method CanvasRenderingContext2D::getImageData() image_data_private_t *idpriv; uint8_t *bitmap_base; + if (priv->bitmap == NULL) + return duk_generic_error(ctx, "Canvas in bad state, sorry"); + 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); @@ -191,6 +350,9 @@ method CanvasRenderingContext2D::putImageData() return duk_generic_error(ctx, "Expected ImageData as first argument"); } + if (priv->bitmap == NULL) + return duk_generic_error(ctx, "Canvas in bad state, sorry"); + duk_get_prop_string(ctx, 0, dukky_magic_string_private); idpriv = duk_get_pointer(ctx, -1); duk_pop(ctx); -- cgit v1.2.3