sp-style-elem.cpp revision 4a659284a4e327168cfc7b81687934e517543b2a
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include <libcroco/cr-parser.h>
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "xml/node-event-vector.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "xml/repr.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "document.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "sp-style-elem.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "attributes.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "style.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshusing Inkscape::XML::TEXT_NODE;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#include "sp-factory.h"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshnamespace {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh SPObject* createStyle() {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh return new SPStyleElem();
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh bool styleRegistered = SPFactory::instance().registerObject("svg:style", createStyle);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshSPStyleElem::SPStyleElem() : SPObject() {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh media_set_all(this->media);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh this->is_css = false;
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshSPStyleElem::~SPStyleElem() {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshvoid SPStyleElem::set(unsigned int key, const gchar* value) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh switch (key) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh case SP_ATTR_TYPE: {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (!value) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* TODO: `type' attribute is required. Give error message as per
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing. */
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh is_css = false;
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh } else {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh /* fixme: determine what whitespace is allowed. Will probably need to ask on SVG
fba63a357654d8b3e84c60007e40aa698cd45d19miklosh list; though the relevant RFC may give info on its lexer. */
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh is_css = ( g_ascii_strncasecmp(value, "text/css", 8) == 0
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh && ( value[8] == '\0' ||
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh value[8] == ';' ) );
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh break;
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh }
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh#if 0 /* unfinished */
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh case SP_ATTR_MEDIA: {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parse_media(style_elem, value);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh break;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh#endif
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh /* title is ignored. */
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh default: {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh SPObject::set(key, value);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh break;
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh}
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emikloshstatic void
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emikloshchild_add_rm_cb(Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *,
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh void *const data)
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh{
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh SPObject *obj = reinterpret_cast<SPObject *>(data);
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh g_assert(data != NULL);
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh obj->read_content();
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh}
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emikloshstatic void
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emikloshcontent_changed_cb(Inkscape::XML::Node *, gchar const *, gchar const *,
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh void *const data)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh{
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh SPObject *obj = reinterpret_cast<SPObject *>(data);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_assert(data != NULL);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh obj->read_content();
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
68664e00e2372534b4df2fdc5f54f836bafece18miklosh
1cda9431ef400135f5e1bd899a94b921bdad0eafmikloshstatic void
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshchild_order_changed_cb(Inkscape::XML::Node *, Inkscape::XML::Node *,
68664e00e2372534b4df2fdc5f54f836bafece18miklosh Inkscape::XML::Node *, Inkscape::XML::Node *,
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh void *const data)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh{
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh SPObject *obj = reinterpret_cast<SPObject *>(data);
a4d12a5147f3d1d6b568a326e39ef5dca384248dmiklosh g_assert(data != NULL);
1667116521643e2475184b048e0abb77a2aa9735miklosh obj->read_content();
cb814cb0df20053ca3ef16ce55da474435daf045miklosh}
cb814cb0df20053ca3ef16ce55da474435daf045miklosh
cb814cb0df20053ca3ef16ce55da474435daf045mikloshInkscape::XML::Node* SPStyleElem::write(Inkscape::XML::Document* xml_doc, Inkscape::XML::Node* repr, guint flags) {
cb814cb0df20053ca3ef16ce55da474435daf045miklosh if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh repr = xml_doc->createElement("svg:style");
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
1cda9431ef400135f5e1bd899a94b921bdad0eafmiklosh if (flags & SP_OBJECT_WRITE_BUILD) {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh g_warning("nyi: Forming <style> content for SP_OBJECT_WRITE_BUILD.");
68664e00e2372534b4df2fdc5f54f836bafece18miklosh /* fixme: Consider having the CRStyleSheet be a member of SPStyleElem, and then
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh pretty-print to a string s, then repr->addChild(xml_doc->createTextNode(s), NULL). */
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh }
cb814cb0df20053ca3ef16ce55da474435daf045miklosh if (is_css) {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh repr->setAttribute("type", "text/css");
1667116521643e2475184b048e0abb77a2aa9735miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* todo: media */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh SPObject::write(xml_doc, repr, flags);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh return repr;
1667116521643e2475184b048e0abb77a2aa9735miklosh}
1667116521643e2475184b048e0abb77a2aa9735miklosh
1667116521643e2475184b048e0abb77a2aa9735miklosh
1667116521643e2475184b048e0abb77a2aa9735miklosh/** Returns the concatenation of the content of the text children of the specified object. */
1667116521643e2475184b048e0abb77a2aa9735mikloshstatic GString *
1667116521643e2475184b048e0abb77a2aa9735mikloshconcat_children(Inkscape::XML::Node const &repr)
1667116521643e2475184b048e0abb77a2aa9735miklosh{
1667116521643e2475184b048e0abb77a2aa9735miklosh GString *ret = g_string_sized_new(0);
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh // effic: 0 is just to catch bugs. Increase to something reasonable.
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh for (Inkscape::XML::Node const *rch = repr.firstChild(); rch != NULL; rch = rch->next()) {
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh if ( rch->type() == TEXT_NODE ) {
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh ret = g_string_append(ret, rch->content());
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh }
1667116521643e2475184b048e0abb77a2aa9735miklosh }
1667116521643e2475184b048e0abb77a2aa9735miklosh return ret;
1667116521643e2475184b048e0abb77a2aa9735miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh/* Callbacks for SAC-style libcroco parser. */
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshenum StmtType { NO_STMT, FONT_FACE_STMT, NORMAL_RULESET_STMT };
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
68664e00e2372534b4df2fdc5f54f836bafece18mikloshstruct ParseTmp
68664e00e2372534b4df2fdc5f54f836bafece18miklosh{
68664e00e2372534b4df2fdc5f54f836bafece18miklosh CRStyleSheet *const stylesheet;
68664e00e2372534b4df2fdc5f54f836bafece18miklosh StmtType stmtType;
68664e00e2372534b4df2fdc5f54f836bafece18miklosh CRStatement *currStmt;
68664e00e2372534b4df2fdc5f54f836bafece18miklosh unsigned magic;
68664e00e2372534b4df2fdc5f54f836bafece18miklosh static unsigned const ParseTmp_magic = 0x23474397; // from /dev/urandom
68664e00e2372534b4df2fdc5f54f836bafece18miklosh
68664e00e2372534b4df2fdc5f54f836bafece18miklosh ParseTmp(CRStyleSheet *const stylesheet) :
68664e00e2372534b4df2fdc5f54f836bafece18miklosh stylesheet(stylesheet),
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh stmtType(NO_STMT),
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh currStmt(NULL),
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh magic(ParseTmp_magic)
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh { }
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh bool hasMagic() const {
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh return magic == ParseTmp_magic;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh ~ParseTmp()
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh {
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh g_return_if_fail(hasMagic());
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh magic = 0;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh};
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emikloshstatic void
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshstart_selector_cb(CRDocHandler *a_handler,
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRSelector *a_sel_list)
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh{
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(a_handler && a_sel_list);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(a_handler->app_data != NULL);
1667116521643e2475184b048e0abb77a2aa9735miklosh ParseTmp &parse_tmp = *static_cast<ParseTmp *>(a_handler->app_data);
1667116521643e2475184b048e0abb77a2aa9735miklosh g_return_if_fail(parse_tmp.hasMagic());
1667116521643e2475184b048e0abb77a2aa9735miklosh if ( (parse_tmp.currStmt != NULL)
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh || (parse_tmp.stmtType != NO_STMT) ) {
1667116521643e2475184b048e0abb77a2aa9735miklosh g_warning("Expecting currStmt==NULL and stmtType==0 (NO_STMT) at start of ruleset, but found currStmt=%p, stmtType=%u",
1667116521643e2475184b048e0abb77a2aa9735miklosh static_cast<void *>(parse_tmp.currStmt), unsigned(parse_tmp.stmtType));
1667116521643e2475184b048e0abb77a2aa9735miklosh // fixme: Check whether we need to unref currStmt if non-NULL.
1667116521643e2475184b048e0abb77a2aa9735miklosh }
1667116521643e2475184b048e0abb77a2aa9735miklosh CRStatement *ruleset = cr_statement_new_ruleset(parse_tmp.stylesheet, a_sel_list, NULL, NULL);
1667116521643e2475184b048e0abb77a2aa9735miklosh g_return_if_fail(ruleset && ruleset->type == RULESET_STMT);
1667116521643e2475184b048e0abb77a2aa9735miklosh parse_tmp.stmtType = NORMAL_RULESET_STMT;
1667116521643e2475184b048e0abb77a2aa9735miklosh parse_tmp.currStmt = ruleset;
1667116521643e2475184b048e0abb77a2aa9735miklosh}
1667116521643e2475184b048e0abb77a2aa9735miklosh
1667116521643e2475184b048e0abb77a2aa9735mikloshstatic void
1667116521643e2475184b048e0abb77a2aa9735mikloshend_selector_cb(CRDocHandler *a_handler,
1667116521643e2475184b048e0abb77a2aa9735miklosh CRSelector *a_sel_list)
1667116521643e2475184b048e0abb77a2aa9735miklosh{
1667116521643e2475184b048e0abb77a2aa9735miklosh g_return_if_fail(a_handler && a_sel_list);
1667116521643e2475184b048e0abb77a2aa9735miklosh g_return_if_fail(a_handler->app_data != NULL);
1667116521643e2475184b048e0abb77a2aa9735miklosh ParseTmp &parse_tmp = *static_cast<ParseTmp *>(a_handler->app_data);
1667116521643e2475184b048e0abb77a2aa9735miklosh g_return_if_fail(parse_tmp.hasMagic());
1667116521643e2475184b048e0abb77a2aa9735miklosh CRStatement *const ruleset = parse_tmp.currStmt;
1667116521643e2475184b048e0abb77a2aa9735miklosh if (parse_tmp.stmtType == NORMAL_RULESET_STMT
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh && ruleset
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh && ruleset->type == RULESET_STMT
68664e00e2372534b4df2fdc5f54f836bafece18miklosh && ruleset->kind.ruleset->sel_list == a_sel_list)
1cda9431ef400135f5e1bd899a94b921bdad0eafmiklosh {
68664e00e2372534b4df2fdc5f54f836bafece18miklosh parse_tmp.stylesheet->statements = cr_statement_append(parse_tmp.stylesheet->statements,
68664e00e2372534b4df2fdc5f54f836bafece18miklosh ruleset);
68664e00e2372534b4df2fdc5f54f836bafece18miklosh } else {
68664e00e2372534b4df2fdc5f54f836bafece18miklosh g_warning("Found stmtType=%u, stmt=%p, stmt.type=%u, ruleset.sel_list=%p, a_sel_list=%p.",
68664e00e2372534b4df2fdc5f54f836bafece18miklosh unsigned(parse_tmp.stmtType),
68664e00e2372534b4df2fdc5f54f836bafece18miklosh ruleset,
68664e00e2372534b4df2fdc5f54f836bafece18miklosh unsigned(ruleset->type),
68664e00e2372534b4df2fdc5f54f836bafece18miklosh ruleset->kind.ruleset->sel_list,
68664e00e2372534b4df2fdc5f54f836bafece18miklosh a_sel_list);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh parse_tmp.currStmt = NULL;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parse_tmp.stmtType = NO_STMT;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshstatic void
1667116521643e2475184b048e0abb77a2aa9735mikloshstart_font_face_cb(CRDocHandler *a_handler,
c53f16f52840e8c0f2be9c1cc3af633c0ba1552emiklosh CRParsingLocation *)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh{
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(a_handler->app_data != NULL);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ParseTmp &parse_tmp = *static_cast<ParseTmp *>(a_handler->app_data);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(parse_tmp.hasMagic());
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (parse_tmp.stmtType != NO_STMT || parse_tmp.currStmt != NULL) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_warning("Expecting currStmt==NULL and stmtType==0 (NO_STMT) at start of @font-face, but found currStmt=%p, stmtType=%u",
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh static_cast<void *>(parse_tmp.currStmt), unsigned(parse_tmp.stmtType));
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // fixme: Check whether we need to unref currStmt if non-NULL.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parse_tmp.stmtType = FONT_FACE_STMT;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parse_tmp.currStmt = NULL;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
fba63a357654d8b3e84c60007e40aa698cd45d19miklosh
fba63a357654d8b3e84c60007e40aa698cd45d19mikloshstatic void
fba63a357654d8b3e84c60007e40aa698cd45d19mikloshend_font_face_cb(CRDocHandler *a_handler)
fba63a357654d8b3e84c60007e40aa698cd45d19miklosh{
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh g_return_if_fail(a_handler->app_data != NULL);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ParseTmp &parse_tmp = *static_cast<ParseTmp *>(a_handler->app_data);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(parse_tmp.hasMagic());
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (parse_tmp.stmtType != FONT_FACE_STMT || parse_tmp.currStmt != NULL) {
d27f5758e12c3107ee69e66702043931e0756f6bmiklosh g_warning("Expecting currStmt==NULL and stmtType==1 (FONT_FACE_STMT) at end of @font-face, but found currStmt=%p, stmtType=%u",
d27f5758e12c3107ee69e66702043931e0756f6bmiklosh static_cast<void *>(parse_tmp.currStmt), unsigned(parse_tmp.stmtType));
d27f5758e12c3107ee69e66702043931e0756f6bmiklosh // fixme: Check whether we need to unref currStmt if non-NULL.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parse_tmp.currStmt = NULL;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parse_tmp.stmtType = NO_STMT;
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh}
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshstatic void
3711b3e25395437ee0a09dbbb2a76d999c4ef322mikloshproperty_cb(CRDocHandler *const a_handler,
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh CRString *const a_name,
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh CRTerm *const a_value, gboolean const a_important)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh{
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(a_handler && a_name);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh g_return_if_fail(a_handler->app_data != NULL);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh ParseTmp &parse_tmp = *static_cast<ParseTmp *>(a_handler->app_data);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh g_return_if_fail(parse_tmp.hasMagic());
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (parse_tmp.stmtType == FONT_FACE_STMT) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (parse_tmp.currStmt != NULL) {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh g_warning("Found non-NULL currStmt %p though stmtType==FONT_FACE_STMT.", parse_tmp.currStmt);
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh }
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh /* We currently ignore @font-face descriptors. */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh return;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRStatement *const ruleset = parse_tmp.currStmt;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(ruleset
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh && ruleset->type == RULESET_STMT
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh && parse_tmp.stmtType == NORMAL_RULESET_STMT);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRDeclaration *const decl = cr_declaration_new(ruleset, cr_string_dup(a_name), a_value);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(decl);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh decl->important = a_important;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRStatus const append_status = cr_statement_ruleset_append_decl(ruleset, decl);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_return_if_fail(append_status == CR_OK);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshvoid SPStyleElem::read_content() {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* fixme: If there's more than one <style> element in a document, then the document stylesheet
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * will be set to a random one of them, even switching between them.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh *
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * However, I don't see in the spec what's supposed to happen when there are multiple <style>
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * elements. The wording suggests that <style>'s content should be a full stylesheet.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * http://www.w3.org/TR/REC-CSS2/cascade.html#cascade says that "The author specifies style
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * sheets for a source document according to the conventions of the document language. For
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * instance, in HTML, style sheets may be included in the document or linked externally."
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * (Note the plural in both sentences.) Whereas libcroco's CRCascade allows only one author
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * stylesheet. CRStyleSheet has no next/prev members that I can see, nor can I see any append
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * stuff.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh *
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * Dodji replies "right, that's *bug*"; just an unexpected oversight.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh //XML Tree being used directly here while it shouldn't be.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh GString *const text = concat_children(*getRepr());
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRParser *parser = cr_parser_new_from_buf(reinterpret_cast<guchar *>(text->str), text->len,
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CR_UTF_8, FALSE);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh /* I see a cr_statement_parse_from_buf for returning a CRStatement*, but no corresponding
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh cr_stylesheet_parse_from_buf. And cr_statement_parse_from_buf takes a char*, not a
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRInputBuf, and doesn't provide a way for calling it in a loop over the one buffer.
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh (I.e. it doesn't tell us where it got up to in the buffer.)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh There's also the generic cr_parser_parse_stylesheet (or just cr_parser_parse), but that
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh just calls user-supplied callbacks rather than constructing a CRStylesheet.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRDocHandler *sac_handler = cr_doc_handler_new();
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // impl: ref_count inited to 0, so cr_parser_destroy suffices to delete sac_handler.
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh g_return_if_fail(sac_handler); // out of memory
dc4f69a188c203f2fdc65f22d0d57904a8c52dd7miklosh CRStyleSheet *const stylesheet = cr_stylesheet_new(NULL);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh ParseTmp parse_tmp(stylesheet);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sac_handler->app_data = &parse_tmp;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sac_handler->start_selector = start_selector_cb;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sac_handler->end_selector = end_selector_cb;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sac_handler->start_font_face = start_font_face_cb;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sac_handler->end_font_face = end_font_face_cb;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh sac_handler->property = property_cb;
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* todo: start_media, end_media. */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* todo: Test error condition. */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh cr_parser_set_sac_handler(parser, sac_handler);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh CRStatus const parse_status = cr_parser_parse(parser);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_assert(sac_handler->app_data == &parse_tmp);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (parse_status == CR_OK) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh cr_cascade_set_sheet(document->style_cascade, stylesheet, ORIGIN_AUTHOR);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh } else {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if (parse_status != CR_PARSING_ERROR) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh g_printerr("parsing error code=%u\n", unsigned(parse_status));
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* Better than nothing. TODO: Improve libcroco's error handling. At a minimum, add a
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh strerror-like function so that we can give a string rather than an integer. */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh /* TODO: Improve error diagnosis stuff in inkscape. We'd like a panel showing the
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh errors/warnings/unsupported features of the current document. */
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh cr_parser_destroy(parser);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh //requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // Style references via class= do not, and actually cannot, use autoupdating URIReferences.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // Therefore, if an object refers to a stylesheet which has not yet loaded when the object is
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // being loaded (e.g. if the stylesheet is below or inside the object in XML), its class= has
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // no effect (bug 1491639). Below is a partial hack that fixes this for a single case: when
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // the <style> is a child of the object that uses a style from it. It just forces the parent of
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // <style> to reread its style as soon as the stylesheet is fully loaded. Naturally, this won't
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh // work if the user of the stylesheet is its grandparent or precedent.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh if ( parent ) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh parent->style->readFromObject( parent );
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh/**
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh * Does addListener(fns, data) on \a repr and all of its descendents.
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh */
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshstatic void
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshrec_add_listener(Inkscape::XML::Node &repr,
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Inkscape::XML::NodeEventVector const *const fns, void *const data)
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh{
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh repr.addListener(fns, data);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh for (Inkscape::XML::Node *child = repr.firstChild(); child != NULL; child = child->next()) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh rec_add_listener(*child, fns, data);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh }
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9mikloshvoid SPStyleElem::build(SPDocument *document, Inkscape::XML::Node *repr) {
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh read_content();
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh readAttr( "type" );
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh readAttr( "media" );
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh static Inkscape::XML::NodeEventVector const nodeEventVector = {
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh child_add_rm_cb, // child_added
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh child_add_rm_cb, // child_removed
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh NULL, // attr_changed
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh content_changed_cb, // content_changed
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh child_order_changed_cb, // order_changed
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh };
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh rec_add_listener(*repr, &nodeEventVector, this);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh SPObject::build(document, repr);
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh}
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh/*
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh Local Variables:
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh mode:c++
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh c-file-style:"stroustrup"
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh indent-tabs-mode:nil
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh fill-column:99
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh End:
3711b3e25395437ee0a09dbbb2a76d999c4ef322miklosh*/
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
7a7fa095a483e8b652af9f00e5169f62c84f09b9miklosh