filter-chemistry.cpp revision 07b7f1aaaf1087716e784a50cf574a059f7018d3
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Various utility methods for filters
506aa7c68b127eefb0197e329af7e9abcc3ebc98Garrett D'Amore * Hugo Rodrigues
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Niko Kiirala
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Jon A. Cruz <jon@joncruz.org>
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Abhishek Sharma
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Copyright (C) 2006-2008 authors
00687e57f8c568d4f8fb446b6530a2942842292fartem * Released under GNU GPL, read the file 'COPYING' for more information
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Count how many times the filter is used by the styles of o and its
7b840e52d558c34b70cbcde044d8d79852d169d2phitran * descendants
18c2aff776a775d34a4c9893a4c72e0434d68e36artemstatic guint count_filter_hrefs(SPObject *o, SPFilter *filter)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem for ( SPObject *child = o->firstChild(); child; child = child->getNext() ) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Sets a suitable filter effects area according to given blur radius,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * expansion and object size.
18c2aff776a775d34a4c9893a4c72e0434d68e36artemstatic void set_filter_area(Inkscape::XML::Node *repr, gdouble radius,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // TODO: make this more generic, now assumed, that only the blur
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // being added can affect the required filter area
18c2aff776a775d34a4c9893a4c72e0434d68e36artem double rx = radius * (expansionY != 0 ? (expansion / expansionY) : 1);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem double ry = radius * (expansionX != 0 ? (expansion / expansionX) : 1);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (width != 0 && height != 0 && (2.4 * rx > width * 0.1 || 2.4 * ry > height * 0.1)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // If not within the default 10% margin (see
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // http://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion), specify margins
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // The 2.4 is an empirical coefficient: at that distance the cutoff is practically invisible
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // (the opacity at 2.4*radius is about 3e-3)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // TODO: set it in UserSpaceOnUse instead?
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sp_repr_set_svg_double(repr, "width", 1 + 2 * xmargin);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sp_repr_set_svg_double(repr, "height", 1 + 2 * ymargin);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Document *xml_doc = document->getReprDoc();
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // create a new filter
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Append the new filter node to defs
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // get corresponding object
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artemfilter_add_primitive(SPFilter *filter, const Inkscape::Filters::FilterPrimitiveType type)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Document *xml_doc = filter->document->getReprDoc();
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //create filter primitive node
18c2aff776a775d34a4c9893a4c72e0434d68e36artem repr = xml_doc->createElement(FPConverter.get_key(type).c_str());
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // set default values
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore case Inkscape::Filters::NR_FILTER_CONVOLVEMATRIX:
18c2aff776a775d34a4c9893a4c72e0434d68e36artem repr->setAttribute("kernelMatrix", "0 0 0 0 0 0 0 0 0");
b453864f3587ccc3324d7a3b0438a1e542dcfde7Lin Guo - Sun Microsystems case Inkscape::Filters::NR_FILTER_FLOOD:
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //set primitive as child of filter node
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // XML tree being used directly while/where it shouldn't be...
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // get corresponding object
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPFilterPrimitive *prim = SP_FILTER_PRIMITIVE( filter->document->getObjectByRepr(repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Creates a filter with blur primitive of specified radius for an item with the given matrix expansion, width and height
18c2aff776a775d34a4c9893a4c72e0434d68e36artemnew_filter_gaussian_blur (SPDocument *document, gdouble radius, double expansion, double expansionX, double expansionY, double width, double height)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Document *xml_doc = document->getReprDoc();
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // create a new filter
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //repr->setAttribute("inkscape:collect", "always");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem set_filter_area(repr, radius, expansion, expansionX, expansionY,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //create feGaussianBlur node
18c2aff776a775d34a4c9893a4c72e0434d68e36artem b_repr = xml_doc->createElement("svg:feGaussianBlur");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //b_repr->setAttribute("inkscape:collect", "always");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //set stdDeviation attribute
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //set feGaussianBlur as child of filter node
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Append the new filter node to defs
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // get corresponding object
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPGaussianBlur *b = SP_GAUSSIANBLUR( document->getObjectByRepr(b_repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Creates a simple filter with a blend primitive and a blur primitive of specified radius for
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * an item with the given matrix expansion, width and height
18c2aff776a775d34a4c9893a4c72e0434d68e36artemnew_filter_blend_gaussian_blur (SPDocument *document, const char *blendmode, gdouble radius, double expansion,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem double expansionX, double expansionY, double width, double height)
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Document *xml_doc = document->getReprDoc();
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // create a new filter
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Append the new filter node to defs
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // get corresponding object
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPFilter *f = SP_FILTER( document->getObjectByRepr(repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Gaussian blur primitive
18c2aff776a775d34a4c9893a4c72e0434d68e36artem set_filter_area(repr, radius, expansion, expansionX, expansionY, width, height);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //create feGaussianBlur node
18c2aff776a775d34a4c9893a4c72e0434d68e36artem b_repr = xml_doc->createElement("svg:feGaussianBlur");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //set stdDeviation attribute
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //set feGaussianBlur as child of filter node
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPGaussianBlur *b = SP_GAUSSIANBLUR( document->getObjectByRepr(b_repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Blend primitive
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems // set feBlend as child of filter node
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems // Enable background image buffer for document
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems Inkscape::XML::Node *root = b_repr->root();
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems if (!root->attribute("enable-background")) {
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems root->setAttribute("enable-background", "new");
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems SPFeBlend *b = SP_FEBLEND(document->getObjectByRepr(b_repr));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Creates a simple filter for the given item with blend and blur primitives, using the
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * specified mode and radius, respectively
18c2aff776a775d34a4c9893a4c72e0434d68e36artemnew_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, gdouble radius)
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems Geom::OptRect const r = item->getBboxDesktop(SPItem::GEOMETRIC_BBOX);
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems width = r->dimensions()[Geom::X];
8b80e8cb6855118d46f605e91b5ed4ce83417395Lin Guo - Sun Microsystems height= r->dimensions()[Geom::Y];
18c2aff776a775d34a4c9893a4c72e0434d68e36artem return (new_filter_blend_gaussian_blur (document, mode, radius, i2d.descrim(), i2d.expansionX(), i2d.expansionY(), width, height));
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Modifies the gaussian blur applied to the item.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * If no filters are applied to given item, creates a new blur filter.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * If a filter is applied and it contains a blur, modify that blur.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * If the filter doesn't contain blur, a blur is added to the filter.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * Should there be more references to modified filter, that filter is
18c2aff776a775d34a4c9893a4c72e0434d68e36artem * duplicated, so that other elements referring that filter are not modified.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem/* TODO: this should be made more generic, not just for blurs */
18c2aff776a775d34a4c9893a4c72e0434d68e36artemSPFilter *modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *item,
18c2aff776a775d34a4c9893a4c72e0434d68e36artem return new_filter_simple_from_item(document, item, "normal", radius);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem SPFilter *filter = SP_FILTER(item->style->getFilter());
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Document *xml_doc = document->getReprDoc();
00687e57f8c568d4f8fb446b6530a2942842292fartem // If there are more users for this filter, duplicate it
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (filter->hrefcount > count_filter_hrefs(item, filter)) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Node *repr = item->style->getFilter()->getRepr()->duplicate(xml_doc);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem filter = SP_FILTER( document->getObjectByRepr(repr) );
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Determine the required standard deviation value
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Get the object size
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Geom::OptRect const r = item->getBboxDesktop(SPItem::GEOMETRIC_BBOX);
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Set the filter effects area
18c2aff776a775d34a4c9893a4c72e0434d68e36artem Inkscape::XML::Node *repr = item->style->getFilter()->getRepr();
18c2aff776a775d34a4c9893a4c72e0434d68e36artem set_filter_area(repr, radius, expansion, i2d.expansionX(),
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // Search for gaussian blur primitives. If found, set the stdDeviation
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // of the first one and return.
18c2aff776a775d34a4c9893a4c72e0434d68e36artem if (strcmp("svg:feGaussianBlur", primitive->name()) == 0) {
18c2aff776a775d34a4c9893a4c72e0434d68e36artem // If there were no gaussian blur primitives, create a new one
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //create feGaussianBlur node
076d97abc78bcba2f2216859fe2c6913cc7aff32Phi Tran b_repr = xml_doc->createElement("svg:feGaussianBlur");
7b840e52d558c34b70cbcde044d8d79852d169d2phitran //b_repr->setAttribute("inkscape:collect", "always");
18c2aff776a775d34a4c9893a4c72e0434d68e36artem //set stdDeviation attribute
18c2aff776a775d34a4c9893a4c72e0434d68e36artem sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation);
42a7bded1b1244af097afdc88654381a3d3879f9jacobs //set feGaussianBlur as child of filter node
42a7bded1b1244af097afdc88654381a3d3879f9jacobs sp_repr_css_change_recursive(item->getRepr(), css, "style");
while (primitive) {
return MAX(x, y);