diff options
author | Philip Chimento <philip.chimento@gmail.com> | 2019-10-26 22:52:35 -0700 |
---|---|---|
committer | Philip Chimento <philip.chimento@gmail.com> | 2019-10-30 21:29:48 -0700 |
commit | e7ca4d37ed3446ede0daa0a99d5488b5c37d0f20 (patch) | |
tree | f9aebf6741df8654416c99e32cbb56daa44bdb97 /modules/cairo-surface.cpp | |
parent | 85ebaae84234c82379236272f80782338cef4aae (diff) | |
download | gjs-e7ca4d37ed3446ede0daa0a99d5488b5c37d0f20.tar.gz |
cairo: Add type checking to Path, Pattern, and Surface
Previously, passing the wrong kind of object where a Cairo.Path,
Cairo.Pattern (subclass), or Cairo.Surface (subclass) was expected,
would crash. This adds type checking to avoid these crashes.
The normal way to do this would be with JS_HasInstance(), but since
Cairo.Pattern and Cairo.Surface are abstract classes, that won't work.
JS_HasInstance() takes a constructor, and abstract classes don't have a
constructor. Instead, we have to check the passed-in object's prototype
chain. It turns out there isn't a JSAPI function to do that, so we add
gjs_object_in_prototype_chain() for this purpose.
In addition we add missing error checking in a few places.
Closes: #49.
Diffstat (limited to 'modules/cairo-surface.cpp')
-rw-r--r-- | modules/cairo-surface.cpp | 55 |
1 files changed, 35 insertions, 20 deletions
diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp index a2bb9514..5b98c1b7 100644 --- a/modules/cairo-surface.cpp +++ b/modules/cairo-surface.cpp @@ -70,13 +70,12 @@ writeToPNG_func(JSContext *context, { GJS_GET_THIS(context, argc, vp, argv, obj); GjsAutoChar filename; - cairo_surface_t *surface; if (!gjs_parse_call_args(context, "writeToPNG", argv, "F", "filename", &filename)) return false; - surface = gjs_cairo_surface_get_surface(context, obj); + cairo_surface_t* surface = gjs_cairo_surface_get_surface(context, obj); if (!surface) return false; @@ -95,7 +94,6 @@ getType_func(JSContext *context, JS::Value *vp) { GJS_GET_THIS(context, argc, vp, rec, obj); - cairo_surface_t *surface; cairo_surface_type_t type; if (argc > 1) { @@ -103,7 +101,10 @@ getType_func(JSContext *context, return false; } - surface = gjs_cairo_surface_get_surface(context, obj); + cairo_surface_t* surface = gjs_cairo_surface_get_surface(context, obj); + if (!surface) + return false; + type = cairo_surface_get_type(surface); if (!gjs_cairo_check_status(context, cairo_surface_status(surface), "surface")) @@ -226,24 +227,33 @@ gjs_cairo_surface_from_surface(JSContext *context, /** * gjs_cairo_surface_get_surface: - * @context: the context - * @object: surface wrapper - * - * Returns: the surface attaches to the wrapper. + * @cx: the context + * @surface_wrapper: surface wrapper * + * Returns: the surface attached to the wrapper. */ -cairo_surface_t * -gjs_cairo_surface_get_surface(JSContext *context, - JSObject *object) -{ - GjsCairoSurface *priv; +cairo_surface_t* gjs_cairo_surface_get_surface( + JSContext* cx, JS::HandleObject surface_wrapper) { + g_return_val_if_fail(cx, nullptr); + g_return_val_if_fail(surface_wrapper, nullptr); - g_return_val_if_fail(context, nullptr); - g_return_val_if_fail(object, nullptr); + JS::RootedObject proto(cx, gjs_cairo_surface_get_proto(cx)); + + bool is_surface_subclass = false; + if (!gjs_object_in_prototype_chain(cx, proto, surface_wrapper, + &is_surface_subclass)) + return nullptr; + if (!is_surface_subclass) { + gjs_throw(cx, "Expected Cairo.Surface but got %s", + JS_GetClass(surface_wrapper)->name); + return nullptr; + } - priv = (GjsCairoSurface*) JS_GetPrivate(object); + auto* priv = static_cast<GjsCairoSurface*>(JS_GetPrivate(surface_wrapper)); if (!priv) return nullptr; + + g_assert(priv->surface); return priv->surface; } @@ -269,11 +279,16 @@ surface_to_g_argument(JSContext *context, return true; } - JSObject *obj; - cairo_surface_t *s; + if (!value.isObject()) { + GjsAutoChar display_name = + gjs_argument_display_name(arg_name, argument_type); + gjs_throw(context, "%s is not a Cairo.Surface", display_name.get()); + return false; + } - obj = &value.toObject(); - s = gjs_cairo_surface_get_surface(context, obj); + JS::RootedObject surface_wrapper(context, &value.toObject()); + cairo_surface_t* s = + gjs_cairo_surface_get_surface(context, surface_wrapper); if (!s) return false; if (transfer == GI_TRANSFER_EVERYTHING) |