summaryrefslogtreecommitdiff
path: root/modules/cairo-surface.cpp
diff options
context:
space:
mode:
authorPhilip Chimento <philip.chimento@gmail.com>2019-10-26 22:52:35 -0700
committerPhilip Chimento <philip.chimento@gmail.com>2019-10-30 21:29:48 -0700
commite7ca4d37ed3446ede0daa0a99d5488b5c37d0f20 (patch)
treef9aebf6741df8654416c99e32cbb56daa44bdb97 /modules/cairo-surface.cpp
parent85ebaae84234c82379236272f80782338cef4aae (diff)
downloadgjs-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.cpp55
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)