Logo Search packages:      
Sourcecode: inkscape version File versions

filter.cpp

/*
 * Authors:
 *   Ted Gould <ted@gould.cx>
 *
 * Copyright (C) 2008 Authors
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */

#include "desktop.h"
#include "selection.h"
#include "document-private.h"
#include "sp-item.h"
#include "util/glib-list-iterators.h"
#include "extension/extension.h"
#include "extension/effect.h"
#include "extension/system.h"
#include "xml/repr.h"
#include "xml/simple-node.h"
#include "xml/attribute-record.h"

#include "filter.h"

namespace Inkscape {
namespace Extension {
namespace Internal {
namespace Filter {

Filter::Filter() :
            Inkscape::Extension::Implementation::Implementation(),
            _filter(NULL) {
      return;
}

Filter::Filter(gchar const * filter) :
            Inkscape::Extension::Implementation::Implementation(),
            _filter(filter) {
      return;
}

Filter::~Filter (void) {
      if (_filter != NULL) {
            _filter = NULL;
      }

      return;
}

bool
Filter::load (Inkscape::Extension::Extension *module)
{
      return true;
}

Inkscape::Extension::Implementation::ImplementationDocumentCache *
Filter::newDocCache (Inkscape::Extension::Extension * ext, Inkscape::UI::View::View * doc)
{
      return NULL;
}

gchar const *
Filter::get_filter_text (Inkscape::Extension::Extension * ext)
{
      return _filter;
}

Inkscape::XML::Document *
Filter::get_filter (Inkscape::Extension::Extension * ext) {
      gchar const * filter = get_filter_text(ext);
      return sp_repr_read_mem(filter, strlen(filter), NULL);
}

void 
Filter::merge_filters (Inkscape::XML::Node * to, Inkscape::XML::Node * from, Inkscape::XML::Document * doc, gchar * srcGraphic, gchar * srcGraphicAlpha)
{
      if (from == NULL) return;

      // copy attributes
    for ( Inkscape::Util::List<Inkscape::XML::AttributeRecord const> iter = from->attributeList() ;
          iter ; ++iter ) {
            gchar const * attr = g_quark_to_string(iter->key);
            //printf("Attribute List: %s\n", attr);
            if (!strcmp(attr, "id")) continue; // nope, don't copy that one!
            to->setAttribute(attr, from->attribute(attr));

            if (!strcmp(attr, "in") || !strcmp(attr, "in2") || !strcmp(attr, "in3")) {
                  if (srcGraphic != NULL && !strcmp(from->attribute(attr), "SourceGraphic")) {
                        to->setAttribute(attr, srcGraphic);
                  }

                  if (srcGraphicAlpha != NULL && !strcmp(from->attribute(attr), "SourceAlpha")) {
                        to->setAttribute(attr, srcGraphicAlpha);
                  }
            }
      }

      // for each child call recursively
      for (Inkscape::XML::Node * from_child = from->firstChild();
                from_child != NULL ; from_child = from_child->next()) {
            Glib::ustring name = "svg:";
            name += from_child->name();
            
            Inkscape::XML::Node * to_child = doc->createElement(name.c_str());
            to->appendChild(to_child);
            merge_filters(to_child, from_child, doc, srcGraphic, srcGraphicAlpha);

            if (from_child == from->firstChild() && !strcmp("filter", from->name()) && srcGraphic != NULL && to_child->attribute("in") == NULL) {
                  to_child->setAttribute("in", srcGraphic);
            }
    Inkscape::GC::release(to_child);
      }
}

#define FILTER_SRC_GRAPHIC       "fbSourceGraphic"
#define FILTER_SRC_GRAPHIC_ALPHA "fbSourceGraphicAlpha"

void
Filter::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document, Inkscape::Extension::Implementation::ImplementationDocumentCache * docCache)
{
      Inkscape::XML::Document *filterdoc = get_filter(module);
      if (filterdoc == NULL) {
            return; // could not parse the XML source of the filter; typically parser will stderr a warning
      }

      //printf("Calling filter effect\n");
    Inkscape::Selection * selection = ((SPDesktop *)document)->selection;

    using Inkscape::Util::GSListConstIterator;
    // TODO need to properly refcount the items, at least
    std::list<SPItem *> items;
    items.insert<GSListConstIterator<SPItem *> >(items.end(), selection->itemList(), NULL);

      Inkscape::XML::Document * xmldoc = sp_document_repr_doc(document->doc());
      Inkscape::XML::Node * defsrepr = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(document->doc()));

    for(std::list<SPItem *>::iterator item = items.begin();
            item != items.end(); item++) {
        SPItem * spitem = *item;
            Inkscape::XML::Node * node = SP_OBJECT_REPR(spitem);

            SPCSSAttr * css = sp_repr_css_attr(node, "style");
            gchar const * filter = sp_repr_css_property(css, "filter", NULL);

            if (filter == NULL) {

                  Inkscape::XML::Node * newfilterroot = xmldoc->createElement("svg:filter");
                  defsrepr->appendChild(newfilterroot);

                  Glib::ustring url = "url(#"; url += newfilterroot->attribute("id"); url += ")";

                  merge_filters(newfilterroot, filterdoc->root(), xmldoc);
  
      Inkscape::GC::release(newfilterroot);

                  sp_repr_css_set_property(css, "filter", url.c_str());
                  sp_repr_css_set(node, css, "style");
            } else {
                  if (strncmp(filter, "url(#", strlen("url(#")) || filter[strlen(filter) - 1] != ')') {
                        // This is not url(#id) -- we can't handle it
                        continue;
                  }

                  gchar * lfilter = g_strndup(filter + 5, strlen(filter) - 6);
                  Inkscape::XML::Node * filternode = NULL;
                  for (Inkscape::XML::Node * child = defsrepr->firstChild(); child != NULL; child = child->next()) {
                        if (!strcmp(lfilter, child->attribute("id"))) {
                              filternode = child;
                              break;
                        }
                  }
                  g_free(lfilter);

                  if (filternode == NULL) {
                        continue;
                  }

                  filternode->lastChild()->setAttribute("result", FILTER_SRC_GRAPHIC);

                  Inkscape::XML::Node * alpha = xmldoc->createElement("svg:feColorMatrix");
                  alpha->setAttribute("result", FILTER_SRC_GRAPHIC_ALPHA);
                  alpha->setAttribute("in", FILTER_SRC_GRAPHIC); // not required, but we're being explicit
                  alpha->setAttribute("values", "0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0");
                  filternode->appendChild(alpha);

                  merge_filters(filternode, filterdoc->root(), xmldoc, FILTER_SRC_GRAPHIC, FILTER_SRC_GRAPHIC_ALPHA);

      Inkscape::GC::release(alpha);
            }
    }

    return;
}

#include "extension/internal/clear-n_.h"

void
Filter::filter_init (gchar const * id, gchar const * name, gchar const * submenu, gchar const * tip, gchar const * filter)
{
      gchar * xml_str = g_strdup_printf(
        "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
            "<name>%s</name>\n"
            "<id>org.inkscape.effect.filter.%s</id>\n"
            "<effect>\n"
                "<object-type>all</object-type>\n"
                "<effects-menu>\n"
                    "<submenu name=\"" N_("Filters") "\" />\n"
                                          "<submenu name=\"%s\"/>\n"
                "</effects-menu>\n"
                "<menu-tip>%s</menu-tip>\n"
            "</effect>\n"
        "</inkscape-extension>\n", name, id, submenu, tip);
    Inkscape::Extension::build_from_mem(xml_str, new Filter::Filter(filter));
      g_free(xml_str);
    return;
}

}; /* namespace Filter */
}; /* namespace Internal */
}; /* namespace Extension */
}; /* namespace Inkscape */


Generated by  Doxygen 1.6.0   Back to index