summaryrefslogtreecommitdiffstats
path: root/src/helper/stock-items.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:50:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:50:49 +0000
commitc853ffb5b2f75f5a889ed2e3ef89b818a736e87a (patch)
tree7d13a0883bb7936b84d6ecdd7bc332b41ed04bee /src/helper/stock-items.cpp
parentInitial commit. (diff)
downloadinkscape-c853ffb5b2f75f5a889ed2e3ef89b818a736e87a.tar.xz
inkscape-c853ffb5b2f75f5a889ed2e3ef89b818a736e87a.zip
Adding upstream version 1.3+ds.upstream/1.3+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/helper/stock-items.cpp')
-rw-r--r--src/helper/stock-items.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/helper/stock-items.cpp b/src/helper/stock-items.cpp
new file mode 100644
index 0000000..6b77937
--- /dev/null
+++ b/src/helper/stock-items.cpp
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Stock-items
+ *
+ * Stock Item management code
+ *
+ * Authors:
+ * John Cliff <simarilius@yahoo.com>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
+ *
+ * Copyright 2004 John Cliff
+ *
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+#include <glibmm/fileutils.h>
+
+#include "libnrtype/font-factory.h"
+#include "path-prefix.h"
+
+#include <xml/repr.h>
+#include "inkscape.h"
+
+#include "io/sys.h"
+#include "io/resource.h"
+#include "pattern-manipulation.h"
+#include "stock-items.h"
+#include "manipulation/copy-resource.h"
+#include "object/sp-gradient.h"
+#include "object/sp-pattern.h"
+#include "object/sp-marker.h"
+#include "object/sp-defs.h"
+#include "util/statics.h"
+
+// Stock objects kept in documents with controlled life time
+struct Documents {
+ static Documents& get();
+ std::vector<std::shared_ptr<SPDocument>> documents;
+};
+
+Documents& Documents::get() {
+ // make sure font factory is initialized first, that way Documents will be destructed before it
+ FontFactory::get();
+
+ static auto factory = Inkscape::Util::Static<Documents>();
+ return factory.get();
+}
+
+std::vector<std::shared_ptr<SPDocument>> sp_get_paint_documents(const std::function<bool (SPDocument*)>& filter) {
+ auto& storage = Documents::get();
+
+ if (storage.documents.empty()) {
+ using namespace Inkscape::IO::Resource;
+ auto files = get_filenames(SYSTEM, PAINT, {".svg"});
+ auto share = get_filenames(SHARED, PAINT, {".svg"});
+ auto user = get_filenames(USER, PAINT, {".svg"});
+ files.insert(files.end(), user.begin(), user.end());
+ files.insert(files.end(), share.begin(), share.end());
+ for (auto&& file : files) {
+ if (Glib::file_test(file, Glib::FILE_TEST_IS_REGULAR)) {
+ std::shared_ptr<SPDocument> doc(SPDocument::createNewDoc(file.c_str(), false));
+ if (doc) {
+ doc->ensureUpToDate(); // update, so patterns referencing clippaths render properly
+ storage.documents.push_back(std::move(doc));
+ }
+ else {
+ g_warning("File %s not loaded.", file.c_str());
+ }
+ }
+ }
+ }
+
+ std::vector<std::shared_ptr<SPDocument>> out;
+ std::copy_if(storage.documents.begin(), storage.documents.end(), std::back_inserter(out), [=](const std::shared_ptr<SPDocument>& doc) {
+ return filter(doc.get());
+ });
+
+ return out;
+}
+
+static SPDocument *load_paint_doc(char const *basename,
+ Inkscape::IO::Resource::Type type = Inkscape::IO::Resource::PAINT)
+{
+ using namespace Inkscape::IO::Resource;
+
+ for (Domain const domain : {SYSTEM, CREATE}) {
+ auto const filename = get_path_string(domain, type, basename);
+ if (Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) {
+ auto doc = SPDocument::createNewDoc(filename.c_str(), false);
+ if (doc) {
+ doc->ensureUpToDate();
+ return doc;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+// FIXME: these should be merged with the icon loading code so they
+// can share a common file/doc cache. This function should just
+// take the dir to look in, and the file to check for, and cache
+// against that, rather than the existing copy/paste code seen here.
+
+static SPObject * sp_marker_load_from_svg(gchar const *name, SPDocument *current_doc)
+{
+ if (!current_doc) {
+ return nullptr;
+ }
+ /* Try to load from document */
+ static SPDocument *doc = load_paint_doc("markers.svg", Inkscape::IO::Resource::MARKERS);
+
+ if (doc) {
+ /* Get the marker we want */
+ SPObject *object = doc->getObjectById(name);
+ if (object && is<SPMarker>(object)) {
+ SPDefs *defs = current_doc->getDefs();
+ Inkscape::XML::Document *xml_doc = current_doc->getReprDoc();
+ Inkscape::XML::Node *mark_repr = object->getRepr()->duplicate(xml_doc);
+ defs->getRepr()->addChild(mark_repr, nullptr);
+ SPObject *cloned_item = current_doc->getObjectByRepr(mark_repr);
+ Inkscape::GC::release(mark_repr);
+ return cloned_item;
+ }
+ }
+ return nullptr;
+}
+
+
+static SPObject* sp_pattern_load_from_svg(gchar const *name, SPDocument *current_doc, SPDocument* source_doc) {
+ if (!current_doc || !source_doc) {
+ return nullptr;
+ }
+ // Try to load from document
+ // Get the pattern we want
+ if (auto pattern = cast<SPPattern>(source_doc->getObjectById(name))) {
+ return sp_copy_resource(pattern, current_doc);
+ }
+ return nullptr;
+}
+
+
+static SPObject *
+sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc)
+{
+ if (!current_doc) {
+ return nullptr;
+ }
+ /* Try to load from document */
+ static SPDocument *doc = load_paint_doc("gradients.svg");
+
+ if (doc) {
+ /* Get the gradient we want */
+ SPObject *object = doc->getObjectById(name);
+ if (object && is<SPGradient>(object)) {
+ SPDefs *defs = current_doc->getDefs();
+ Inkscape::XML::Document *xml_doc = current_doc->getReprDoc();
+ Inkscape::XML::Node *pat_repr = object->getRepr()->duplicate(xml_doc);
+ defs->getRepr()->addChild(pat_repr, nullptr);
+ Inkscape::GC::release(pat_repr);
+ return object;
+ }
+ }
+ return nullptr;
+}
+
+// get_stock_item returns a pointer to an instance of the desired stock object in the current doc
+// if necessary it will import the object. Copes with name clashes through use of the inkscape:stockid property
+// This should be set to be the same as the id in the library file.
+
+SPObject *get_stock_item(gchar const *urn, bool stock, SPDocument* stock_doc)
+{
+ g_assert(urn != nullptr);
+
+ /* check its an inkscape URN */
+ if (!strncmp (urn, "urn:inkscape:", 13)) {
+
+ gchar const *e = urn + 13;
+ int a = 0;
+ gchar * name = g_strdup(e);
+ gchar *name_p = name;
+ while (*name_p != ':' && *name_p != '\0'){
+ name_p++;
+ a++;
+ }
+
+ if (*name_p ==':') {
+ name_p++;
+ }
+
+ gchar * base = g_strndup(e, a);
+
+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
+ SPDefs *defs = doc->getDefs();
+ if (!defs) {
+ g_free(base);
+ return nullptr;
+ }
+ SPObject *object = nullptr;
+ if (!strcmp(base, "marker") && !stock) {
+ for (auto& child: defs->children)
+ {
+ if (child.getRepr()->attribute("inkscape:stockid") &&
+ !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) &&
+ is<SPMarker>(&child))
+ {
+ object = &child;
+ }
+ }
+ }
+ else if (!strcmp(base,"pattern") && !stock) {
+ for (auto& child: defs->children)
+ {
+ if (child.getRepr()->attribute("inkscape:stockid") &&
+ !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) &&
+ is<SPPattern>(&child))
+ {
+ object = &child;
+ }
+ }
+ }
+ else if (!strcmp(base,"gradient") && !stock) {
+ for (auto& child: defs->children)
+ {
+ if (child.getRepr()->attribute("inkscape:stockid") &&
+ !strcmp(name_p, child.getRepr()->attribute("inkscape:stockid")) &&
+ is<SPGradient>(&child))
+ {
+ object = &child;
+ }
+ }
+ }
+
+ if (object == nullptr) {
+
+ if (!strcmp(base, "marker")) {
+ object = sp_marker_load_from_svg(name_p, doc);
+ }
+ else if (!strcmp(base, "pattern")) {
+ object = sp_pattern_load_from_svg(name_p, doc, stock_doc);
+ if (object) {
+ object->getRepr()->setAttribute("inkscape:collect", "always");
+ }
+ }
+ else if (!strcmp(base, "gradient")) {
+ object = sp_gradient_load_from_svg(name_p, doc);
+ }
+ }
+
+ g_free(base);
+ g_free(name);
+
+ if (object) {
+ object->setAttribute("inkscape:isstock", "true");
+ }
+
+ return object;
+ }
+
+ else {
+
+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
+ SPObject *object = doc->getObjectById(urn);
+
+ return object;
+ }
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :