canvas: Support changing canvas size at runtime

Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
This commit is contained in:
Daniel Silverstone 2020-05-23 23:44:07 +01:00
parent 121c41a730
commit d157b505e6
No known key found for this signature in database
GPG Key ID: C30DF439F2987D74
2 changed files with 143 additions and 8 deletions

View File

@ -9,11 +9,12 @@
*/ */
class CanvasRenderingContext2D { class CanvasRenderingContext2D {
private struct dom_html_element *canvas; private struct dom_html_canvas_element *canvas;
private struct bitmap *bitmap; private struct bitmap *bitmap;
private int width; private int width;
private int height; private int height;
private size_t stride; private size_t stride;
private dom_event_listener *listener;
prologue %{ prologue %{
/* prologue */ /* prologue */
#include "desktop/gui_internal.h" #include "desktop/gui_internal.h"
@ -202,11 +203,79 @@ static nserror canvas2d_create_bitmap(dom_node *node, struct bitmap **bitmap_out
return NSERROR_OK; 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 */ /* prologue ends */
%}; %};
}; };
init CanvasRenderingContext2D(struct dom_html_element *canvas) init CanvasRenderingContext2D(struct dom_html_canvas_element *canvas)
%{ %{
struct bitmap *bitmap; struct bitmap *bitmap;
dom_exception exc; dom_exception exc;
@ -216,6 +285,18 @@ init CanvasRenderingContext2D(struct dom_html_element *canvas)
priv->canvas = canvas; priv->canvas = canvas;
dom_node_ref(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, exc = dom_node_get_user_data(canvas,
corestring_dom___ns_key_canvas_node_data, corestring_dom___ns_key_canvas_node_data,
&bitmap); &bitmap);
@ -242,6 +323,14 @@ init CanvasRenderingContext2D(struct dom_html_element *canvas)
fini CanvasRenderingContext2D() 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); dom_node_unref(priv->canvas);
%} %}
@ -251,6 +340,52 @@ getter CanvasRenderingContext2D::canvas()
return 1; 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() method CanvasRenderingContext2D::createImageData()
%{ %{
/* Can be called either with width and height, or with a reference /* Can be called either with width and height, or with a reference

View File

@ -12,10 +12,10 @@
init HTMLCanvasElement(struct dom_html_element *html_canvas_element::html_element); init HTMLCanvasElement(struct dom_html_element *html_canvas_element::html_element);
getter HTMLCanvasElement::width(); getter HTMLCanvasElement::width();
/* setter HTMLCanvasElement::width(); */ setter HTMLCanvasElement::width();
getter HTMLCanvasElement::height(); getter HTMLCanvasElement::height();
/* setter HTMLCanvasElement::height(); */ setter HTMLCanvasElement::height();
method HTMLCanvasElement::getContext() method HTMLCanvasElement::getContext()
%{ %{