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: 2010 Red Hat, Inc.
4 : : // SPDX-FileCopyrightText: 2020 Philip Chimento <philip.chimento@gmail.com>
5 : :
6 : : #include <config.h>
7 : :
8 : : #include <cairo.h>
9 : : #include <girepository/girepository.h> // for GIArgument, GITransfer, ...
10 : :
11 : : #include <js/PropertyDescriptor.h> // for JSPROP_READONLY
12 : : #include <js/PropertySpec.h>
13 : : #include <js/RootingAPI.h>
14 : : #include <js/TypeDecls.h>
15 : : #include <js/Value.h>
16 : : #include <jsapi.h> // for JS_NewObjectWithGivenProto
17 : :
18 : : #include "gi/arg-inl.h"
19 : : #include "gi/arg.h"
20 : : #include "gi/foreign.h"
21 : : #include "gjs/auto.h"
22 : : #include "gjs/enum-utils.h"
23 : : #include "gjs/jsapi-util.h"
24 : : #include "gjs/macros.h"
25 : : #include "modules/cairo-private.h"
26 : :
27 : : // clang-format off
28 : : const JSPropertySpec CairoPath::proto_props[] = {
29 : : JS_STRING_SYM_PS(toStringTag, "Path", JSPROP_READONLY),
30 : : JS_PS_END};
31 : : // clang-format on
32 : :
33 : : /**
34 : : * CairoPath::take_c_ptr():
35 : : *
36 : : * Same as CWrapper::from_c_ptr(), but always takes ownership of the pointer
37 : : * rather than copying it.
38 : : */
39 : 3 : JSObject* CairoPath::take_c_ptr(JSContext* cx, cairo_path_t* ptr) {
40 : 3 : JS::RootedObject proto(cx, CairoPath::prototype(cx));
41 [ - + ]: 3 : if (!proto)
42 : 0 : return nullptr;
43 : :
44 : 3 : JS::RootedObject wrapper(
45 : 3 : cx, JS_NewObjectWithGivenProto(cx, &CairoPath::klass, proto));
46 [ - + ]: 3 : if (!wrapper)
47 : 0 : return nullptr;
48 : :
49 : 3 : CairoPath::init_private(wrapper, ptr);
50 : :
51 : 3 : debug_lifecycle(ptr, wrapper, "take_c_ptr");
52 : :
53 : 3 : return wrapper;
54 : 3 : }
55 : :
56 : 5 : void CairoPath::finalize_impl(JS::GCContext*, cairo_path_t* path) {
57 [ - + ]: 5 : if (!path)
58 : 0 : return;
59 : 5 : cairo_path_destroy(path);
60 : : }
61 : :
62 : 2 : GJS_JSAPI_RETURN_CONVENTION static bool path_to_gi_argument(
63 : : JSContext* cx, JS::Value value, const char* arg_name,
64 : : GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
65 : : GIArgument* arg) {
66 [ - + ]: 2 : if (value.isNull()) {
67 [ # # ]: 0 : if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
68 : 0 : Gjs::AutoChar display_name{
69 : 0 : gjs_argument_display_name(arg_name, argument_type)};
70 : 0 : gjs_throw(cx, "%s may not be null", display_name.get());
71 : 0 : return false;
72 : 0 : }
73 : :
74 : 0 : gjs_arg_unset(arg);
75 : 0 : return true;
76 : : }
77 : :
78 [ - + ]: 2 : if (!value.isObject()) {
79 : 0 : Gjs::AutoChar display_name{
80 : 0 : gjs_argument_display_name(arg_name, argument_type)};
81 : 0 : gjs_throw(cx, "%s is not a Cairo.Path", display_name.get());
82 : 0 : return false;
83 : 0 : }
84 : :
85 : 2 : JS::RootedObject path_wrapper{cx, &value.toObject()};
86 : 2 : cairo_path_t* s = CairoPath::for_js(cx, path_wrapper);
87 [ - + ]: 2 : if (!s)
88 : 0 : return false;
89 [ + + ]: 2 : if (transfer == GI_TRANSFER_EVERYTHING)
90 : 1 : s = CairoPath::copy_ptr(s);
91 : :
92 : 2 : gjs_arg_set(arg, s);
93 : 2 : return true;
94 : 2 : }
95 : :
96 : : GJS_JSAPI_RETURN_CONVENTION
97 : 2 : static bool path_from_gi_argument(JSContext* cx, JS::MutableHandleValue value_p,
98 : : GIArgument* arg) {
99 : 2 : JSObject* obj = CairoPath::from_c_ptr(cx, gjs_arg_get<cairo_path_t*>(arg));
100 [ - + ]: 2 : if (!obj)
101 : 0 : return false;
102 : :
103 : 2 : value_p.setObject(*obj);
104 : 2 : return true;
105 : : }
106 : :
107 : 3 : static bool path_release_argument(JSContext*, GITransfer transfer,
108 : : GIArgument* arg) {
109 [ + + ]: 3 : if (transfer != GI_TRANSFER_NOTHING)
110 : 2 : cairo_path_destroy(gjs_arg_get<cairo_path_t*>(arg));
111 : 3 : return true;
112 : : }
113 : :
114 : 2 : void gjs_cairo_path_init() {
115 : : static GjsForeignInfo foreign_info = {
116 : : path_to_gi_argument, path_from_gi_argument, path_release_argument};
117 : 2 : gjs_struct_foreign_register("cairo", "Path", &foreign_info);
118 : 2 : }
119 : :
120 : : // Adapted from PyGObject cairo code
121 : 3 : cairo_path_t* CairoPath::copy_ptr(cairo_path_t* path) {
122 : : cairo_surface_t* surface =
123 : 3 : cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
124 : 3 : cairo_t* cr = cairo_create(surface);
125 : 3 : cairo_append_path(cr, path);
126 : 3 : cairo_path_t* copy = cairo_copy_path(cr);
127 : 3 : cairo_destroy(cr);
128 : 3 : cairo_surface_destroy(surface);
129 : :
130 : 3 : return copy;
131 : : }
|