sp-flowtext.cpp revision 2f99f08590b9e75d4c4f33cc4374db3e8f97f15d
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_class_init(SPFlowtextClass *klass);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_init(SPFlowtext *group);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_dispose(GObject *object);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_remove_child(SPObject *object, Inkscape::XML::Node *child);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_update(SPObject *object, SPCtx *ctx, guint flags);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_modified(SPObject *object, guint flags);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_set(SPObject *object, unsigned key, gchar const *value);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_print(SPItem *item, SPPrintContext *ctx);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic gchar *sp_flowtext_description(SPItem *item);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic NRArenaItem *sp_flowtext_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenstatic void sp_flowtext_hide(SPItem *item, unsigned key);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen group_type = g_type_register_static(SP_TYPE_ITEM, "SPFlowtext", &group_info, (GTypeFlags)0);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen GObjectClass *object_class = (GObjectClass *) klass;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen SPObjectClass *sp_object_class = (SPObjectClass *) klass;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen SPItemClass *item_class = (SPItemClass *) klass;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen parent_class = (SPItemClass *)g_type_class_ref(SP_TYPE_ITEM);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen sp_object_class->child_added = sp_flowtext_child_added;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen sp_object_class->remove_child = sp_flowtext_remove_child;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen sp_object_class->modified = sp_flowtext_modified;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen item_class->description = sp_flowtext_description;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen new (&group->layout) Inkscape::Text::Layout();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelensp_flowtext_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if (((SPObjectClass *) (parent_class))->child_added)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen (* ((SPObjectClass *) (parent_class))->child_added)(object, child, ref);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen object->requestModified(SP_OBJECT_MODIFIED_FLAG);
ea7d8c8f5752fe8fe4f814fc01baf6f250825817Johan Engelen/* fixme: hide (Lauris) */
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelensp_flowtext_remove_child(SPObject *object, Inkscape::XML::Node *child)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if (((SPObjectClass *) (parent_class))->remove_child)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen (* ((SPObjectClass *) (parent_class))->remove_child)(object, child);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen object->requestModified(SP_OBJECT_MODIFIED_FLAG);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelensp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if (((SPObjectClass *) (parent_class))->update)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen ((SPObjectClass *) (parent_class))->update(object, ctx, flags);
b49365c42b99e3cc135dcde0077aad31d930f6c1Johan B. C. Engelen if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen for (SPObject *child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen sp_item_invoke_bbox(group, &paintbox, NR::identity(), TRUE);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen for (SPItemView *v = group->display; v != NULL; v = v->next) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen group->_clearFlow(NR_ARENA_GROUP(v->arenaitem));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // pass the bbox of the flowtext object as paintbox (used for paintserver fills)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen group->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelensp_flowtext_modified(SPObject *object, guint flags)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // FIXME: the below stanza is copied over from sp_text_modified, consider factoring it out
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen sp_item_invoke_bbox(text, &paintbox, NR::identity(), TRUE);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen for (SPItemView* v = text->display; v != NULL; v = v->next) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen text->_clearFlow(NR_ARENA_GROUP(v->arenaitem));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox);
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen for (SPObject *o = sp_object_first_child(SP_OBJECT(ft)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (flags || (region->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen region->emitModified(flags); // pass down to the region only
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelensp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen object->_requireSVGVersion(Inkscape::Version(1, 2));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (((SPObjectClass *) (parent_class))->build) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen (* ((SPObjectClass *) (parent_class))->build)(object, document, repr);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen sp_object_read_attr(object, "inkscape:layoutOptions"); // must happen after css has been read
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelensp_flowtext_set(SPObject *object, unsigned key, gchar const *value)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen SPFlowtext *group = (SPFlowtext *) object;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // deprecated attribute, read for backward compatibility only
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen SPCSSAttr *opts = sp_repr_css_attr((SP_OBJECT(group))->repr, "inkscape:layoutOptions");
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen gchar const *val = sp_repr_css_property(opts, "justification", NULL);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (val != NULL && !object->style->text_align.set) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if ( strcmp(val, "0") == 0 || strcmp(val, "false") == 0 ) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen object->style->text_align.value = SP_CSS_TEXT_ALIGN_LEFT;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen object->style->text_align.value = SP_CSS_TEXT_ALIGN_JUSTIFY;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen object->style->text_align.inherit = FALSE;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen object->style->text_align.computed = object->style->text_align.value;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen /* no equivalent css attribute for these two (yet)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen gchar const *val = sp_repr_css_property(opts, "layoutAlgo", NULL);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if ( val == NULL ) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen group->algo = 0;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if ( strcmp(val, "better") == 0 ) { // knuth-plass, never worked for general cases
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen group->algo = 2;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen } else if ( strcmp(val, "simple") == 0 ) { // greedy, but allowed lines to be compressed by up to 20% if it would make them fit
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen group->algo = 1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen } else if ( strcmp(val, "default") == 0 ) { // the same one we use, a standard greedy
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen group->algo = 0;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen { // This would probably translate to padding-left, if SPStyle had it.
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen gchar const *val = sp_repr_css_property(opts, "par-indent", NULL);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen sp_repr_get_double((Inkscape::XML::Node*)opts, "par-indent", &group->par_indent);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen object->requestModified(SP_OBJECT_MODIFIED_FLAG);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if (((SPObjectClass *) (parent_class))->set) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen (* ((SPObjectClass *) (parent_class))->set)(object, key, value);
for (SPObject *child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
if ( SP_IS_FLOWDIV(child) || SP_IS_FLOWPARA(child) || SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child)) {
for (SPObject *child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
if ( SP_IS_FLOWDIV(child) || SP_IS_FLOWPARA(child) || SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child) ) {
return repr;
sp_flowtext_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const /*flags*/)
return g_strdup_printf(ngettext("<b>Flowed text</b> (%d character)", "<b>Flowed text</b> (%d characters)", nChars), nChars);
return g_strdup_printf(ngettext("<b>Linked flowed text</b> (%d character)", "<b>Linked flowed text</b> (%d characters)", nChars), nChars);
static NRArenaItem *
return flowed;
void SPFlowtext::_buildLayoutInput(SPObject *root, Shape const *exclusion_shape, std::list<Shape> *shapes, SPObject **pending_line_break_object)
bool with_indent = false;
if (SP_IS_FLOWTEXT(t)) {
if (indent != 0) {
with_indent = true;
if (*pending_line_break_object) {
for (SPObject *child = sp_object_first_child(root) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
if (*pending_line_break_object) {
if (with_indent)
if (SP_IS_FLOWDIV(root) || SP_IS_FLOWPARA(root) || SP_IS_FLOWREGIONBREAK(root) || SP_IS_FLOWLINE(root)) {
delete shape_temp;
return shape;
delete exclusion_shape;
bool set_x = false;
bool set_y = false;
set_x = true;
set_y = true;
if (set_x)
sp_repr_set_svg_double(span_tspan, "x", anchor_point[NR::X]); // FIXME: this will pick up the wrong end of counter-directional runs
if (set_y)
void *rawptr = 0;
gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, this->style);
void *rawptr = 0;
for (int i = this->layout.iteratorToCharIndex(it_span_end) - this->layout.iteratorToCharIndex(it) ; i ; --i)
return repr;
if (SP_IS_FLOWREGION(o)) {
region = o;
bool past = false;
if (SP_IS_ITEM(o)) {
past = true;
return frame;
root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create
Inkscape::XML::Node *rect_repr = xml_doc->createElement("svg:rect"); // FIXME: use path!!! after rects are converted to use path
using NR::X;
using NR::Y;
return ft_item;