X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-flowtext.cpp;h=3af12064ff622e7f1b31f7888bd537307ce5a24e;hb=6302669b796eadd6994ecdc2e70f0119b29194dd;hp=fbf0efabd5b5da992b7f75a642f72991cce13dad;hpb=6b15695578f07a3f72c4c9475c1a261a3021472a;p=inkscape.git diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index fbf0efabd..3af12064f 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -5,6 +5,8 @@ # include "config.h" #endif #include +#include +#include #include "attributes.h" #include "xml/repr.h" @@ -14,7 +16,6 @@ #include "selection.h" #include "desktop-handles.h" #include "desktop.h" -#include "desktop-affine.h" #include "xml/repr.h" @@ -25,7 +26,8 @@ #include "sp-use.h" #include "sp-rect.h" #include "text-tag-attributes.h" - +#include "text-chemistry.h" +#include "text-editing.h" #include "livarot/Shape.h" @@ -40,13 +42,14 @@ static void sp_flowtext_child_added(SPObject *object, Inkscape::XML::Node *child static void sp_flowtext_remove_child(SPObject *object, Inkscape::XML::Node *child); static void sp_flowtext_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_flowtext_modified(SPObject *object, guint flags); -static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); +static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void sp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static void sp_flowtext_set(SPObject *object, unsigned key, gchar const *value); -static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags); +static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); static void sp_flowtext_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_flowtext_description(SPItem *item); +static void sp_flowtext_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *snapprefs); static NRArenaItem *sp_flowtext_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags); static void sp_flowtext_hide(SPItem *item, unsigned key); @@ -96,6 +99,7 @@ sp_flowtext_class_init(SPFlowtextClass *klass) item_class->bbox = sp_flowtext_bbox; item_class->print = sp_flowtext_print; item_class->description = sp_flowtext_description; + item_class->snappoints = sp_flowtext_snappoints; item_class->show = sp_flowtext_show; item_class->hide = sp_flowtext_hide; } @@ -103,6 +107,7 @@ sp_flowtext_class_init(SPFlowtextClass *klass) static void sp_flowtext_init(SPFlowtext *group) { + group->par_indent = 0; new (&group->layout) Inkscape::Text::Layout(); } @@ -134,21 +139,21 @@ sp_flowtext_remove_child(SPObject *object, Inkscape::XML::Node *child) object->requestModified(SP_OBJECT_MODIFIED_FLAG); } -static void -sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) +static void sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) { SPFlowtext *group = SP_FLOWTEXT(object); SPItemCtx *ictx = (SPItemCtx *) ctx; SPItemCtx cctx = *ictx; - if (((SPObjectClass *) (parent_class))->update) + if (((SPObjectClass *) (parent_class))->update) { ((SPObjectClass *) (parent_class))->update(object, ctx, flags); + } if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; flags &= SP_OBJECT_MODIFIED_CASCADE; GSList *l = NULL; - for (SPObject *child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) { + for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { g_object_ref(G_OBJECT(child)); l = g_slist_prepend(l, child); } @@ -171,17 +176,17 @@ sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) group->rebuildLayout(); - // pass the bbox of the flowtext object as paintbox (used for paintserver fills) NRRect paintbox; - sp_item_invoke_bbox(group, &paintbox, NR::identity(), TRUE); + group->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView *v = group->display; v != NULL; v = v->next) { group->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + // pass the bbox of the flowtext object as paintbox (used for paintserver fills) group->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); } } -static void -sp_flowtext_modified(SPObject *object, guint flags) +static void sp_flowtext_modified(SPObject *object, guint flags) { SPObject *ft = SP_FLOWTEXT (object); SPObject *region = NULL; @@ -189,17 +194,29 @@ sp_flowtext_modified(SPObject *object, guint flags) if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; flags &= SP_OBJECT_MODIFIED_CASCADE; - for (SPObject *o = sp_object_first_child(SP_OBJECT(ft)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) { + // FIXME: the below stanza is copied over from sp_text_modified, consider factoring it out + if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG )) { + SPFlowtext *text = SP_FLOWTEXT(object); + NRRect paintbox; + text->invoke_bbox( &paintbox, Geom::identity(), TRUE); + for (SPItemView* v = text->display; v != NULL; v = v->next) { + text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); + } + } + + for ( SPObject *o = ft->firstChild() ; o ; o = o->getNext() ) { if (SP_IS_FLOWREGION(o)) { region = o; break; } } - if (!region) return; - - if (flags || (region->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - region->emitModified(flags); // pass down to the region only + if (region) { + if (flags || (region->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + region->emitModified(flags); // pass down to the region only + } } } @@ -212,7 +229,7 @@ sp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *r (* ((SPObjectClass *) (parent_class))->build)(object, document, repr); } - sp_object_read_attr(object, "inkscape:layoutOptions"); // must happen after css has been read + object->readAttr( "inkscape:layoutOptions" ); // must happen after css has been read } static void @@ -223,7 +240,8 @@ sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) switch (key) { case SP_ATTR_LAYOUT_OPTIONS: { // deprecated attribute, read for backward compatibility only - SPCSSAttr *opts = sp_repr_css_attr((SP_OBJECT(group))->repr, "inkscape:layoutOptions"); + //XML Tree being directly used while it shouldn't be. + SPCSSAttr *opts = sp_repr_css_attr((SP_OBJECT(group))->getRepr(), "inkscape:layoutOptions"); { gchar const *val = sp_repr_css_property(opts, "justification", NULL); if (val != NULL && !object->style->text_align.set) { @@ -252,6 +270,7 @@ sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) } } } + */ { // This would probably translate to padding-left, if SPStyle had it. gchar const *val = sp_repr_css_property(opts, "par-indent", NULL); if ( val == NULL ) { @@ -260,7 +279,6 @@ sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) sp_repr_get_double((Inkscape::XML::Node*)opts, "par-indent", &group->par_indent); } } - */ sp_repr_css_attr_unref(opts); object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; @@ -273,18 +291,21 @@ sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) } } -static Inkscape::XML::Node * -sp_flowtext_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) +static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ( flags & SP_OBJECT_WRITE_BUILD ) { - if ( repr == NULL ) repr = sp_repr_new("svg:flowRoot"); + if ( repr == NULL ) { + repr = xml_doc->createElement("svg:flowRoot"); + } GSList *l = NULL; - for (SPObject *child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) { + for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { Inkscape::XML::Node *c_repr = NULL; if ( SP_IS_FLOWDIV(child) || SP_IS_FLOWPARA(child) || SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child)) { - c_repr = child->updateRepr(NULL, flags); - } - if ( c_repr ) l = g_slist_prepend(l, c_repr); + c_repr = child->updateRepr(xml_doc, NULL, flags); + } + if ( c_repr ) { + l = g_slist_prepend(l, c_repr); + } } while ( l ) { repr->addChild((Inkscape::XML::Node *) l->data, NULL); @@ -292,24 +313,40 @@ sp_flowtext_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) l = g_slist_remove(l, l->data); } } else { - for (SPObject *child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) { + for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { if ( SP_IS_FLOWDIV(child) || SP_IS_FLOWPARA(child) || SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child) ) { child->updateRepr(flags); } } } - if (((SPObjectClass *) (parent_class))->write) - ((SPObjectClass *) (parent_class))->write(object, repr, flags); + if (((SPObjectClass *) (parent_class))->write) { + ((SPObjectClass *) (parent_class))->write(object, xml_doc, repr, flags); + } return repr; } static void -sp_flowtext_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const /*flags*/) +sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) { SPFlowtext *group = SP_FLOWTEXT(item); group->layout.getBoundingBox(bbox, transform); + + // Add stroke width + SPStyle* style=SP_OBJECT_STYLE (item); + if ( !style->stroke.isNone() ) { + double const scale = transform.descrim(); + if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord + double const width = MAX(0.125, style->stroke_width.computed * scale); + if ( fabs(bbox->x1 - bbox->x0) > -0.00001 && fabs(bbox->y1 - bbox->y0) > -0.00001 ) { + bbox->x0-=0.5*width; + bbox->x1+=0.5*width; + bbox->y0-=0.5*width; + bbox->y1+=0.5*width; + } + } + } } static void @@ -318,15 +355,20 @@ sp_flowtext_print(SPItem *item, SPPrintContext *ctx) SPFlowtext *group = SP_FLOWTEXT(item); NRRect pbox; - sp_item_invoke_bbox(item, &pbox, NR::identity(), TRUE); + item->invoke_bbox( &pbox, Geom::identity(), TRUE); NRRect bbox; - sp_item_bbox_desktop(item, &bbox); + Geom::OptRect bbox_maybe = item->getBboxDesktop(); + if (!bbox_maybe) { + return; + } + bbox = NRRect(from_2geom(*bbox_maybe)); + NRRect dbox; dbox.x0 = 0.0; dbox.y0 = 0.0; - dbox.x1 = sp_document_width(SP_OBJECT_DOCUMENT(item)); - dbox.y1 = sp_document_height(SP_OBJECT_DOCUMENT(item)); - NR::Matrix const ctm = sp_item_i2d_affine(item); + dbox.x1 = SP_OBJECT_DOCUMENT(item)->getWidth(); + dbox.y1 = SP_OBJECT_DOCUMENT(item)->getHeight(); + Geom::Matrix const ctm (item->i2d_affine()); group->layout.print(ctx, &pbox, &dbox, &bbox, ctm); } @@ -336,10 +378,27 @@ static gchar *sp_flowtext_description(SPItem *item) { Inkscape::Text::Layout const &layout = SP_FLOWTEXT(item)->layout; int const nChars = layout.iteratorToCharIndex(layout.end()); - if (SP_FLOWTEXT(item)->has_internal_frame()) - return g_strdup_printf(_("Flowed text (%d characters)"), nChars); - else - return g_strdup_printf(_("Linked flowed text (%d characters)"), nChars); + + char const *trunc = (layout.inputTruncated()) ? _(" [truncated]") : ""; + + if (SP_FLOWTEXT(item)->has_internal_frame()) { + return g_strdup_printf(ngettext("Flowed text (%d character%s)", "Flowed text (%d characters%s)", nChars), nChars, trunc); + } else { + return g_strdup_printf(ngettext("Linked flowed text (%d character%s)", "Linked flowed text (%d characters%s)", nChars), nChars, trunc); + } +} + +static void sp_flowtext_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const */*snapprefs*/) +{ + // Choose a point on the baseline for snapping from or to, with the horizontal position + // of this point depending on the text alignment (left vs. right) + Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) item); + if (layout != NULL && layout->outputExists()) { + boost::optional pt = layout->baselineAnchorPoint(); + if (pt) { + p.push_back(Inkscape::SnapCandidatePoint((*pt) * item->i2d_affine(), Inkscape::SNAPSOURCE_TEXT_BASELINE, Inkscape::SNAPTARGET_TEXT_BASELINE)); + } + } } static NRArenaItem * @@ -349,9 +408,11 @@ sp_flowtext_show(SPItem *item, NRArena *arena, unsigned/* key*/, unsigned /*flag NRArenaGroup *flowed = NRArenaGroup::create(arena); nr_arena_group_set_transparent(flowed, FALSE); - // pass the bbox of the flowtext object as paintbox (used for paintserver fills) + nr_arena_group_set_style(flowed, group->style); + + // pass the bbox of the flowtext object as paintbox (used for paintserver fills) NRRect paintbox; - sp_item_invoke_bbox(item, &paintbox, NR::identity(), TRUE); + item->invoke_bbox( &paintbox, Geom::identity(), TRUE); group->layout.show(flowed, &paintbox); return flowed; @@ -371,37 +432,65 @@ sp_flowtext_hide(SPItem *item, unsigned int key) void SPFlowtext::_buildLayoutInput(SPObject *root, Shape const *exclusion_shape, std::list *shapes, SPObject **pending_line_break_object) { + Inkscape::Text::Layout::OptionalTextTagAttrs pi; + bool with_indent = false; + + if (SP_IS_FLOWPARA(root)) { + // emulate par-indent with the first char's kern + SPObject *t = root; + for ( ; t != NULL && !SP_IS_FLOWTEXT(t); t = SP_OBJECT_PARENT(t)){}; + if (SP_IS_FLOWTEXT(t)) { + double indent = SP_FLOWTEXT(t)->par_indent; + if (indent != 0) { + with_indent = true; + SVGLength sl; + sl.value = sl.computed = indent; + sl._set = true; + pi.dx.push_back(sl); + } + } + } + if (*pending_line_break_object) { - if (SP_IS_FLOWREGIONBREAK(*pending_line_break_object)) + if (SP_IS_FLOWREGIONBREAK(*pending_line_break_object)) { layout.appendControlCode(Inkscape::Text::Layout::SHAPE_BREAK, *pending_line_break_object); - else + } else { layout.appendControlCode(Inkscape::Text::Layout::PARAGRAPH_BREAK, *pending_line_break_object); + } *pending_line_break_object = NULL; } - for (SPObject *child = sp_object_first_child(root) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) { + for (SPObject *child = root->firstChild() ; child ; child = child->getNext() ) { if (SP_IS_STRING(child)) { if (*pending_line_break_object) { if (SP_IS_FLOWREGIONBREAK(*pending_line_break_object)) layout.appendControlCode(Inkscape::Text::Layout::SHAPE_BREAK, *pending_line_break_object); - else + else { layout.appendControlCode(Inkscape::Text::Layout::PARAGRAPH_BREAK, *pending_line_break_object); + } *pending_line_break_object = NULL; } - layout.appendText(SP_STRING(child)->string, root->style, child); + if (with_indent) { + layout.appendText(SP_STRING(child)->string, root->style, child, &pi); + } else { + layout.appendText(SP_STRING(child)->string, root->style, child); + } } else if (SP_IS_FLOWREGION(child)) { std::vector const &computed = SP_FLOWREGION(child)->computed; for (std::vector::const_iterator it = computed.begin() ; it != computed.end() ; it++) { shapes->push_back(Shape()); - if (exclusion_shape->hasEdges()) + if (exclusion_shape->hasEdges()) { shapes->back().Booleen(*it, const_cast(exclusion_shape), bool_op_diff); - else + } else { shapes->back().Copy(*it); + } layout.appendWrapShape(&shapes->back()); } } - else if (!SP_IS_FLOWREGIONEXCLUDE(child)) + //XML Tree is being directly used while it shouldn't be. + else if (!SP_IS_FLOWREGIONEXCLUDE(child) && !sp_repr_is_meta_element(child->getRepr())) { _buildLayoutInput(child, exclusion_shape, shapes, pending_line_break_object); + } } if (SP_IS_FLOWDIV(root) || SP_IS_FLOWPARA(root) || SP_IS_FLOWREGIONBREAK(root) || SP_IS_FLOWLINE(root)) { @@ -416,17 +505,18 @@ Shape* SPFlowtext::_buildExclusionShape() const Shape *shape = new Shape; Shape *shape_temp = new Shape; - for (SPObject *child = children ; child != NULL ; child = SP_OBJECT_NEXT(child) ) { + for (SPObject *child = children ; child ; child = child->getNext() ) { // RH: is it right that this shouldn't be recursive? if ( SP_IS_FLOWREGIONEXCLUDE(child) ) { SPFlowregionExclude *c_child = SP_FLOWREGIONEXCLUDE(child); - if (c_child->computed == NULL || !c_child->computed->hasEdges()) - continue; - if (shape->hasEdges()) { - shape_temp->Booleen(shape, c_child->computed, bool_op_union); - std::swap(shape, shape_temp); - } else - shape->Copy(c_child->computed); + if ( c_child->computed && c_child->computed->hasEdges() ) { + if (shape->hasEdges()) { + shape_temp->Booleen(shape, c_child->computed, bool_op_union); + std::swap(shape, shape_temp); + } else { + shape->Copy(c_child->computed); + } + } } } delete shape_temp; @@ -459,44 +549,41 @@ void SPFlowtext::_clearFlow(NRArenaGroup *in_arena) } } -void SPFlowtext::convert_to_text() +Inkscape::XML::Node * +SPFlowtext::getAsText() { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = SP_DT_SELECTION(desktop); - SPItem *item = selection->singleItem(); - if (!SP_IS_FLOWTEXT(item)) return; - - SPFlowtext *group = SP_FLOWTEXT(item); + if (!this->layout.outputExists()) return NULL; - if (!group->layout.outputExists()) return; + SPItem *item = SP_ITEM(this); - Inkscape::XML::Node *repr = sp_repr_new("svg:text"); + Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(this)->getReprDoc(); + Inkscape::XML::Node *repr = xml_doc->createElement("svg:text"); repr->setAttribute("xml:space", "preserve"); - repr->setAttribute("style", SP_OBJECT_REPR(group)->attribute("style")); - NR::Point anchor_point = group->layout.characterAnchorPoint(group->layout.begin()); - sp_repr_set_svg_double(repr, "x", anchor_point[NR::X]); - sp_repr_set_svg_double(repr, "y", anchor_point[NR::Y]); - - for (Inkscape::Text::Layout::iterator it = group->layout.begin() ; it != group->layout.end() ; ) { - - Inkscape::XML::Node *line_tspan = sp_repr_new("svg:tspan"); + repr->setAttribute("style", SP_OBJECT_REPR(this)->attribute("style")); + Geom::Point anchor_point = this->layout.characterAnchorPoint(this->layout.begin()); + sp_repr_set_svg_double(repr, "x", anchor_point[Geom::X]); + sp_repr_set_svg_double(repr, "y", anchor_point[Geom::Y]); + + for (Inkscape::Text::Layout::iterator it = this->layout.begin() ; it != this->layout.end() ; ) { + Inkscape::XML::Node *line_tspan = xml_doc->createElement("svg:tspan"); line_tspan->setAttribute("sodipodi:role", "line"); Inkscape::Text::Layout::iterator it_line_end = it; it_line_end.nextStartOfLine(); + while (it != it_line_end) { - Inkscape::XML::Node *span_tspan = sp_repr_new("svg:tspan"); - NR::Point anchor_point = group->layout.characterAnchorPoint(it); + Inkscape::XML::Node *span_tspan = xml_doc->createElement("svg:tspan"); + Geom::Point anchor_point = this->layout.characterAnchorPoint(it); // use kerning to simulate justification and whatnot Inkscape::Text::Layout::iterator it_span_end = it; it_span_end.nextStartOfSpan(); Inkscape::Text::Layout::OptionalTextTagAttrs attrs; - group->layout.simulateLayoutUsingKerning(it, it_span_end, &attrs); + this->layout.simulateLayoutUsingKerning(it, it_span_end, &attrs); // set x,y attributes only when we need to bool set_x = false; bool set_y = false; - if (!item->transform.test_identity()) { + if (!item->transform.isIdentity()) { set_x = set_y = true; } else { Inkscape::Text::Layout::iterator it_chunk_start = it; @@ -514,14 +601,20 @@ void SPFlowtext::convert_to_text() attrs.dx[0] = 0.0; TextTagAttributes(attrs).writeTo(span_tspan); 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 + sp_repr_set_svg_double(span_tspan, "x", anchor_point[Geom::X]); // FIXME: this will pick up the wrong end of counter-directional runs if (set_y) - sp_repr_set_svg_double(span_tspan, "y", anchor_point[NR::Y]); + sp_repr_set_svg_double(span_tspan, "y", anchor_point[Geom::Y]); + if (line_tspan->childCount() == 0) { + sp_repr_set_svg_double(line_tspan, "x", anchor_point[Geom::X]); // FIXME: this will pick up the wrong end of counter-directional runs + sp_repr_set_svg_double(line_tspan, "y", anchor_point[Geom::Y]); + } - SPObject *source_obj; + SPObject *source_obj = 0; + void *rawptr = 0; Glib::ustring::iterator span_text_start_iter; - group->layout.getSourceOfCharacter(it, (void**)&source_obj, &span_text_start_iter); - gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, group->style); + this->layout.getSourceOfCharacter(it, &rawptr, &span_text_start_iter); + source_obj = SP_OBJECT (rawptr); + gchar *style_text = sp_style_write_difference((SP_IS_STRING(source_obj) ? source_obj->parent : source_obj)->style, this->style); if (style_text && *style_text) { span_tspan->setAttribute("style", style_text); g_free(style_text); @@ -529,13 +622,15 @@ void SPFlowtext::convert_to_text() if (SP_IS_STRING(source_obj)) { Glib::ustring *string = &SP_STRING(source_obj)->string; - SPObject *span_end_obj; + SPObject *span_end_obj = 0; + void *rawptr = 0; Glib::ustring::iterator span_text_end_iter; - group->layout.getSourceOfCharacter(it_span_end, (void**)&span_end_obj, &span_text_end_iter); + this->layout.getSourceOfCharacter(it_span_end, &rawptr, &span_text_end_iter); + span_end_obj = SP_OBJECT(rawptr); if (span_end_obj != source_obj) { - if (it_span_end == group->layout.end()) { + if (it_span_end == this->layout.end()) { span_text_end_iter = span_text_start_iter; - for (int i = group->layout.iteratorToCharIndex(it_span_end) - group->layout.iteratorToCharIndex(it) ; i ; --i) + for (int i = this->layout.iteratorToCharIndex(it_span_end) - this->layout.iteratorToCharIndex(it) ; i ; --i) ++span_text_end_iter; } else span_text_end_iter = string->end(); // spans will never straddle a source boundary @@ -545,7 +640,7 @@ void SPFlowtext::convert_to_text() Glib::ustring new_string; while (span_text_start_iter != span_text_end_iter) new_string += *span_text_start_iter++; // grr. no substr() with iterators - Inkscape::XML::Node *new_text = sp_repr_new_text(new_string.c_str()); + Inkscape::XML::Node *new_text = xml_doc->createTextNode(new_string.c_str()); span_tspan->appendChild(new_text); Inkscape::GC::release(new_text); } @@ -553,61 +648,47 @@ void SPFlowtext::convert_to_text() it = it_span_end; line_tspan->appendChild(span_tspan); - Inkscape::GC::release(span_tspan); + Inkscape::GC::release(span_tspan); } repr->appendChild(line_tspan); - Inkscape::GC::release(line_tspan); + Inkscape::GC::release(line_tspan); } - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); - parent->appendChild(repr); - SPItem *new_item = (SPItem *) SP_DT_DOCUMENT(desktop)->getObjectByRepr(repr); - sp_item_write_transform(new_item, repr, item->transform); - SP_OBJECT(new_item)->updateRepr(); - - Inkscape::GC::release(repr); - selection->set(new_item); - item->deleteObject(); - - sp_document_done(SP_DT_DOCUMENT(desktop)); + return repr; } SPItem *SPFlowtext::get_frame(SPItem *after) { - SPObject *ft = SP_OBJECT (this); - SPObject *region = NULL; + SPItem *frame = 0; - for (SPObject *o = sp_object_first_child(SP_OBJECT(ft)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) { + SPObject *region = 0; + for (SPObject *o = firstChild() ; o ; o = o->getNext() ) { if (SP_IS_FLOWREGION(o)) { region = o; break; } } - if (!region) return NULL; + if (region) { + bool past = false; - bool past = false; - SPItem *frame = NULL; - - for (SPObject *o = sp_object_first_child(SP_OBJECT(region)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) { - if (SP_IS_ITEM(o)) { - if (after == NULL || past) { - frame = SP_ITEM(o); - } else { - if (SP_ITEM(o) == after) { - past = true; + for (SPObject *o = region->firstChild() ; o ; o = o->getNext() ) { + if (SP_IS_ITEM(o)) { + if ( (after == NULL) || past ) { + frame = SP_ITEM(o); + } else { + if (SP_ITEM(o) == after) { + past = true; + } } } } - } - - if (!frame) return NULL; - if (SP_IS_USE (frame)) { - return sp_use_get_original(SP_USE(frame)); - } else { - return frame; + if ( frame && SP_IS_USE(frame) ) { + frame = sp_use_get_original(SP_USE(frame)); + } } + return frame; } bool SPFlowtext::has_internal_frame() @@ -618,46 +699,47 @@ bool SPFlowtext::has_internal_frame() } -SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, NR::Point p0, NR::Point p1) +SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, Geom::Point p0, Geom::Point p1) { - SPDocument *doc = SP_DT_DOCUMENT (desktop); + SPDocument *doc = sp_desktop_document (desktop); - Inkscape::XML::Node *root_repr = sp_repr_new("svg:flowRoot"); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *root_repr = xml_doc->createElement("svg:flowRoot"); root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create SPItem *ft_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(root_repr)); SPObject *root_object = doc->getObjectByRepr(root_repr); g_assert(SP_IS_FLOWTEXT(root_object)); - Inkscape::XML::Node *region_repr = sp_repr_new("svg:flowRegion"); + Inkscape::XML::Node *region_repr = xml_doc->createElement("svg:flowRegion"); root_repr->appendChild(region_repr); SPObject *region_object = doc->getObjectByRepr(region_repr); g_assert(SP_IS_FLOWREGION(region_object)); - Inkscape::XML::Node *rect_repr = sp_repr_new("svg:rect"); // FIXME: use path!!! after rects are converted to use path + Inkscape::XML::Node *rect_repr = xml_doc->createElement("svg:rect"); // FIXME: use path!!! after rects are converted to use path region_repr->appendChild(rect_repr); SPObject *rect = doc->getObjectByRepr(rect_repr); - p0 = sp_desktop_dt2root_xy_point(desktop, p0); - p1 = sp_desktop_dt2root_xy_point(desktop, p1); - using NR::X; - using NR::Y; - NR::Coord const x0 = MIN(p0[X], p1[X]); - NR::Coord const y0 = MIN(p0[Y], p1[Y]); - NR::Coord const x1 = MAX(p0[X], p1[X]); - NR::Coord const y1 = MAX(p0[Y], p1[Y]); - NR::Coord const w = x1 - x0; - NR::Coord const h = y1 - y0; + p0 *= desktop->dt2doc(); + p1 *= desktop->dt2doc(); + using Geom::X; + using Geom::Y; + Geom::Coord const x0 = MIN(p0[X], p1[X]); + Geom::Coord const y0 = MIN(p0[Y], p1[Y]); + Geom::Coord const x1 = MAX(p0[X], p1[X]); + Geom::Coord const y1 = MAX(p0[Y], p1[Y]); + Geom::Coord const w = x1 - x0; + Geom::Coord const h = y1 - y0; sp_rect_position_set(SP_RECT(rect), x0, y0, w, h); SP_OBJECT(rect)->updateRepr(); - Inkscape::XML::Node *para_repr = sp_repr_new("svg:flowPara"); + Inkscape::XML::Node *para_repr = xml_doc->createElement("svg:flowPara"); root_repr->appendChild(para_repr); SPObject *para_object = doc->getObjectByRepr(para_repr); g_assert(SP_IS_FLOWPARA(para_object)); - Inkscape::XML::Node *text = sp_repr_new_text(""); + Inkscape::XML::Node *text = xml_doc->createTextNode(""); para_repr->appendChild(text); Inkscape::GC::release(root_repr); @@ -665,6 +747,8 @@ SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, NR::Point p0, N Inkscape::GC::release(para_repr); Inkscape::GC::release(rect_repr); + ft_item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + return ft_item; }