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