Branch data Line data Source code
1 : : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 : : // SPDX-FileCopyrightText: 2014 Red Hat, Inc.
4 : :
5 : : #include <config.h>
6 : :
7 : : #include <cairo.h>
8 : : #include <girepository.h>
9 : :
10 : : #include <js/CallArgs.h>
11 : : #include <js/Conversions.h>
12 : : #include <js/PropertyAndElement.h>
13 : : #include <js/PropertyDescriptor.h> // for JSPROP_READONLY
14 : : #include <js/PropertySpec.h>
15 : : #include <js/RootingAPI.h>
16 : : #include <js/TypeDecls.h>
17 : : #include <js/Value.h>
18 : : #include <jsapi.h> // for JS_NewPlainObject
19 : :
20 : : #include "gi/arg-inl.h"
21 : : #include "gi/arg.h"
22 : : #include "gi/foreign.h"
23 : : #include "gjs/atoms.h"
24 : : #include "gjs/auto.h"
25 : : #include "gjs/context-private.h"
26 : : #include "gjs/enum-utils.h"
27 : : #include "gjs/jsapi-util-args.h"
28 : : #include "gjs/jsapi-util.h"
29 : : #include "gjs/macros.h"
30 : : #include "modules/cairo-private.h"
31 : :
32 : : GJS_JSAPI_RETURN_CONVENTION
33 : : static bool
34 : : fill_rectangle(JSContext *context,
35 : : JS::HandleObject obj,
36 : : cairo_rectangle_int_t *rect);
37 : :
38 : : #define PRELUDE \
39 : : GJS_GET_THIS(context, argc, vp, argv, obj); \
40 : : cairo_region_t* this_region; \
41 : : if (!CairoRegion::for_js_typecheck(context, obj, &this_region, &argv)) \
42 : : return false;
43 : :
44 : : #define RETURN_STATUS \
45 : : return gjs_cairo_check_status(context, cairo_region_status(this_region), "region");
46 : :
47 : : #define REGION_DEFINE_REGION_FUNC(method) \
48 : : GJS_JSAPI_RETURN_CONVENTION \
49 : : static bool method##_func(JSContext* context, unsigned argc, \
50 : : JS::Value* vp) { \
51 : : PRELUDE; \
52 : : JS::RootedObject other_obj(context); \
53 : : if (!gjs_parse_call_args(context, #method, argv, "o", "other_region", \
54 : : &other_obj)) \
55 : : return false; \
56 : : \
57 : : cairo_region_t* other_region = \
58 : : CairoRegion::for_js(context, other_obj); \
59 : : \
60 : : cairo_region_##method(this_region, other_region); \
61 : : argv.rval().setUndefined(); \
62 : : RETURN_STATUS; \
63 : : }
64 : :
65 : : #define REGION_DEFINE_RECT_FUNC(method) \
66 : : GJS_JSAPI_RETURN_CONVENTION \
67 : : static bool method##_rectangle_func(JSContext* context, unsigned argc, \
68 : : JS::Value* vp) { \
69 : : PRELUDE; \
70 : : JS::RootedObject rect_obj(context); \
71 : : if (!gjs_parse_call_args(context, #method, argv, "o", "rect", \
72 : : &rect_obj)) \
73 : : return false; \
74 : : \
75 : : cairo_rectangle_int_t rect; \
76 : : if (!fill_rectangle(context, rect_obj, &rect)) \
77 : : return false; \
78 : : \
79 : : cairo_region_##method##_rectangle(this_region, &rect); \
80 : : argv.rval().setUndefined(); \
81 : : RETURN_STATUS; \
82 : : }
83 : :
84 [ # # # # : 0 : REGION_DEFINE_REGION_FUNC(union)
# # ]
85 [ # # # # : 0 : REGION_DEFINE_REGION_FUNC(subtract)
# # ]
86 [ # # # # : 0 : REGION_DEFINE_REGION_FUNC(intersect)
# # ]
87 [ # # # # : 0 : REGION_DEFINE_REGION_FUNC(xor)
# # ]
88 : :
89 [ # # # # : 0 : REGION_DEFINE_RECT_FUNC(union)
# # # # ]
90 [ # # # # : 0 : REGION_DEFINE_RECT_FUNC(subtract)
# # # # ]
91 [ # # # # : 0 : REGION_DEFINE_RECT_FUNC(intersect)
# # # # ]
92 [ # # # # : 0 : REGION_DEFINE_RECT_FUNC(xor)
# # # # ]
93 : :
94 : : GJS_JSAPI_RETURN_CONVENTION
95 : : static bool
96 : 0 : fill_rectangle(JSContext *context,
97 : : JS::HandleObject obj,
98 : : cairo_rectangle_int_t *rect)
99 : : {
100 : 0 : const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
101 : 0 : JS::RootedValue val(context);
102 : :
103 [ # # ]: 0 : if (!JS_GetPropertyById(context, obj, atoms.x(), &val))
104 : 0 : return false;
105 [ # # ]: 0 : if (!JS::ToInt32(context, val, &rect->x))
106 : 0 : return false;
107 : :
108 [ # # ]: 0 : if (!JS_GetPropertyById(context, obj, atoms.y(), &val))
109 : 0 : return false;
110 [ # # ]: 0 : if (!JS::ToInt32(context, val, &rect->y))
111 : 0 : return false;
112 : :
113 [ # # ]: 0 : if (!JS_GetPropertyById(context, obj, atoms.width(), &val))
114 : 0 : return false;
115 [ # # ]: 0 : if (!JS::ToInt32(context, val, &rect->width))
116 : 0 : return false;
117 : :
118 [ # # ]: 0 : if (!JS_GetPropertyById(context, obj, atoms.height(), &val))
119 : 0 : return false;
120 [ # # ]: 0 : if (!JS::ToInt32(context, val, &rect->height))
121 : 0 : return false;
122 : :
123 : 0 : return true;
124 : 0 : }
125 : :
126 : : GJS_JSAPI_RETURN_CONVENTION
127 : : static JSObject *
128 : 0 : make_rectangle(JSContext *context,
129 : : cairo_rectangle_int_t *rect)
130 : : {
131 : 0 : const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
132 : 0 : JS::RootedObject rect_obj(context, JS_NewPlainObject(context));
133 [ # # ]: 0 : if (!rect_obj)
134 : 0 : return nullptr;
135 : 0 : JS::RootedValue val(context);
136 : :
137 : 0 : val = JS::Int32Value(rect->x);
138 [ # # ]: 0 : if (!JS_SetPropertyById(context, rect_obj, atoms.x(), val))
139 : 0 : return nullptr;
140 : :
141 : 0 : val = JS::Int32Value(rect->y);
142 [ # # ]: 0 : if (!JS_SetPropertyById(context, rect_obj, atoms.y(), val))
143 : 0 : return nullptr;
144 : :
145 : 0 : val = JS::Int32Value(rect->width);
146 [ # # ]: 0 : if (!JS_SetPropertyById(context, rect_obj, atoms.width(), val))
147 : 0 : return nullptr;
148 : :
149 : 0 : val = JS::Int32Value(rect->height);
150 [ # # ]: 0 : if (!JS_SetPropertyById(context, rect_obj, atoms.height(), val))
151 : 0 : return nullptr;
152 : :
153 : 0 : return rect_obj;
154 : 0 : }
155 : :
156 : : GJS_JSAPI_RETURN_CONVENTION
157 : : static bool
158 : 0 : num_rectangles_func(JSContext *context,
159 : : unsigned argc,
160 : : JS::Value *vp)
161 : : {
162 [ # # # # ]: 0 : PRELUDE;
163 : : int n_rects;
164 : :
165 [ # # ]: 0 : if (!gjs_parse_call_args(context, "num_rectangles", argv, ""))
166 : 0 : return false;
167 : :
168 : 0 : n_rects = cairo_region_num_rectangles(this_region);
169 : 0 : argv.rval().setInt32(n_rects);
170 : 0 : RETURN_STATUS;
171 : 0 : }
172 : :
173 : : GJS_JSAPI_RETURN_CONVENTION
174 : : static bool
175 : 0 : get_rectangle_func(JSContext *context,
176 : : unsigned argc,
177 : : JS::Value *vp)
178 : : {
179 [ # # # # ]: 0 : PRELUDE;
180 : : int i;
181 : : JSObject *rect_obj;
182 : : cairo_rectangle_int_t rect;
183 : :
184 [ # # ]: 0 : if (!gjs_parse_call_args(context, "get_rectangle", argv, "i",
185 : : "rect", &i))
186 : 0 : return false;
187 : :
188 : 0 : cairo_region_get_rectangle(this_region, i, &rect);
189 : 0 : rect_obj = make_rectangle(context, &rect);
190 : :
191 : 0 : argv.rval().setObjectOrNull(rect_obj);
192 : 0 : RETURN_STATUS;
193 : 0 : }
194 : :
195 : : // clang-format off
196 : : const JSPropertySpec CairoRegion::proto_props[] = {
197 : : JS_STRING_SYM_PS(toStringTag, "Region", JSPROP_READONLY),
198 : : JS_PS_END};
199 : : // clang-format on
200 : :
201 : : const JSFunctionSpec CairoRegion::proto_funcs[] = {
202 : : JS_FN("union", union_func, 0, 0),
203 : : JS_FN("subtract", subtract_func, 0, 0),
204 : : JS_FN("intersect", intersect_func, 0, 0),
205 : : JS_FN("xor", xor_func, 0, 0),
206 : :
207 : : JS_FN("unionRectangle", union_rectangle_func, 0, 0),
208 : : JS_FN("subtractRectangle", subtract_rectangle_func, 0, 0),
209 : : JS_FN("intersectRectangle", intersect_rectangle_func, 0, 0),
210 : : JS_FN("xorRectangle", xor_rectangle_func, 0, 0),
211 : :
212 : : JS_FN("numRectangles", num_rectangles_func, 0, 0),
213 : : JS_FN("getRectangle", get_rectangle_func, 0, 0),
214 : : JS_FS_END};
215 : :
216 : 0 : cairo_region_t* CairoRegion::constructor_impl(JSContext* context,
217 : : const JS::CallArgs& argv) {
218 [ # # ]: 0 : if (!gjs_parse_call_args(context, "Region", argv, ""))
219 : 0 : return nullptr;
220 : :
221 : 0 : return cairo_region_create();
222 : : }
223 : :
224 : 0 : void CairoRegion::finalize_impl(JS::GCContext*, cairo_region_t* region) {
225 [ # # ]: 0 : if (!region)
226 : 0 : return;
227 : :
228 : 0 : cairo_region_destroy(region);
229 : : }
230 : :
231 : 0 : [[nodiscard]] static bool region_to_gi_argument(
232 : : JSContext* context, JS::Value value, const char* arg_name,
233 : : GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
234 : : GIArgument* arg) {
235 [ # # ]: 0 : if (value.isNull()) {
236 [ # # ]: 0 : if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
237 : : Gjs::AutoChar display_name{
238 : 0 : gjs_argument_display_name(arg_name, argument_type)};
239 : 0 : gjs_throw(context, "%s may not be null", display_name.get());
240 : 0 : return false;
241 : 0 : }
242 : :
243 : 0 : gjs_arg_unset(arg);
244 : 0 : return true;
245 : : }
246 : :
247 : 0 : JS::RootedObject obj(context, &value.toObject());
248 : : cairo_region_t *region;
249 : :
250 [ # # ]: 0 : if (!CairoRegion::for_js_typecheck(context, obj, ®ion))
251 : 0 : return false;
252 [ # # ]: 0 : if (transfer == GI_TRANSFER_EVERYTHING)
253 : 0 : cairo_region_destroy(region);
254 : :
255 : 0 : gjs_arg_set(arg, region);
256 : 0 : return true;
257 : 0 : }
258 : :
259 : : GJS_JSAPI_RETURN_CONVENTION
260 : 0 : static bool region_from_gi_argument(JSContext* context,
261 : : JS::MutableHandleValue value_p,
262 : : GIArgument* arg) {
263 : : JSObject* obj =
264 : 0 : CairoRegion::from_c_ptr(context, gjs_arg_get<cairo_region_t*>(arg));
265 [ # # ]: 0 : if (!obj)
266 : 0 : return false;
267 : :
268 : 0 : value_p.setObject(*obj);
269 : 0 : return true;
270 : : }
271 : :
272 : 0 : static bool region_release_argument(JSContext*, GITransfer transfer,
273 : : GIArgument* arg) {
274 [ # # ]: 0 : if (transfer != GI_TRANSFER_NOTHING)
275 : 0 : cairo_region_destroy(gjs_arg_get<cairo_region_t*>(arg));
276 : 0 : return true;
277 : : }
278 : :
279 : :
280 : 2 : void gjs_cairo_region_init(void) {
281 : : static GjsForeignInfo foreign_info = {region_to_gi_argument,
282 : : region_from_gi_argument,
283 : : region_release_argument};
284 : :
285 : 2 : gjs_struct_foreign_register("cairo", "Region", &foreign_info);
286 : 2 : }
|