From ccfaafdc59f88d185fe5cd5c3a83bf6364c361a5 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 7 Aug 2017 11:20:55 +0200 Subject: Add support for imported style sheets via @import to Inkscape. --- src/document.cpp | 2 + src/document.h | 3 + src/sp-style-elem.cpp | 171 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 123 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index 3a7d4408f..d9c709626 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -96,6 +96,7 @@ SPDocument::SPDocument() : rroot(NULL), root(NULL), style_cascade(cr_cascade_new(NULL, NULL, NULL)), + style_sheet(NULL), uri(NULL), base(NULL), name(NULL), @@ -177,6 +178,7 @@ SPDocument::~SPDocument() { priv->resources.clear(); } + // This also destroys all attached stylesheets cr_cascade_unref(style_cascade); style_cascade = NULL; diff --git a/src/document.h b/src/document.h index 92f53559f..b60561c32 100644 --- a/src/document.h +++ b/src/document.h @@ -113,10 +113,13 @@ public: Inkscape::XML::Document *rdoc; ///< Our Inkscape::XML::Document Inkscape::XML::Node *rroot; ///< Root element of Inkscape::XML::Document + private: SPRoot *root; ///< Our SPRoot + public: CRCascade *style_cascade; + CRStyleSheet *style_sheet; protected: char *uri; ///< A filename (not a URI yet), or NULL diff --git a/src/sp-style-elem.cpp b/src/sp-style-elem.cpp index c15f810e9..c87b5436d 100644 --- a/src/sp-style-elem.cpp +++ b/src/sp-style-elem.cpp @@ -6,6 +6,12 @@ #include "sp-root.h" #include "attributes.h" #include "style.h" + +// For external style sheets +#include "io/resource.h" +#include +#include + using Inkscape::XML::TEXT_NODE; SPStyleElem::SPStyleElem() : SPObject() { @@ -124,13 +130,15 @@ struct ParseTmp CRStyleSheet *const stylesheet; StmtType stmtType; CRStatement *currStmt; + SPDocument *const document; // Need file location for '@import' unsigned magic; static unsigned const ParseTmp_magic = 0x23474397; // from /dev/urandom - ParseTmp(CRStyleSheet *const stylesheet) : + ParseTmp(CRStyleSheet *const stylesheet, SPDocument *const document) : stylesheet(stylesheet), stmtType(NO_STMT), currStmt(NULL), + document(document), magic(ParseTmp_magic) { } @@ -145,6 +153,70 @@ struct ParseTmp } }; +CRParser* +parser_init(CRStyleSheet *const stylesheet, SPDocument *const document); + +static void +import_style_cb (CRDocHandler *a_handler, + GList *a_media_list, + CRString *a_uri, + CRString *a_uri_default_ns, + CRParsingLocation *a_location) +{ + /* a_uri_default_ns is set to NULL and is unused by libcroco */ + + // Get document + g_return_if_fail(a_handler && a_uri); + g_return_if_fail(a_handler->app_data != NULL); + ParseTmp &parse_tmp = *static_cast(a_handler->app_data); + g_return_if_fail(parse_tmp.hasMagic()); + + SPDocument* document = parse_tmp.document; + if (!document) { + std::cerr << "import_style_cb: No document!" << std::endl; + return; + } + if (!document->getURI()) { + std::cerr << "import_style_cb: Document URI is NULL" << std::endl; + return; + } + + // Get file + Glib::ustring import_file = + Inkscape::IO::Resource::get_filename (document->getURI(), a_uri->stryng->str); + + // Parse file + CRStyleSheet *stylesheet = cr_stylesheet_new (NULL); + CRParser *parser = parser_init(stylesheet, document); + CRStatus const parse_status = + cr_parser_parse_file (parser, reinterpret_cast(import_file.c_str()), CR_UTF_8); + if (parse_status == CR_OK) { + cr_stylesheet_append_import (document->style_sheet, stylesheet); + } else { + std::cerr << "import_style_cb: Could not parse: " << import_file << std::endl; + cr_stylesheet_destroy (stylesheet); + } + + // Need to delete ParseTmp created by parser_init() + CRDocHandler *sac_handler = NULL; + cr_parser_get_sac_handler (parser, &sac_handler); + ParseTmp *parse_new = reinterpret_cast(sac_handler->app_data); + cr_parser_destroy(parser); + delete parse_new; +}; + +/* NOT USED, incomplete libcroco implementation */ +static void +import_style_result_cb (CRDocHandler *a_this, + GList *a_media_list, + CRString *a_uri, + CRString *a_uri_default_ns, + CRStyleSheet *a_sheet) +{ + /* a_uri_default_ns and a_sheet are set to NULL and are unused by libcroco */ + std::cerr << "import_style_result_cb: unimplemented" << std::endl; +}; + static void start_selector_cb(CRDocHandler *a_handler, CRSelector *a_sel_list) @@ -251,6 +323,26 @@ property_cb(CRDocHandler *const a_handler, g_return_if_fail(append_status == CR_OK); } +CRParser* +parser_init(CRStyleSheet *const stylesheet, SPDocument *const document) { + + ParseTmp *parse_tmp = new ParseTmp(stylesheet, document); + + CRDocHandler *sac_handler = cr_doc_handler_new(); + sac_handler->app_data = parse_tmp; + sac_handler->import_style = import_style_cb; + sac_handler->start_selector = start_selector_cb; + sac_handler->end_selector = end_selector_cb; + sac_handler->start_font_face = start_font_face_cb; + sac_handler->end_font_face = end_font_face_cb; + sac_handler->property = property_cb; + + CRParser *parser = cr_parser_new (NULL); + cr_parser_set_sac_handler(parser, sac_handler); + + return parser; +} + void update_style_recursively( SPObject *object ) { if (object) { // std::cout << "update_style_recursively: " @@ -265,52 +357,35 @@ void update_style_recursively( SPObject *object ) { } void SPStyleElem::read_content() { - /* fixme: If there's more than one