1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Stock-items
4 *
5 * Stock Item management code
6 *
7 * Authors:
8 * John Cliff <simarilius@yahoo.com>
9 * Jon A. Cruz <jon@joncruz.org>
10 * Abhishek Sharma
11 *
12 * Copyright 2004 John Cliff
13 *
14 *
15 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
16 */
17
18 #define noSP_SS_VERBOSE
19
20 #include <cstring>
21 #include <glibmm/fileutils.h>
22
23 #include "path-prefix.h"
24
25 #include <xml/repr.h>
26 #include "inkscape.h"
27
28 #include "io/sys.h"
29 #include "io/resource.h"
30 #include "stock-items.h"
31
32 #include "object/sp-gradient.h"
33 #include "object/sp-pattern.h"
34 #include "object/sp-marker.h"
35 #include "object/sp-defs.h"
36
load_paint_doc(char const * basename,Inkscape::IO::Resource::Type type=Inkscape::IO::Resource::PAINT)37 static SPDocument *load_paint_doc(char const *basename,
38 Inkscape::IO::Resource::Type type = Inkscape::IO::Resource::PAINT)
39 {
40 using namespace Inkscape::IO::Resource;
41
42 for (Domain const domain : {SYSTEM, CREATE}) {
43 auto const filename = get_path_string(domain, type, basename);
44 if (Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) {
45 auto doc = SPDocument::createNewDoc(filename.c_str(), false);
46 if (doc) {
47 doc->ensureUpToDate();
48 return doc;
49 }
50 }
51 }
52
53 return nullptr;
54 }
55
56 // FIXME: these should be merged with the icon loading code so they
57 // can share a common file/doc cache. This function should just
58 // take the dir to look in, and the file to check for, and cache
59 // against that, rather than the existing copy/paste code seen here.
60
sp_marker_load_from_svg(gchar const * name,SPDocument * current_doc)61 static SPObject * sp_marker_load_from_svg(gchar const *name, SPDocument *current_doc)
62 {
63 if (!current_doc) {
64 return nullptr;
65 }
66 /* Try to load from document */
67 static SPDocument *doc = load_paint_doc("markers.svg", Inkscape::IO::Resource::MARKERS);
68
69 if (doc) {
70 /* Get the marker we want */
71 SPObject *object = doc->getObjectById(name);
72 if (object && SP_IS_MARKER(object)) {
73 SPDefs *defs = current_doc->getDefs();
74 Inkscape::XML::Document *xml_doc = current_doc->getReprDoc();
75 Inkscape::XML::Node *mark_repr = object->getRepr()->duplicate(xml_doc);
76 defs->getRepr()->addChild(mark_repr, nullptr);
77 SPObject *cloned_item = current_doc->getObjectByRepr(mark_repr);
78 Inkscape::GC::release(mark_repr);
79 return cloned_item;
80 }
81 }
82 return nullptr;
83 }
84
85
86 static SPObject *
sp_pattern_load_from_svg(gchar const * name,SPDocument * current_doc)87 sp_pattern_load_from_svg(gchar const *name, SPDocument *current_doc)
88 {
89 if (!current_doc) {
90 return nullptr;
91 }
92 /* Try to load from document */
93 static SPDocument *doc = load_paint_doc("patterns.svg");
94
95 if (doc) {
96 /* Get the pattern we want */
97 SPObject *object = doc->getObjectById(name);
98 if (object && SP_IS_PATTERN(object)) {
99 SPDefs *defs = current_doc->getDefs();
100 Inkscape::XML::Document *xml_doc = current_doc->getReprDoc();
101 Inkscape::XML::Node *pat_repr = object->getRepr()->duplicate(xml_doc);
102 defs->getRepr()->addChild(pat_repr, nullptr);
103 Inkscape::GC::release(pat_repr);
104 return object;
105 }
106 }
107 return nullptr;
108 }
109
110
111 static SPObject *
sp_gradient_load_from_svg(gchar const * name,SPDocument * current_doc)112 sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc)
113 {
114 if (!current_doc) {
115 return nullptr;
116 }
117 /* Try to load from document */
118 static SPDocument *doc = load_paint_doc("gradients.svg");
119
120 if (doc) {
121 /* Get the gradient we want */
122 SPObject *object = doc->getObjectById(name);
123 if (object && SP_IS_GRADIENT(object)) {
124 SPDefs *defs = current_doc->getDefs();
125 Inkscape::XML::Document *xml_doc = current_doc->getReprDoc();
126 Inkscape::XML::Node *pat_repr = object->getRepr()->duplicate(xml_doc);
127 defs->getRepr()->addChild(pat_repr, nullptr);
128 Inkscape::GC::release(pat_repr);
129 return object;
130 }
131 }
132 return nullptr;
133 }
134
135 // get_stock_item returns a pointer to an instance of the desired stock object in the current doc
136 // if necessary it will import the object. Copes with name clashes through use of the inkscape:stockid property
137 // This should be set to be the same as the id in the library file.
138
get_stock_item(gchar const * urn,gboolean stock)139 SPObject *get_stock_item(gchar const *urn, gboolean stock)
140 {
141 g_assert(urn != nullptr);
142
143 /* check its an inkscape URN */
144 if (!strncmp (urn, "urn:inkscape:", 13)) {
145
146 gchar const *e = urn + 13;
147 int a = 0;
148 gchar * name = g_strdup(e);
149 gchar *name_p = name;
150 while (*name_p != ':' && *name_p != '\0'){
151 name_p++;
152 a++;
153 }
154
155 if (*name_p ==':') {
156 name_p++;
157 }
158
159 gchar * base = g_strndup(e, a);
160
161 SPDocument *doc = SP_ACTIVE_DOCUMENT;
162 SPDefs *defs = doc->getDefs();
163 if (!defs) {
164 g_free(base);
165 return nullptr;
166 }
167 SPObject *object = nullptr;
168 if (!strcmp(base, "marker") && !stock) {
169 for (auto& child: defs->children)
170 {
171 if (child.getRepr()->attribute("inkscape:stockid") &&
172 !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) &&
173 SP_IS_MARKER(&child))
174 {
175 object = &child;
176 }
177 }
178 }
179 else if (!strcmp(base,"pattern") && !stock) {
180 for (auto& child: defs->children)
181 {
182 if (child.getRepr()->attribute("inkscape:stockid") &&
183 !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) &&
184 SP_IS_PATTERN(&child))
185 {
186 object = &child;
187 }
188 }
189 }
190 else if (!strcmp(base,"gradient") && !stock) {
191 for (auto& child: defs->children)
192 {
193 if (child.getRepr()->attribute("inkscape:stockid") &&
194 !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) &&
195 SP_IS_GRADIENT(&child))
196 {
197 object = &child;
198 }
199 }
200 }
201
202 if (object == nullptr) {
203
204 if (!strcmp(base, "marker")) {
205 object = sp_marker_load_from_svg(name_p, doc);
206 }
207 else if (!strcmp(base, "pattern")) {
208 object = sp_pattern_load_from_svg(name_p, doc);
209 }
210 else if (!strcmp(base, "gradient")) {
211 object = sp_gradient_load_from_svg(name_p, doc);
212 }
213 }
214
215 g_free(base);
216 g_free(name);
217
218 if (object) {
219 object->setAttribute("inkscape:isstock", "true");
220 }
221
222 return object;
223 }
224
225 else {
226
227 SPDocument *doc = SP_ACTIVE_DOCUMENT;
228 SPObject *object = doc->getObjectById(urn);
229
230 return object;
231 }
232 }
233
234 /*
235 Local Variables:
236 mode:c++
237 c-file-style:"stroustrup"
238 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
239 indent-tabs-mode:nil
240 fill-column:99
241 End:
242 */
243 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
244