void gr_apply_gradient_to_item (SPItem *item, SPGradient *gr, SPGradientType new_type, guint new_fill, bool do_fill, bool do_stroke) { SPStyle *style = SP_OBJECT_STYLE (item); if (do_fill) { if (style && (style->fill.isPaintserver()) && SP_IS_GRADIENT (SP_OBJECT_STYLE_FILL_SERVER (item))) { SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (item); if (SP_IS_LINEARGRADIENT (server)) { sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_LINEAR, true); } else if (SP_IS_RADIALGRADIENT (server)) { sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_RADIAL, true); } } else if (new_fill) { sp_item_set_gradient(item, gr, new_type, true); } } if (do_stroke) { if (style && (style->stroke.isPaintserver()) && SP_IS_GRADIENT (SP_OBJECT_STYLE_STROKE_SERVER (item))) { SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER (item); if (SP_IS_LINEARGRADIENT (server)) { sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_LINEAR, false); } else if (SP_IS_RADIALGRADIENT (server)) { sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_RADIAL, false); } } else if (!new_fill) { sp_item_set_gradient(item, gr, new_type, false); } } }
/** * Writes the gradient's internal vector (whether from its own stops, or * inherited from refs) into the gradient repr as svg:stop elements. */ void sp_gradient_repr_write_vector(SPGradient *gr) { g_return_if_fail(gr != NULL); g_return_if_fail(SP_IS_GRADIENT(gr)); Inkscape::XML::Document *xml_doc = gr->document->getReprDoc(); Inkscape::XML::Node *repr = gr->getRepr(); /* We have to be careful, as vector may be our own, so construct repr list at first */ GSList *cl = NULL; for (guint i = 0; i < gr->vector.stops.size(); i++) { Inkscape::CSSOStringStream os; Inkscape::XML::Node *child = xml_doc->createElement("svg:stop"); sp_repr_set_css_double(child, "offset", gr->vector.stops[i].offset); /* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no * sense for offset proportions. */ os << "stop-color:" << gr->vector.stops[i].color.toString() << ";stop-opacity:" << gr->vector.stops[i].opacity; child->setAttribute("style", os.str().c_str()); /* Order will be reversed here */ cl = g_slist_prepend(cl, child); } sp_gradient_repr_clear_vector(gr); /* And insert new children from list */ while (cl) { Inkscape::XML::Node *child = static_cast<Inkscape::XML::Node *>(cl->data); repr->addChild(child, NULL); Inkscape::GC::release(child); cl = g_slist_remove(cl, child); } }
/** * Returns the first of {src, src-\>ref-\>getObject(), * src-\>ref-\>getObject()-\>ref-\>getObject(),...} * for which \a match is true, or NULL if none found. * * The raison d'être of this routine is that it correctly handles cycles in the href chain (e.g., if * a gradient gives itself as its href, or if each of two gradients gives the other as its href). * * \pre SP_IS_GRADIENT(src). */ static SPGradient * chase_hrefs(SPGradient *const src, bool (*match)(SPGradient const *)) { g_return_val_if_fail(SP_IS_GRADIENT(src), NULL); /* Use a pair of pointers for detecting loops: p1 advances half as fast as p2. If there is a loop, then once p1 has entered the loop, we'll detect it the next time the distance between p1 and p2 is a multiple of the loop size. */ SPGradient *p1 = src, *p2 = src; bool do1 = false; for (;;) { if (match(p2)) { return p2; } p2 = p2->ref->getObject(); if (!p2) { return p2; } if (do1) { p1 = p1->ref->getObject(); } do1 = !do1; if ( p2 == p1 ) { /* We've been here before, so return NULL to indicate that no matching gradient found * in the chain. */ return NULL; } } }
/** * Gets called when the gradient is (re)attached to another gradient. */ void SPGradient::gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr) { if (old_ref) { gr->modified_connection.disconnect(); } if ( SP_IS_GRADIENT(ref) && ref != gr ) { gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&SPGradient::gradientRefModified), gr)); } // Per SVG, all unset attributes must be inherited from linked gradient. // So, as we're now (re)linked, we assign linkee's values to this gradient if they are not yet set - // but without setting the _set flags. // FIXME: do the same for gradientTransform too if (!gr->units_set) { gr->units = gr->fetchUnits(); } if (!gr->spread_set) { gr->spread = gr->fetchSpread(); } /// \todo Fixme: what should the flags (second) argument be? */ gradientRefModified(ref, 0, gr); }
// TODO: So a solid brush is a gradient with a swatch and zero stops? // Should we derive a new class for that? Or at least make this method // virtual and move it out of the way? bool SPPaintServer::isSolid() const { bool solid = false; if (swatch && SP_IS_GRADIENT(this)) { SPGradient *grad = SP_GRADIENT(this); if ( grad->hasStops() && (grad->getStopCount() == 0) ) { solid = true; } } return solid; }
static void sp_gradient_context_add_stops_between_selected_stops (SPGradientContext *rc) { SPDocument *doc = NULL; GrDrag *drag = rc->_grdrag; GSList *these_stops = NULL; GSList *next_stops = NULL; std::vector<Geom::Point> coords = sp_gradient_context_get_stop_intervals (drag, &these_stops, &next_stops); if (g_slist_length(these_stops) == 0 && drag->numSelected() == 1) { // if a single stop is selected, add between that stop and the next one GrDragger *dragger = (GrDragger *) drag->selected->data; for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { GrDraggable *d = (GrDraggable *) j->data; SPGradient *gradient = sp_item_gradient (d->item, d->fill_or_stroke); SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false); SPStop *this_stop = sp_get_stop_i (vector, d->point_i); SPStop *next_stop = sp_next_stop (this_stop); if (this_stop && next_stop) { these_stops = g_slist_prepend (these_stops, this_stop); next_stops = g_slist_prepend (next_stops, next_stop); } } } // now actually create the new stops GSList *i = these_stops; GSList *j = next_stops; for (; i != NULL && j != NULL; i = i->next, j = j->next) { SPStop *this_stop = (SPStop *) i->data; SPStop *next_stop = (SPStop *) j->data; gfloat offset = 0.5*(this_stop->offset + next_stop->offset); SPObject *parent = SP_OBJECT_PARENT(this_stop); if (SP_IS_GRADIENT (parent)) { doc = SP_OBJECT_DOCUMENT (parent); sp_vector_add_stop (SP_GRADIENT (parent), this_stop, next_stop, offset); sp_gradient_ensure_vector (SP_GRADIENT (parent)); } } if (g_slist_length(these_stops) > 0 && doc) { sp_document_done (doc, SP_VERB_CONTEXT_GRADIENT, _("Add gradient stop")); drag->updateDraggers(); // so that it does not automatically update draggers in idle loop, as this would deselect drag->local_change = true; // select all the old selected and new created draggers drag->selectByCoords(coords); } g_slist_free (these_stops); g_slist_free (next_stops); }
static SPObject * sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc) { static SPDocument *doc = NULL; static unsigned int edoc = FALSE; if (!current_doc) { return NULL; } /* Try to load from document */ if (!edoc && !doc) { gchar *gradients = g_build_filename(INKSCAPE_GRADIENTSDIR, "/gradients.svg", NULL); if (Inkscape::IO::file_test(gradients, G_FILE_TEST_IS_REGULAR)) { doc = SPDocument::createNewDoc(gradients, FALSE); } if (!doc) { gchar *gradients = g_build_filename(CREATE_GRADIENTSDIR, "/gradients.svg", NULL); if (Inkscape::IO::file_test(gradients, G_FILE_TEST_IS_REGULAR)) { doc = SPDocument::createNewDoc(gradients, FALSE); } g_free(gradients); if (doc) { doc->ensureUpToDate(); } else { edoc = TRUE; } } } if (!edoc && doc) { /* Get the gradient we want */ SPObject *object = doc->getObjectById(name); if (object && SP_IS_GRADIENT(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, NULL); Inkscape::GC::release(pat_repr); return object; } } return NULL; }
SPObject *get_stock_item(gchar const *urn, gboolean stock) { g_assert(urn != NULL); /* 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); SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPDocument *doc = desktop->getDocument(); SPDefs *defs = doc->getDefs(); if (!defs) { g_free(base); return NULL; } SPObject *object = NULL; if (!strcmp(base, "marker") && !stock) { for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_MARKER(child)) { object = child; } } } else if (!strcmp(base,"pattern") && !stock) { for ( SPObject *child = defs->firstChild() ; child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_PATTERN(child)) { object = child; } } } else if (!strcmp(base,"gradient") && !stock) { for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_GRADIENT(child)) { object = child; } } } if (object == NULL) { 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); } else if (!strcmp(base, "gradient")) { object = sp_gradient_load_from_svg(name_p, doc); } } g_free(base); g_free(name); if (object) { object->getRepr()->setAttribute("inkscape:isstock", "true"); } return object; } else { SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPDocument *doc = desktop->getDocument(); SPObject *object = doc->getObjectById(urn); return object; } }
void gr_read_selection (Inkscape::Selection *selection, GrDrag *drag, SPGradient **gr_selected, bool *gr_multi, SPGradientSpread *spr_selected, bool *spr_multi) { if (drag && drag->selected) { // GRADIENTFIXME: make this work for more than one selected dragger? GrDragger *dragger = (GrDragger*) drag->selected->data; for (GSList const* i = dragger->draggables; i != NULL; i = i->next) { // for all draggables of dragger GrDraggable *draggable = (GrDraggable *) i->data; SPGradient *gradient = sp_item_gradient_get_vector (draggable->item, draggable->fill_or_stroke); SPGradientSpread spread = sp_item_gradient_get_spread (draggable->item, draggable->fill_or_stroke); if (gradient != *gr_selected) { if (*gr_selected != NULL) { *gr_multi = true; } else { *gr_selected = gradient; } } if (spread != *spr_selected) { if (*spr_selected != INT_MAX) { *spr_multi = true; } else { *spr_selected = spread; } } } return; } // If no selected dragger, read desktop selection for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { SPItem *item = SP_ITEM(i->data); SPStyle *style = SP_OBJECT_STYLE (item); if (style && (style->fill.isPaintserver())) { SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (item); if (SP_IS_GRADIENT (server)) { SPGradient *gradient = sp_gradient_get_vector (SP_GRADIENT (server), false); SPGradientSpread spread = sp_gradient_get_spread (SP_GRADIENT (server)); if (gradient != *gr_selected) { if (*gr_selected != NULL) { *gr_multi = true; } else { *gr_selected = gradient; } } if (spread != *spr_selected) { if (*spr_selected != INT_MAX) { *spr_multi = true; } else { *spr_selected = spread; } } } } if (style && (style->stroke.isPaintserver())) { SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER (item); if (SP_IS_GRADIENT (server)) { SPGradient *gradient = sp_gradient_get_vector (SP_GRADIENT (server), false); SPGradientSpread spread = sp_gradient_get_spread (SP_GRADIENT (server)); if (gradient != *gr_selected) { if (*gr_selected != NULL) { *gr_multi = true; } else { *gr_selected = gradient; } } if (spread != *spr_selected) { if (*spr_selected != INT_MAX) { *spr_multi = true; } else { *spr_selected = spread; } } } } } }