File: cairo-path.cpp

package info (click to toggle)
gjs 1.86.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,724 kB
  • sloc: cpp: 39,075; javascript: 30,720; ansic: 15,971; sh: 1,759; python: 772; xml: 135; makefile: 40
file content (129 lines) | stat: -rw-r--r-- 3,832 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2010 Red Hat, Inc.
// SPDX-FileCopyrightText: 2020 Philip Chimento <philip.chimento@gmail.com>

#include <config.h>

#include <cairo.h>

#include <js/PropertyDescriptor.h>  // for JSPROP_READONLY
#include <js/PropertySpec.h>
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
#include <jsapi.h>  // for JS_NewObjectWithGivenProto

#include "gi/arg-inl.h"
#include "gi/arg.h"
#include "gi/cwrapper.h"
#include "gi/foreign.h"
#include "gjs/auto.h"
#include "gjs/enum-utils.h"
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
#include "modules/cairo-private.h"

// clang-format off
const JSPropertySpec CairoPath::proto_props[] = {
    JS_STRING_SYM_PS(toStringTag, "Path", JSPROP_READONLY),
    JS_PS_END};
// clang-format on

/*
 * CairoPath::take_c_ptr():
 * Same as CWrapper::from_c_ptr(), but always takes ownership of the pointer
 * rather than copying it.
 */
JSObject* CairoPath::take_c_ptr(JSContext* cx, cairo_path_t* ptr) {
    JS::RootedObject proto(cx, CairoPath::prototype(cx));
    if (!proto)
        return nullptr;

    JS::RootedObject wrapper(
        cx, JS_NewObjectWithGivenProto(cx, &CairoPath::klass, proto));
    if (!wrapper)
        return nullptr;

    CairoPath::init_private(wrapper, ptr);

    debug_lifecycle(ptr, wrapper, "take_c_ptr");

    return wrapper;
}

void CairoPath::finalize_impl(JS::GCContext*, cairo_path_t* path) {
    if (!path)
        return;
    cairo_path_destroy(path);
}

GJS_JSAPI_RETURN_CONVENTION static bool path_to_gi_argument(
    JSContext* cx, JS::Value value, const char* arg_name,
    GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags,
    GIArgument* arg) {
    if (value.isNull()) {
        if (!(flags & GjsArgumentFlags::MAY_BE_NULL)) {
            Gjs::AutoChar display_name{
                gjs_argument_display_name(arg_name, argument_type)};
            gjs_throw(cx, "%s may not be null", display_name.get());
            return false;
        }

        gjs_arg_unset(arg);
        return true;
    }

    if (!value.isObject()) {
        Gjs::AutoChar display_name{
            gjs_argument_display_name(arg_name, argument_type)};
        gjs_throw(cx, "%s is not a Cairo.Path", display_name.get());
        return false;
    }

    JS::RootedObject path_wrapper{cx, &value.toObject()};
    cairo_path_t* s = CairoPath::for_js(cx, path_wrapper);
    if (!s)
        return false;
    if (transfer == GI_TRANSFER_EVERYTHING)
        s = CairoPath::copy_ptr(s);

    gjs_arg_set(arg, s);
    return true;
}

GJS_JSAPI_RETURN_CONVENTION
static bool path_from_gi_argument(JSContext* cx, JS::MutableHandleValue value_p,
                                  GIArgument* arg) {
    JSObject* obj = CairoPath::from_c_ptr(cx, gjs_arg_get<cairo_path_t*>(arg));
    if (!obj)
        return false;

    value_p.setObject(*obj);
    return true;
}

static bool path_release_argument(JSContext*, GITransfer transfer,
                                  GIArgument* arg) {
    if (transfer != GI_TRANSFER_NOTHING)
        cairo_path_destroy(gjs_arg_get<cairo_path_t*>(arg));
    return true;
}

void gjs_cairo_path_init(void) {
    static GjsForeignInfo foreign_info = {
        path_to_gi_argument, path_from_gi_argument, path_release_argument};
    gjs_struct_foreign_register("cairo", "Path", &foreign_info);
}

// Adapted from PyGObject cairo code
cairo_path_t* CairoPath::copy_ptr(cairo_path_t* path) {
    cairo_surface_t* surface =
        cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
    cairo_t* cr = cairo_create(surface);
    cairo_append_path(cr, path);
    cairo_path_t* copy = cairo_copy_path(cr);
    cairo_destroy(cr);
    cairo_surface_destroy(surface);

    return copy;
}