diff --git a/src/text-editing.cpp b/src/text-editing.cpp
index a225c1a00e205b3ce8bb07667e685dd77fa3fbf9..2e6e2f9fa9b454fe5ae9579dec40a4531af86773 100644 (file)
--- a/src/text-editing.cpp
+++ b/src/text-editing.cpp
* Authors:
* bulia byak
* Richard Hughes
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
*
* Copyright (C) 2004-5 authors
*
SP_TEXT(item)->rebuildLayout();
else if (SP_IS_FLOWTEXT (item))
SP_FLOWTEXT(item)->rebuildLayout();
+ item->updateRepr();
}
-/** Returns true if there are no visible characters on the canvas */
-bool
-sp_te_output_is_empty (SPItem const *item)
+bool sp_te_output_is_empty(SPItem const *item)
{
Inkscape::Text::Layout const *layout = te_get_layout(item);
return layout->begin() == layout->end();
}
-/** Returns true if the user has typed nothing in the text box */
-bool
-sp_te_input_is_empty (SPObject const *item)
+bool sp_te_input_is_empty(SPObject const *item)
{
- if (SP_IS_STRING(item)) return SP_STRING(item)->string.empty();
- for (SPObject const *child = item->firstChild() ; child ; child = SP_OBJECT_NEXT(child))
- if (!sp_te_input_is_empty(child)) return false;
- return true;
+ bool empty = true;
+ if (SP_IS_STRING(item)) {
+ empty = SP_STRING(item)->string.empty();
+ } else {
+ for (SPObject const *child = item->firstChild() ; child ; child = child->getNext()) {
+ if (!sp_te_input_is_empty(child)) {
+ empty = false;
+ break;
+ }
+ }
+ }
+ return empty;
}
Inkscape::Text::Layout::iterator
-sp_te_get_position_by_coords (SPItem const *item, NR::Point &i_p)
+sp_te_get_position_by_coords (SPItem const *item, Geom::Point const &i_p)
{
- NR::Matrix im=sp_item_i2d_affine (item);
+ Geom::Matrix im (item->i2d_affine ());
im = im.inverse();
- NR::Point p = i_p * im;
+ Geom::Point p = i_p * im;
Inkscape::Text::Layout const *layout = te_get_layout(item);
return layout->getNearestCursorPositionTo(p);
}
-std::vector<NR::Point> sp_te_create_selection_quads(SPItem const *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, NR::Matrix const &transform)
+std::vector<Geom::Point> sp_te_create_selection_quads(SPItem const *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, Geom::Matrix const &transform)
{
if (start == end)
- return std::vector<NR::Point>();
+ return std::vector<Geom::Point>();
Inkscape::Text::Layout const *layout = te_get_layout(item);
if (layout == NULL)
- return std::vector<NR::Point>();
+ return std::vector<Geom::Point>();
return layout->createSelectionShape(start, end, transform);
}
void
-sp_te_get_cursor_coords (SPItem const *item, Inkscape::Text::Layout::iterator const &position, NR::Point &p0, NR::Point &p1)
+sp_te_get_cursor_coords (SPItem const *item, Inkscape::Text::Layout::iterator const &position, Geom::Point &p0, Geom::Point &p1)
{
Inkscape::Text::Layout const *layout = te_get_layout(item);
double height, rotation;
- layout->queryCursorShape(position, &p0, &height, &rotation);
- p1 = NR::Point(p0[NR::X] + height * sin(rotation), p0[NR::Y] - height * cos(rotation));
+ layout->queryCursorShape(position, p0, height, rotation);
+ p1 = Geom::Point(p0[Geom::X] + height * sin(rotation), p0[Geom::Y] - height * cos(rotation));
}
SPStyle const * sp_te_style_at_position(SPItem const *text, Inkscape::Text::Layout::iterator const &position)
+{
+ SPObject const *pos_obj = sp_te_object_at_position(text, position);
+ if (pos_obj)
+ return SP_OBJECT_STYLE(pos_obj);
+ return NULL;
+}
+
+SPObject const * sp_te_object_at_position(SPItem const *text, Inkscape::Text::Layout::iterator const &position)
{
Inkscape::Text::Layout const *layout = te_get_layout(text);
if (layout == NULL)
@@ -119,8 +134,8 @@ SPStyle const * sp_te_style_at_position(SPItem const *text, Inkscape::Text::Layo
pos_obj = SP_OBJECT(rawptr);
if (pos_obj == 0) pos_obj = text;
while (SP_OBJECT_STYLE(pos_obj) == NULL)
- pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style
- return SP_OBJECT_STYLE(pos_obj);
+ pos_obj = SP_OBJECT_PARENT(pos_obj); // not interested in SPStrings
+ return pos_obj;
}
/*
return NULL;
}
-/** Recursively gets the length of all the SPStrings at or below the given
-\a item. Also adds 1 for each line break encountered. */
unsigned sp_text_get_length(SPObject const *item)
{
unsigned length = 0;
- if (SP_IS_STRING(item)) return SP_STRING(item)->string.length();
-
- if (is_line_break_object(item)) length++;
+ if (SP_IS_STRING(item)) {
+ length = SP_STRING(item)->string.length();
+ } else {
+ if (is_line_break_object(item)) {
+ length++;
+ }
- for (SPObject const *child = item->firstChild() ; child ; child = SP_OBJECT_NEXT(child)) {
- if (SP_IS_STRING(child)) length += SP_STRING(child)->string.length();
- else length += sp_text_get_length(child);
+ for (SPObject const *child = item->firstChild() ; child ; child = child->getNext()) {
+ if (SP_IS_STRING(child)) {
+ length += SP_STRING(child)->string.length();
+ } else {
+ length += sp_text_get_length(child);
+ }
+ }
}
+
return length;
}
-/** Recursively gets the length of all the SPStrings at or below the given
-\a item, before and not including \a upto. Also adds 1 for each line break encountered. */
unsigned sp_text_get_length_upto(SPObject const *item, SPObject const *upto)
{
unsigned length = 0;
}
// Count the length of the children
- for (SPObject const *child = item->firstChild() ; child ; child = SP_OBJECT_NEXT(child)) {
+ for (SPObject const *child = item->firstChild() ; child ; child = child->getNext()) {
if (upto && child == upto) {
// hit upto, return immediately
return length;
static unsigned sum_sibling_text_lengths_before(SPObject const *item)
{
unsigned char_index = 0;
- for (SPObject *sibling = SP_OBJECT_PARENT(item)->firstChild() ; sibling && sibling != item ; sibling = SP_OBJECT_NEXT(sibling))
+ for (SPObject *sibling = SP_OBJECT_PARENT(item)->firstChild() ; sibling && sibling != item ; sibling = sibling->getNext()) {
char_index += sp_text_get_length(sibling);
+ }
return char_index;
}
*/
static SPObject* split_text_object_tree_at(SPObject *split_obj, unsigned char_index)
{
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(split_obj));
+ Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(split_obj)->getReprDoc();
if (is_line_break_object(split_obj)) {
Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, SP_OBJECT_REPR(split_obj));
SP_OBJECT_REPR(SP_OBJECT_PARENT(split_obj))->addChild(new_node, SP_OBJECT_REPR(split_obj));
Inkscape::GC::release(new_node);
- split_attributes(split_obj, SP_OBJECT_NEXT(split_obj), char_index);
- return SP_OBJECT_NEXT(split_obj);
+ split_attributes(split_obj, split_obj->getNext(), char_index);
+ return split_obj->getNext();
}
unsigned char_count_before = sum_sibling_text_lengths_before(split_obj);
@@ -327,10 +347,10 @@ static SPObject* split_text_object_tree_at(SPObject *split_obj, unsigned char_in
split_attributes(split_obj, duplicate_obj->firstChild(), char_index);
// then move all the subsequent nodes
- split_obj = SP_OBJECT_NEXT(split_obj);
+ split_obj = split_obj->getNext();
while (split_obj) {
Inkscape::XML::Node *move_repr = SP_OBJECT_REPR(split_obj);
- SPObject *next_obj = SP_OBJECT_NEXT(split_obj); // this is about to become invalidated by removeChild()
+ SPObject *next_obj = split_obj->getNext(); // this is about to become invalidated by removeChild()
Inkscape::GC::anchor(move_repr);
SP_OBJECT_REPR(SP_OBJECT_PARENT(split_obj))->removeChild(move_repr);
SP_OBJECT_REPR(duplicate_obj)->appendChild(move_repr);
@@ -367,12 +387,12 @@ Inkscape::Text::Layout::iterator sp_te_insert_line (SPItem *item, Inkscape::Text
if (split_obj == 0) split_obj = item->lastChild();
if (SP_IS_TREF(split_obj)) {
- desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message);
+ desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message);
return position;
}
if (split_obj) {
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(split_obj));
+ Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(split_obj)->getReprDoc();
Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, SP_OBJECT_REPR(split_obj));
SP_OBJECT_REPR(SP_OBJECT_PARENT(split_obj))->addChild(new_node, SP_OBJECT_REPR(split_obj));
Inkscape::GC::release(new_node);
while (start_obj) {
if (start_obj->hasChildren()) {
SPString *found_string = sp_te_seek_next_string_recursive(start_obj->firstChild());
- if (found_string) return found_string;
+ if (found_string) {
+ return found_string;
+ }
}
- if (SP_IS_STRING(start_obj)) return SP_STRING(start_obj);
- start_obj = SP_OBJECT_NEXT(start_obj);
- if (is_line_break_object(start_obj))
+ if (SP_IS_STRING(start_obj)) {
+ return SP_STRING(start_obj);
+ }
+ start_obj = start_obj->getNext();
+ if (is_line_break_object(start_obj)) {
break; // don't cross line breaks
+ }
}
return NULL;
}
@@ -486,10 +511,12 @@ sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gch
if (source_obj->hasChildren()) {
source_obj = source_obj->firstChild();
if (SP_IS_FLOWTEXT(item)) {
- while (SP_IS_FLOWREGION(source_obj) || SP_IS_FLOWREGIONEXCLUDE(source_obj))
- source_obj = SP_OBJECT_NEXT(source_obj);
- if (source_obj == NULL)
+ while (SP_IS_FLOWREGION(source_obj) || SP_IS_FLOWREGIONEXCLUDE(source_obj)) {
+ source_obj = source_obj->getNext();
+ }
+ if (source_obj == NULL) {
source_obj = item;
+ }
}
}
if (source_obj == item && SP_IS_FLOWTEXT(item)) {
@@ -498,7 +525,7 @@ sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gch
source_obj = item->lastChild();
}
} else
- source_obj = SP_OBJECT_NEXT(source_obj);
+ source_obj = source_obj->getNext();
if (source_obj) { // never fails
SPString *string_item = sp_te_seek_next_string_recursive(source_obj);
@@ -598,16 +625,16 @@ static SPObject* delete_line_break(SPObject *root, SPObject *item, bool *next_is
new_span_repr->setAttribute("rotate", a);
SPObject *following_item = item;
- while (SP_OBJECT_NEXT(following_item) == NULL) {
+ while (following_item->getNext() == NULL) {
following_item = SP_OBJECT_PARENT(following_item);
g_assert(following_item != root);
}
- following_item = SP_OBJECT_NEXT(following_item);
+ following_item = following_item->getNext();
SPObject *new_parent_item;
if (SP_IS_STRING(following_item)) {
new_parent_item = SP_OBJECT_PARENT(following_item);
- SP_OBJECT_REPR(new_parent_item)->addChild(new_span_repr, SP_OBJECT_PREV(following_item) ? SP_OBJECT_REPR(SP_OBJECT_PREV(following_item)) : NULL);
+ SP_OBJECT_REPR(new_parent_item)->addChild(new_span_repr, following_item->getPrev() ? SP_OBJECT_REPR(following_item->getPrev()) : NULL);
next_item = following_item;
*next_is_sibling = true;
} else {
SPObject *next_item;
do {
bool is_sibling = true;
- next_item = SP_OBJECT_NEXT(sub_item);
+ next_item = sub_item->getNext();
if (next_item == NULL) {
next_item = SP_OBJECT_PARENT(sub_item);
is_sibling = false;
}
}
- while (tidy_xml_tree_recursively(common_ancestor));
+ while (tidy_xml_tree_recursively(common_ancestor)){};
te_update_layout_now(item);
item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
layout->validateIterator(&iter_pair.first);
replacing line break elements with '\n'. */
static void sp_te_get_ustring_multiline(SPObject const *root, Glib::ustring *string, bool *pending_line_break)
{
- if (*pending_line_break)
+ if (*pending_line_break) {
*string += '\n';
- for (SPObject const *child = root->firstChild() ; child ; child = SP_OBJECT_NEXT(child)) {
- if (SP_IS_STRING(child))
+ }
+ for (SPObject const *child = root->firstChild() ; child ; child = child->getNext()) {
+ if (SP_IS_STRING(child)) {
*string += SP_STRING(child)->string;
- else
+ } else {
sp_te_get_ustring_multiline(child, string, pending_line_break);
+ }
}
- if (!SP_IS_TEXT(root) && !SP_IS_TEXTPATH(root) && is_line_break_object(root))
+ if (!SP_IS_TEXT(root) && !SP_IS_TEXTPATH(root) && is_line_break_object(root)) {
*pending_line_break = true;
+ }
}
/** Gets a text-only representation of the given text or flowroot object,
SPObject *object;
bool is_textpath = false;
if (SP_IS_TEXT_TEXTPATH (text)) {
- repr = SP_OBJECT_REPR (sp_object_first_child(SP_OBJECT (text)));
- object = sp_object_first_child(SP_OBJECT (text));
+ repr = SP_OBJECT_REPR(text->firstChild());
+ object = text->firstChild();
is_textpath = true;
} else {
repr = SP_OBJECT_REPR (text);
repr->setContent("");
SPObject *child = object->firstChild();
while (child) {
- SPObject *next = SP_OBJECT_NEXT(child);
- if (!SP_IS_FLOWREGION(child) && !SP_IS_FLOWREGIONEXCLUDE(child))
+ SPObject *next = child->getNext();
+ if (!SP_IS_FLOWREGION(child) && !SP_IS_FLOWREGIONEXCLUDE(child)) {
repr->removeChild(SP_OBJECT_REPR(child));
+ }
child = next;
}
/** Returns the attributes block and the character index within that block
which represents the iterator \a position. */
-static TextTagAttributes*
+TextTagAttributes*
text_tag_attributes_at_position(SPItem *item, Inkscape::Text::Layout::iterator const &position, unsigned *char_index)
{
if (item == NULL || char_index == NULL || !SP_IS_TEXT(item))
@@ -943,13 +974,13 @@ text_tag_attributes_at_position(SPItem *item, Inkscape::Text::Layout::iterator c
}
void
-sp_te_adjust_kerning_screen (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop *desktop, NR::Point by)
+sp_te_adjust_kerning_screen (SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop *desktop, Geom::Point by)
{
// divide increment by zoom
// divide increment by matrix expansion
gdouble factor = 1 / desktop->current_zoom();
- NR::Matrix t = sp_item_i2doc_affine(item);
- factor = factor / NR::expansion(t);
+ Geom::Matrix t (item->i2doc_affine());
+ factor = factor / t.descrim();
by = factor * by;
unsigned char_index;
@@ -964,14 +995,50 @@ sp_te_adjust_kerning_screen (SPItem *item, Inkscape::Text::Layout::iterator cons
item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
+void sp_te_adjust_dx(SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop * /*desktop*/, double delta)
+{
+ unsigned char_index = 0;
+ TextTagAttributes *attributes = text_tag_attributes_at_position(item, std::min(start, end), &char_index);
+ if (attributes) {
+ attributes->addToDx(char_index, delta);
+ }
+ if (start != end) {
+ attributes = text_tag_attributes_at_position(item, std::max(start, end), &char_index);
+ if (attributes) {
+ attributes->addToDx(char_index, -delta);
+ }
+ }
+
+ item->updateRepr();
+ item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void sp_te_adjust_dy(SPItem *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop * /*desktop*/, double delta)
+{
+ unsigned char_index = 0;
+ TextTagAttributes *attributes = text_tag_attributes_at_position(item, std::min(start, end), &char_index);
+ if (attributes) {
+ attributes->addToDy(char_index, delta);
+ }
+ if (start != end) {
+ attributes = text_tag_attributes_at_position(item, std::max(start, end), &char_index);
+ if (attributes) {
+ attributes->addToDy(char_index, -delta);
+ }
+ }
+
+ item->updateRepr();
+ item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
void
sp_te_adjust_rotation_screen(SPItem *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop *desktop, gdouble pixels)
{
// divide increment by zoom
// divide increment by matrix expansion
gdouble factor = 1 / desktop->current_zoom();
- NR::Matrix t = sp_item_i2doc_affine(text);
- factor = factor / NR::expansion(t);
+ Geom::Matrix t (text->i2doc_affine());
+ factor = factor / t.descrim();
Inkscape::Text::Layout const *layout = te_get_layout(text);
if (layout == NULL) return;
SPObject *source_item = 0;
@@ -1003,6 +1070,27 @@ sp_te_adjust_rotation(SPItem *text, Inkscape::Text::Layout::iterator const &star
text->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
+void sp_te_set_rotation(SPItem *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop */*desktop*/, gdouble degrees)
+{
+ unsigned char_index = 0;
+ TextTagAttributes *attributes = text_tag_attributes_at_position(text, std::min(start, end), &char_index);
+ if (attributes != NULL) {
+ if (start != end) {
+ for (Inkscape::Text::Layout::iterator it = std::min(start, end) ; it != std::max(start, end) ; it.nextCharacter()) {
+ attributes = text_tag_attributes_at_position(text, it, &char_index);
+ if (attributes) {
+ attributes->setRotate(char_index, degrees);
+ }
+ }
+ } else {
+ attributes->setRotate(char_index, degrees);
+ }
+
+ text->updateRepr();
+ text->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+}
+
void
sp_te_adjust_tspan_letterspacing_screen(SPItem *text, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, SPDesktop *desktop, gdouble by)
{
@@ -1055,7 +1143,7 @@ sp_te_adjust_tspan_letterspacing_screen(SPItem *text, Inkscape::Text::Layout::it
gdouble const zoom = desktop->current_zoom();
gdouble const zby = (by
/ (zoom * (nb_let > 1 ? nb_let - 1 : 1))
- / NR::expansion(sp_item_i2doc_affine(SP_ITEM(source_obj))));
+ / to_2geom(SP_ITEM(source_obj)->i2doc_affine()).descrim());
val += zby;
if (start == end) {
@@ -1086,6 +1174,19 @@ sp_te_adjust_tspan_letterspacing_screen(SPItem *text, Inkscape::Text::Layout::it
text->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG);
}
+double
+sp_te_get_average_linespacing (SPItem *text)
+{
+ Inkscape::Text::Layout const *layout = te_get_layout(text);
+ if (!layout)
+ return 0;
+
+ unsigned line_count = layout->lineIndex(layout->end());
+ double all_lines_height = layout->characterAnchorPoint(layout->end())[Geom::Y] - layout->characterAnchorPoint(layout->begin())[Geom::Y];
+ double average_line_height = all_lines_height / (line_count == 0 ? 1 : line_count);
+ return average_line_height;
+}
+
void
sp_te_adjust_linespacing_screen (SPItem *text, Inkscape::Text::Layout::iterator const &/*start*/, Inkscape::Text::Layout::iterator const &/*end*/, SPDesktop *desktop, gdouble by)
{
@@ -1105,7 +1206,7 @@ sp_te_adjust_linespacing_screen (SPItem *text, Inkscape::Text::Layout::iterator
}
unsigned line_count = layout->lineIndex(layout->end());
- double all_lines_height = layout->characterAnchorPoint(layout->end())[NR::Y] - layout->characterAnchorPoint(layout->begin())[NR::Y];
+ double all_lines_height = layout->characterAnchorPoint(layout->end())[Geom::Y] - layout->characterAnchorPoint(layout->begin())[Geom::Y];
double average_line_height = all_lines_height / (line_count == 0 ? 1 : line_count);
if (fabs(average_line_height) < 0.001) average_line_height = 0.001;
@@ -1114,8 +1215,8 @@ sp_te_adjust_linespacing_screen (SPItem *text, Inkscape::Text::Layout::iterator
gdouble zby = by / (desktop->current_zoom() * (line_count == 0 ? 1 : line_count));
// divide increment by matrix expansion
- NR::Matrix t = sp_item_i2doc_affine (SP_ITEM(text));
- zby = zby / NR::expansion(t);
+ Geom::Matrix t (SP_ITEM(text)->i2doc_affine ());
+ zby = zby / t.descrim();
switch (style->line_height.unit) {
case SP_CSS_UNIT_NONE:
@@ -1213,16 +1314,17 @@ static bool objects_have_equal_style(SPObject const *parent, SPObject const *chi
parent_style = sp_style_write_string(parent_spstyle, SP_STYLE_FLAG_ALWAYS);
sp_style_unref(parent_spstyle);
- Glib::ustring child_style_construction(parent_style);
+ Glib::ustring child_style_construction;
while (child != parent) {
// FIXME: this assumes that child's style is only in style= whereas it can also be in css attributes!
char const *style_text = SP_OBJECT_REPR(child)->attribute("style");
if (style_text && *style_text) {
- child_style_construction += ';';
- child_style_construction += style_text;
+ child_style_construction.insert(0, style_text);
+ child_style_construction.insert(0, 1, ';');
}
child = SP_OBJECT_PARENT(child);
}
+ child_style_construction.insert(0, parent_style);
SPStyle *child_spstyle = sp_style_new(SP_OBJECT_DOCUMENT(parent));
sp_style_merge_from_style_string(child_spstyle, child_style_construction.c_str());
gchar *child_style = sp_style_write_string(child_spstyle, SP_STYLE_FLAG_ALWAYS);
{
sp_repr_css_change(SP_OBJECT_REPR(o), const_cast<SPCSSAttr*>(css), "style");
- for (SPObject *child = sp_object_first_child(SP_OBJECT(o)) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
+ for (SPObject *child = o->firstChild() ; child ; child = child->getNext() ) {
if (sp_repr_css_property(const_cast<SPCSSAttr*>(css), "opacity", NULL) != NULL) {
// Unset properties which are accumulating and thus should not be set recursively.
// For example, setting opacity 0.5 on a group recursively would result in the visible opacity of 0.25 for an item in the group.
static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const *css, SPObject *start_item, Glib::ustring::iterator start_text_iter, SPObject *end_item, Glib::ustring::iterator end_text_iter, char const *span_object_name)
{
bool passed_start = start_item == NULL ? true : false;
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(common_ancestor));
+ Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(common_ancestor)->getReprDoc();
- for (SPObject *child = common_ancestor->firstChild() ; child != NULL ; child = SP_OBJECT_NEXT(child)) {
- if (start_item == child)
+ for (SPObject *child = common_ancestor->firstChild() ; child ; child = child->getNext()) {
+ if (start_item == child) {
passed_start = true;
+ }
if (passed_start) {
if (end_item && child->isAncestorOf(end_item)) {
@@ -1305,7 +1408,7 @@ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const *
Inkscape::XML::Node *child_span = xml_doc->createElement(span_object_name);
sp_repr_css_set(child_span, const_cast<SPCSSAttr*>(css), "style"); // better hope that prototype wasn't nonconst for a good reason
- SPObject *prev_item = SP_OBJECT_PREV(child);
+ SPObject *prev_item = child->getPrev();
Inkscape::XML::Node *prev_repr = prev_item ? SP_OBJECT_REPR(prev_item) : NULL;
if (child == start_item || child == end_item) {
@@ -1348,7 +1451,7 @@ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const *
child_span->appendChild(text_in_span);
Inkscape::GC::release(text_in_span);
child->deleteObject();
- child = sp_object_get_child_by_repr(common_ancestor, child_span);
+ child = common_ancestor->get_child_by_repr(child_span);
} else
surround_entire_string = true;
@@ -1360,7 +1463,7 @@ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const *
SP_OBJECT_REPR(common_ancestor)->removeChild(child_repr);
child_span->appendChild(child_repr);
Inkscape::GC::release(child_repr);
- child = sp_object_get_child_by_repr(common_ancestor, child_span);
+ child = common_ancestor->get_child_by_repr(child_span);
}
Inkscape::GC::release(child_span);
@@ -1413,13 +1516,17 @@ static SPObject* ascend_while_first(SPObject *item, Glib::ustring::iterator text
-> abcdef */
static bool tidy_operator_empty_spans(SPObject **item)
{
- if ((*item)->hasChildren()) return false;
- if (is_line_break_object(*item)) return false;
- if (SP_IS_STRING(*item) && !SP_STRING(*item)->string.empty()) return false;
- SPObject *next = SP_OBJECT_NEXT(*item);
- (*item)->deleteObject();
- *item = next;
- return true;
+ bool result = false;
+ if ( !(*item)->hasChildren()
+ && !is_line_break_object(*item)
+ && !(SP_IS_STRING(*item) && !SP_STRING(*item)->string.empty())
+ ) {
+ SPObject *next = (*item)->getNext();
+ (*item)->deleteObject();
+ *item = next;
+ result = true;
+ }
+ return result;
}
/** inexplicable spans: abc<span style="">def</span>ghi
the repeated strings will be merged by another operator. */
static bool tidy_operator_inexplicable_spans(SPObject **item)
{
+ //XML Tree being directly used here while it shouldn't be.
+ if (*item && sp_repr_is_meta_element((*item)->getRepr())) return false;
if (SP_IS_STRING(*item)) return false;
if (is_line_break_object(*item)) return false;
TextTagAttributes *attrs = attributes_for_object(*item);
SP_OBJECT_REPR(*item)->removeChild(repr);
SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(repr, SP_OBJECT_REPR(next));
Inkscape::GC::release(repr);
- next = SP_OBJECT_NEXT(next);
+ next = next->getNext();
}
(*item)->deleteObject();
*item = next;
static bool tidy_operator_repeated_spans(SPObject **item)
{
SPObject *first = *item;
- SPObject *second = SP_OBJECT_NEXT(first);
+ SPObject *second = first->getNext();
if (second == NULL) return false;
Inkscape::XML::Node *first_repr = SP_OBJECT_REPR(first);
@@ -1524,9 +1633,12 @@ static bool redundant_double_nesting_processor(SPObject **item, SPObject *child,
if (attrs && attrs->anyAttributesSet()) return false;
if (!objects_have_equal_style(SP_OBJECT_PARENT(*item), child)) return false;
- Inkscape::XML::Node *insert_after_repr;
- if (prepend) insert_after_repr = SP_OBJECT_REPR(SP_OBJECT_PREV(*item));
- else insert_after_repr = SP_OBJECT_REPR(*item);
+ Inkscape::XML::Node *insert_after_repr = 0;
+ if (!prepend) {
+ insert_after_repr = SP_OBJECT_REPR(*item);
+ } else if ((*item)->getPrev()) {
+ insert_after_repr = SP_OBJECT_REPR((*item)->getPrev());
+ }
while (SP_OBJECT_REPR(child)->childCount()) {
Inkscape::XML::Node *move_repr = SP_OBJECT_REPR(child)->firstChild();
Inkscape::GC::anchor(move_repr);
@@ -1574,15 +1686,15 @@ static bool redundant_semi_nesting_processor(SPObject **item, SPObject *child, b
SPCSSAttr *css_child_and_item = sp_repr_css_attr_new();
SPCSSAttr *css_child_only = sp_repr_css_attr_new();
+ gchar const *item_style = SP_OBJECT_REPR(*item)->attribute("style");
+ if (item_style && *item_style) {
+ sp_repr_css_attr_add_from_string(css_child_and_item, item_style);
+ }
gchar const *child_style = SP_OBJECT_REPR(child)->attribute("style");
if (child_style && *child_style) {
sp_repr_css_attr_add_from_string(css_child_and_item, child_style);
sp_repr_css_attr_add_from_string(css_child_only, child_style);
}
- gchar const *item_style = SP_OBJECT_REPR(*item)->attribute("style");
- if (item_style && *item_style) {
- sp_repr_css_attr_add_from_string(css_child_and_item, item_style);
- }
bool equal = css_attrs_are_equal(css_child_only, css_child_and_item);
sp_repr_css_attr_unref(css_child_and_item);
sp_repr_css_attr_unref(css_child_only);
@@ -1591,7 +1703,7 @@ static bool redundant_semi_nesting_processor(SPObject **item, SPObject *child, b
Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(*item)->document();
Inkscape::XML::Node *new_span = xml_doc->createElement(SP_OBJECT_REPR(*item)->name());
if (prepend) {
- SPObject *prev = SP_OBJECT_PREV(*item);
+ SPObject *prev = (*item)->getPrev();
SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(new_span, prev ? SP_OBJECT_REPR(prev) : NULL);
} else
SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(new_span, SP_OBJECT_REPR(*item));
in a paragraph which is not \a not_obj. */
static SPString* find_last_string_child_not_equal_to(SPObject *root, SPObject *not_obj)
{
- for (SPObject *child = root->lastChild() ; child ; child = SP_OBJECT_PREV(child))
+ for (SPObject *child = root->lastChild() ; child ; child = child->getPrev())
{
if (child == not_obj) continue;
if (child->hasChildren()) {
SPObject *test_item = *item;
SPString *next_string;
for ( ; ; ) { // find the next string
- next_string = sp_te_seek_next_string_recursive(SP_OBJECT_NEXT(test_item));
+ next_string = sp_te_seek_next_string_recursive(test_item->getNext());
if (next_string) {
next_string->string.insert(0, str);
break;
for ( ; ; ) { // go up one item in the xml
test_item = SP_OBJECT_PARENT(test_item);
if (is_line_break_object(test_item)) break;
- SPObject *next = SP_OBJECT_NEXT(test_item);
+ if (SP_IS_FLOWTEXT(test_item)) return false;
+ SPObject *next = test_item->getNext();
if (next) {
test_item = next;
break;
}
SP_OBJECT_REPR(next_string)->setContent(next_string->string.c_str());
SPObject *delete_obj = *item;
- *item = SP_OBJECT_NEXT(*item);
+ *item = (*item)->getNext();
delete_obj->deleteObject();
return true;
}
for (SPObject *child = root->firstChild() ; child != NULL ; ) {
if (SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child) || SP_IS_TREF(child)) {
- child = SP_OBJECT_NEXT(child);
+ child = child->getNext();
continue;
}
- if (child->hasChildren())
+ if (child->hasChildren()) {
changes |= tidy_xml_tree_recursively(child);
+ }
unsigned i;
for (i = 0 ; i < sizeof(tidy_operators) / sizeof(tidy_operators[0]) ; i++) {
break;
}
}
- if (i == sizeof(tidy_operators) / sizeof(tidy_operators[0]))
- child = SP_OBJECT_NEXT(child);
+ if (i == sizeof(tidy_operators) / sizeof(tidy_operators[0])) {
+ child = child->getNext();
+ }
}
return changes;
}
@@ -1755,13 +1870,18 @@ void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &sta
start_item = SP_OBJECT(rawptr);
layout->getSourceOfCharacter(last, &rawptr, &end_text_iter);
end_item = SP_OBJECT(rawptr);
- if (start_item == 0)
+ if (start_item == 0) {
return; // start is at end of text
- if (is_line_break_object(start_item))
- start_item = SP_OBJECT_NEXT(start_item);
- if (is_line_break_object(end_item))
- end_item = SP_OBJECT_NEXT(end_item);
- if (end_item == 0) end_item = text;
+ }
+ if (is_line_break_object(start_item)) {
+ start_item = start_item->getNext();
+ }
+ if (is_line_break_object(end_item)) {
+ end_item = end_item->getNext();
+ }
+ if (end_item == 0) {
+ end_item = text;
+ }
/* Special case: With a tref, we only want to change its style when the whole
@@ -1782,9 +1902,24 @@ void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &sta
The recursion may involve creating new spans.
*/
SPObject *common_ancestor = get_common_ancestor(text, start_item, end_item);
+
+ // bug #168370 (consider parent transform and viewBox)
+ // snipplet copied from desktop-style.cpp sp_desktop_apply_css_recursive(...)
+ SPCSSAttr *css_set = sp_repr_css_attr_new();
+ sp_repr_css_merge(css_set, (SPCSSAttr*) css);
+ {
+ Geom::Matrix const local(SP_ITEM(common_ancestor)->i2doc_affine());
+ double const ex(local.descrim());
+ if ( ( ex != 0. )
+ && ( ex != 1. ) ) {
+ sp_css_attr_scale(css_set, 1/ex);
+ }
+ }
+
start_item = ascend_while_first(start_item, start_text_iter, common_ancestor);
end_item = ascend_while_first(end_item, end_text_iter, common_ancestor);
- recursively_apply_style(common_ancestor, css, start_item, start_text_iter, end_item, end_text_iter, span_name_for_text_object(text));
+ recursively_apply_style(common_ancestor, css_set, start_item, start_text_iter, end_item, end_text_iter, span_name_for_text_object(text));
+ sp_repr_css_attr_unref(css_set);
/* stage 2: cleanup the xml tree (of which there are multiple passes) */
/* discussion: this stage requires a certain level of inventiveness because
@@ -1798,12 +1933,48 @@ void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &sta
and neither option can be made to work, a fallback could be to reduce
everything to a single level of nesting and drop all pretence of
roundtrippability. */
- while (tidy_xml_tree_recursively(common_ancestor));
+ while (tidy_xml_tree_recursively(common_ancestor)){};
// if we only modified subobjects this won't have been automatically sent
text->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
}
+bool is_part_of_text_subtree (SPObject *obj)
+{
+ return (SP_IS_TSPAN(obj)
+ || SP_IS_TEXT(obj)
+ || SP_IS_FLOWTEXT(obj)
+ || SP_IS_FLOWTSPAN(obj)
+ || SP_IS_FLOWDIV(obj)
+ || SP_IS_FLOWPARA(obj)
+ || SP_IS_FLOWLINE(obj)
+ || SP_IS_FLOWREGIONBREAK(obj));
+}
+
+bool is_top_level_text_object (SPObject *obj)
+{
+ return (SP_IS_TEXT(obj)
+ || SP_IS_FLOWTEXT(obj));
+}
+
+bool has_visible_text(SPObject *obj)
+{
+ bool hasVisible = false;
+
+ if (SP_IS_STRING(obj) && !SP_STRING(obj)->string.empty()) {
+ hasVisible = true; // maybe we should also check that it's not all whitespace?
+ } else {
+ for (SPObject const *child = obj->firstChild() ; child ; child = child->getNext()) {
+ if (has_visible_text((SPObject *) child)) {
+ hasVisible = true;
+ break;
+ }
+ }
+ }
+
+ return hasVisible;
+}
+
/*
Local Variables:
mode:c++
@@ -1813,4 +1984,4 @@ void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &sta
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :